diff --git a/documentation.yml b/documentation.yml new file mode 100644 index 0000000..26bd806 --- /dev/null +++ b/documentation.yml @@ -0,0 +1,6 @@ +toc: + - ePub + - name: ePubJS + description: | + main entry + - EpubCFI diff --git a/documentation/html/assets/anchor.js b/documentation/html/assets/anchor.js new file mode 100644 index 0000000..47d871a --- /dev/null +++ b/documentation/html/assets/anchor.js @@ -0,0 +1,197 @@ +/*! + * AnchorJS - v1.2.1 - 2015-07-02 + * https://github.com/bryanbraun/anchorjs + * Copyright (c) 2015 Bryan Braun; Licensed MIT + */ + +function AnchorJS(options) { + 'use strict'; + + this.options = options || {}; + + this._applyRemainingDefaultOptions = function(opts) { + this.options.icon = this.options.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'. + this.options.visible = this.options.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' + this.options.placement = this.options.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left' + this.options.class = this.options.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name. + }; + + this._applyRemainingDefaultOptions(options); + + this.add = function(selector) { + var elements, + elsWithIds, + idList, + elementID, + i, + roughText, + tidyText, + index, + count, + newTidyText, + readableID, + anchor; + + this._applyRemainingDefaultOptions(this.options); + + // Provide a sensible default selector, if none is given. + if (!selector) { + selector = 'h1, h2, h3, h4, h5, h6'; + } else if (typeof selector !== 'string') { + throw new Error('The selector provided to AnchorJS was invalid.'); + } + + elements = document.querySelectorAll(selector); + if (elements.length === 0) { + return false; + } + + this._addBaselineStyles(); + + // We produce a list of existing IDs so we don't generate a duplicate. + elsWithIds = document.querySelectorAll('[id]'); + idList = [].map.call(elsWithIds, function assign(el) { + return el.id; + }); + + for (i = 0; i < elements.length; i++) { + + if (elements[i].hasAttribute('id')) { + elementID = elements[i].getAttribute('id'); + } else { + roughText = elements[i].textContent; + + // Refine it so it makes a good ID. Strip out non-safe characters, replace + // spaces with hyphens, truncate to 32 characters, and make toLowerCase. + // + // Example string: // '⚡⚡⚡ Unicode icons are cool--but they definitely don't belong in a URL fragment.' + tidyText = roughText.replace(/[^\w\s-]/gi, '') // ' Unicode icons are cool--but they definitely dont belong in a URL fragment' + .replace(/\s+/g, '-') // '-Unicode-icons-are-cool--but-they-definitely-dont-belong-in-a-URL-fragment' + .replace(/-{2,}/g, '-') // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL-fragment' + .substring(0, 64) // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL' + .replace(/^-+|-+$/gm, '') // 'Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL' + .toLowerCase(); // 'unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-url' + + // Compare our generated ID to existing IDs (and increment it if needed) + // before we add it to the page. + newTidyText = tidyText; + count = 0; + do { + if (index !== undefined) { + newTidyText = tidyText + '-' + count; + } + // .indexOf is supported in IE9+. + index = idList.indexOf(newTidyText); + count += 1; + } while (index !== -1); + index = undefined; + idList.push(newTidyText); + + // Assign it to our element. + // Currently the setAttribute element is only supported in IE9 and above. + elements[i].setAttribute('id', newTidyText); + + elementID = newTidyText; + } + + readableID = elementID.replace(/-/g, ' '); + + // The following code builds the following DOM structure in a more effiecient (albeit opaque) way. + // ''; + anchor = document.createElement('a'); + anchor.className = 'anchorjs-link ' + this.options.class; + anchor.href = '#' + elementID; + anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID); + anchor.setAttribute('data-anchorjs-icon', this.options.icon); + + if (this.options.visible === 'always') { + anchor.style.opacity = '1'; + } + + if (this.options.icon === '\ue9cb') { + anchor.style.fontFamily = 'anchorjs-icons'; + anchor.style.fontStyle = 'normal'; + anchor.style.fontVariant = 'normal'; + anchor.style.fontWeight = 'normal'; + anchor.style.lineHeight = 1; + } + + if (this.options.placement === 'left') { + anchor.style.position = 'absolute'; + anchor.style.marginLeft = '-1em'; + anchor.style.paddingRight = '0.5em'; + elements[i].insertBefore(anchor, elements[i].firstChild); + } else { // if the option provided is `right` (or anything else). + anchor.style.paddingLeft = '0.375em'; + elements[i].appendChild(anchor); + } + } + + return this; + }; + + this.remove = function(selector) { + var domAnchor, + elements = document.querySelectorAll(selector); + for (var i = 0; i < elements.length; i++) { + domAnchor = elements[i].querySelector('.anchorjs-link'); + if (domAnchor) { + elements[i].removeChild(domAnchor); + } + } + return this; + }; + + this._addBaselineStyles = function() { + // We don't want to add global baseline styles if they've been added before. + if (document.head.querySelector('style.anchorjs') !== null) { + return; + } + + var style = document.createElement('style'), + linkRule = + ' .anchorjs-link {' + + ' opacity: 0;' + + ' text-decoration: none;' + + ' -webkit-font-smoothing: antialiased;' + + ' -moz-osx-font-smoothing: grayscale;' + + ' }', + hoverRule = + ' *:hover > .anchorjs-link,' + + ' .anchorjs-link:focus {' + + ' opacity: 1;' + + ' }', + anchorjsLinkFontFace = + ' @font-face {' + + ' font-family: "anchorjs-icons";' + + ' font-style: normal;' + + ' font-weight: normal;' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above + ' src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBTUAAAC8AAAAYGNtYXAWi9QdAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zgq29TcAAAF4AAABNGhlYWQEZM3pAAACrAAAADZoaGVhBhUDxgAAAuQAAAAkaG10eASAADEAAAMIAAAAFGxvY2EAKACuAAADHAAAAAxtYXhwAAgAVwAAAygAAAAgbmFtZQ5yJ3cAAANIAAAB2nBvc3QAAwAAAAAFJAAAACAAAwJAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpywPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6cv//f//AAAAAAAg6cv//f//AAH/4xY5AAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACADEARAJTAsAAKwBUAAABIiYnJjQ/AT4BMzIWFxYUDwEGIicmND8BNjQnLgEjIgYPAQYUFxYUBw4BIwciJicmND8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFA8BDgEjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAEAAAABAACiToc1Xw889QALBAAAAAAA0XnFFgAAAADRecUWAAAAAAJTAsAAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAAlMAAQAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAACAAAAAoAAMQAAAAAACgAUAB4AmgABAAAABQBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEADgAAAAEAAAAAAAIABwCfAAEAAAAAAAMADgBLAAEAAAAAAAQADgC0AAEAAAAAAAUACwAqAAEAAAAAAAYADgB1AAEAAAAAAAoAGgDeAAMAAQQJAAEAHAAOAAMAAQQJAAIADgCmAAMAAQQJAAMAHABZAAMAAQQJAAQAHADCAAMAAQQJAAUAFgA1AAMAAQQJAAYAHACDAAMAAQQJAAoANAD4YW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQByYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format("truetype");' + + ' }', + pseudoElContent = + ' [data-anchorjs-icon]::after {' + + ' content: attr(data-anchorjs-icon);' + + ' }', + firstStyleEl; + + style.className = 'anchorjs'; + style.appendChild(document.createTextNode('')); // Necessary for Webkit. + + // We place it in the head with the other style tags, if possible, so as to + // not look out of place. We insert before the others so these styles can be + // overridden if necessary. + firstStyleEl = document.head.querySelector('[rel="stylesheet"], style'); + if (firstStyleEl === undefined) { + document.head.appendChild(style); + } else { + document.head.insertBefore(style, firstStyleEl); + } + + style.sheet.insertRule(linkRule, style.sheet.cssRules.length); + style.sheet.insertRule(hoverRule, style.sheet.cssRules.length); + style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length); + style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length); + }; +} + +var anchors = new AnchorJS(); diff --git a/documentation/html/assets/bass-addons.css b/documentation/html/assets/bass-addons.css new file mode 100644 index 0000000..c27e96d --- /dev/null +++ b/documentation/html/assets/bass-addons.css @@ -0,0 +1,12 @@ +.input { + font-family: inherit; + display: block; + width: 100%; + height: 2rem; + padding: .5rem; + margin-bottom: 1rem; + border: 1px solid #ccc; + font-size: .875rem; + border-radius: 3px; + box-sizing: border-box; +} diff --git a/documentation/html/assets/bass.css b/documentation/html/assets/bass.css new file mode 100644 index 0000000..15e0dc9 --- /dev/null +++ b/documentation/html/assets/bass.css @@ -0,0 +1,543 @@ +/*! Basscss | http://basscss.com | MIT License */ + +.h1{ font-size: 2rem } +.h2{ font-size: 1.5rem } +.h3{ font-size: 1.25rem } +.h4{ font-size: 1rem } +.h5{ font-size: .875rem } +.h6{ font-size: .75rem } + +.font-family-inherit{ font-family:inherit } +.font-size-inherit{ font-size:inherit } +.text-decoration-none{ text-decoration:none } + +.bold{ font-weight: bold; font-weight: bold } +.regular{ font-weight:normal } +.italic{ font-style:italic } +.caps{ text-transform:uppercase; letter-spacing: .2em; } + +.left-align{ text-align:left } +.center{ text-align:center } +.right-align{ text-align:right } +.justify{ text-align:justify } + +.nowrap{ white-space:nowrap } +.break-word{ word-wrap:break-word } + +.line-height-1{ line-height: 1 } +.line-height-2{ line-height: 1.125 } +.line-height-3{ line-height: 1.25 } +.line-height-4{ line-height: 1.5 } + +.list-style-none{ list-style:none } +.underline{ text-decoration:underline } + +.truncate{ + max-width:100%; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; +} + +.list-reset{ + list-style:none; + padding-left:0; +} + +.inline{ display:inline } +.block{ display:block } +.inline-block{ display:inline-block } +.table{ display:table } +.table-cell{ display:table-cell } + +.overflow-hidden{ overflow:hidden } +.overflow-scroll{ overflow:scroll } +.overflow-auto{ overflow:auto } + +.clearfix:before, +.clearfix:after{ + content:" "; + display:table +} +.clearfix:after{ clear:both } + +.left{ float:left } +.right{ float:right } + +.fit{ max-width:100% } + +.max-width-1{ max-width: 24rem } +.max-width-2{ max-width: 32rem } +.max-width-3{ max-width: 48rem } +.max-width-4{ max-width: 64rem } + +.border-box{ box-sizing:border-box } + +.align-baseline{ vertical-align:baseline } +.align-top{ vertical-align:top } +.align-middle{ vertical-align:middle } +.align-bottom{ vertical-align:bottom } + +.m0{ margin:0 } +.mt0{ margin-top:0 } +.mr0{ margin-right:0 } +.mb0{ margin-bottom:0 } +.ml0{ margin-left:0 } +.mx0{ margin-left:0; margin-right:0 } +.my0{ margin-top:0; margin-bottom:0 } + +.m1{ margin: .5rem } +.mt1{ margin-top: .5rem } +.mr1{ margin-right: .5rem } +.mb1{ margin-bottom: .5rem } +.ml1{ margin-left: .5rem } +.mx1{ margin-left: .5rem; margin-right: .5rem } +.my1{ margin-top: .5rem; margin-bottom: .5rem } + +.m2{ margin: 1rem } +.mt2{ margin-top: 1rem } +.mr2{ margin-right: 1rem } +.mb2{ margin-bottom: 1rem } +.ml2{ margin-left: 1rem } +.mx2{ margin-left: 1rem; margin-right: 1rem } +.my2{ margin-top: 1rem; margin-bottom: 1rem } + +.m3{ margin: 2rem } +.mt3{ margin-top: 2rem } +.mr3{ margin-right: 2rem } +.mb3{ margin-bottom: 2rem } +.ml3{ margin-left: 2rem } +.mx3{ margin-left: 2rem; margin-right: 2rem } +.my3{ margin-top: 2rem; margin-bottom: 2rem } + +.m4{ margin: 4rem } +.mt4{ margin-top: 4rem } +.mr4{ margin-right: 4rem } +.mb4{ margin-bottom: 4rem } +.ml4{ margin-left: 4rem } +.mx4{ margin-left: 4rem; margin-right: 4rem } +.my4{ margin-top: 4rem; margin-bottom: 4rem } + +.mxn1{ margin-left: -.5rem; margin-right: -.5rem; } +.mxn2{ margin-left: -1rem; margin-right: -1rem; } +.mxn3{ margin-left: -2rem; margin-right: -2rem; } +.mxn4{ margin-left: -4rem; margin-right: -4rem; } + +.ml-auto{ margin-left:auto } +.mr-auto{ margin-right:auto } +.mx-auto{ margin-left:auto; margin-right:auto; } + +.p0{ padding:0 } +.pt0{ padding-top:0 } +.pr0{ padding-right:0 } +.pb0{ padding-bottom:0 } +.pl0{ padding-left:0 } +.px0{ padding-left:0; padding-right:0 } +.py0{ padding-top:0; padding-bottom:0 } + +.p1{ padding: .5rem } +.pt1{ padding-top: .5rem } +.pr1{ padding-right: .5rem } +.pb1{ padding-bottom: .5rem } +.pl1{ padding-left: .5rem } +.py1{ padding-top: .5rem; padding-bottom: .5rem } +.px1{ padding-left: .5rem; padding-right: .5rem } + +.p2{ padding: 1rem } +.pt2{ padding-top: 1rem } +.pr2{ padding-right: 1rem } +.pb2{ padding-bottom: 1rem } +.pl2{ padding-left: 1rem } +.py2{ padding-top: 1rem; padding-bottom: 1rem } +.px2{ padding-left: 1rem; padding-right: 1rem } + +.p3{ padding: 2rem } +.pt3{ padding-top: 2rem } +.pr3{ padding-right: 2rem } +.pb3{ padding-bottom: 2rem } +.pl3{ padding-left: 2rem } +.py3{ padding-top: 2rem; padding-bottom: 2rem } +.px3{ padding-left: 2rem; padding-right: 2rem } + +.p4{ padding: 4rem } +.pt4{ padding-top: 4rem } +.pr4{ padding-right: 4rem } +.pb4{ padding-bottom: 4rem } +.pl4{ padding-left: 4rem } +.py4{ padding-top: 4rem; padding-bottom: 4rem } +.px4{ padding-left: 4rem; padding-right: 4rem } + +.col{ + float:left; + box-sizing:border-box; +} + +.col-right{ + float:right; + box-sizing:border-box; +} + +.col-1{ + width:8.33333%; +} + +.col-2{ + width:16.66667%; +} + +.col-3{ + width:25%; +} + +.col-4{ + width:33.33333%; +} + +.col-5{ + width:41.66667%; +} + +.col-6{ + width:50%; +} + +.col-7{ + width:58.33333%; +} + +.col-8{ + width:66.66667%; +} + +.col-9{ + width:75%; +} + +.col-10{ + width:83.33333%; +} + +.col-11{ + width:91.66667%; +} + +.col-12{ + width:100%; +} +@media (min-width: 40em){ + + .sm-col{ + float:left; + box-sizing:border-box; + } + + .sm-col-right{ + float:right; + box-sizing:border-box; + } + + .sm-col-1{ + width:8.33333%; + } + + .sm-col-2{ + width:16.66667%; + } + + .sm-col-3{ + width:25%; + } + + .sm-col-4{ + width:33.33333%; + } + + .sm-col-5{ + width:41.66667%; + } + + .sm-col-6{ + width:50%; + } + + .sm-col-7{ + width:58.33333%; + } + + .sm-col-8{ + width:66.66667%; + } + + .sm-col-9{ + width:75%; + } + + .sm-col-10{ + width:83.33333%; + } + + .sm-col-11{ + width:91.66667%; + } + + .sm-col-12{ + width:100%; + } + +} +@media (min-width: 52em){ + + .md-col{ + float:left; + box-sizing:border-box; + } + + .md-col-right{ + float:right; + box-sizing:border-box; + } + + .md-col-1{ + width:8.33333%; + } + + .md-col-2{ + width:16.66667%; + } + + .md-col-3{ + width:25%; + } + + .md-col-4{ + width:33.33333%; + } + + .md-col-5{ + width:41.66667%; + } + + .md-col-6{ + width:50%; + } + + .md-col-7{ + width:58.33333%; + } + + .md-col-8{ + width:66.66667%; + } + + .md-col-9{ + width:75%; + } + + .md-col-10{ + width:83.33333%; + } + + .md-col-11{ + width:91.66667%; + } + + .md-col-12{ + width:100%; + } + +} +@media (min-width: 64em){ + + .lg-col{ + float:left; + box-sizing:border-box; + } + + .lg-col-right{ + float:right; + box-sizing:border-box; + } + + .lg-col-1{ + width:8.33333%; + } + + .lg-col-2{ + width:16.66667%; + } + + .lg-col-3{ + width:25%; + } + + .lg-col-4{ + width:33.33333%; + } + + .lg-col-5{ + width:41.66667%; + } + + .lg-col-6{ + width:50%; + } + + .lg-col-7{ + width:58.33333%; + } + + .lg-col-8{ + width:66.66667%; + } + + .lg-col-9{ + width:75%; + } + + .lg-col-10{ + width:83.33333%; + } + + .lg-col-11{ + width:91.66667%; + } + + .lg-col-12{ + width:100%; + } + +} +.flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } + +@media (min-width: 40em){ + .sm-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } +} + +@media (min-width: 52em){ + .md-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } +} + +@media (min-width: 64em){ + .lg-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex } +} + +.flex-column{ -webkit-box-orient:vertical; -webkit-box-direction:normal; -webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column } +.flex-wrap{ -webkit-flex-wrap:wrap; -ms-flex-wrap:wrap; flex-wrap:wrap } + +.items-start{ -webkit-box-align:start; -webkit-align-items:flex-start; -ms-flex-align:start; -ms-grid-row-align:flex-start; align-items:flex-start } +.items-end{ -webkit-box-align:end; -webkit-align-items:flex-end; -ms-flex-align:end; -ms-grid-row-align:flex-end; align-items:flex-end } +.items-center{ -webkit-box-align:center; -webkit-align-items:center; -ms-flex-align:center; -ms-grid-row-align:center; align-items:center } +.items-baseline{ -webkit-box-align:baseline; -webkit-align-items:baseline; -ms-flex-align:baseline; -ms-grid-row-align:baseline; align-items:baseline } +.items-stretch{ -webkit-box-align:stretch; -webkit-align-items:stretch; -ms-flex-align:stretch; -ms-grid-row-align:stretch; align-items:stretch } + +.self-start{ -webkit-align-self:flex-start; -ms-flex-item-align:start; align-self:flex-start } +.self-end{ -webkit-align-self:flex-end; -ms-flex-item-align:end; align-self:flex-end } +.self-center{ -webkit-align-self:center; -ms-flex-item-align:center; align-self:center } +.self-baseline{ -webkit-align-self:baseline; -ms-flex-item-align:baseline; align-self:baseline } +.self-stretch{ -webkit-align-self:stretch; -ms-flex-item-align:stretch; align-self:stretch } + +.justify-start{ -webkit-box-pack:start; -webkit-justify-content:flex-start; -ms-flex-pack:start; justify-content:flex-start } +.justify-end{ -webkit-box-pack:end; -webkit-justify-content:flex-end; -ms-flex-pack:end; justify-content:flex-end } +.justify-center{ -webkit-box-pack:center; -webkit-justify-content:center; -ms-flex-pack:center; justify-content:center } +.justify-between{ -webkit-box-pack:justify; -webkit-justify-content:space-between; -ms-flex-pack:justify; justify-content:space-between } +.justify-around{ -webkit-justify-content:space-around; -ms-flex-pack:distribute; justify-content:space-around } + +.content-start{ -webkit-align-content:flex-start; -ms-flex-line-pack:start; align-content:flex-start } +.content-end{ -webkit-align-content:flex-end; -ms-flex-line-pack:end; align-content:flex-end } +.content-center{ -webkit-align-content:center; -ms-flex-line-pack:center; align-content:center } +.content-between{ -webkit-align-content:space-between; -ms-flex-line-pack:justify; align-content:space-between } +.content-around{ -webkit-align-content:space-around; -ms-flex-line-pack:distribute; align-content:space-around } +.content-stretch{ -webkit-align-content:stretch; -ms-flex-line-pack:stretch; align-content:stretch } +.flex-auto{ + -webkit-box-flex:1; + -webkit-flex:1 1 auto; + -ms-flex:1 1 auto; + flex:1 1 auto; + min-width:0; + min-height:0; +} +.flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none } + +.order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 } +.order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 } +.order-2{ -webkit-box-ordinal-group:3; -webkit-order:2; -ms-flex-order:2; order:2 } +.order-3{ -webkit-box-ordinal-group:4; -webkit-order:3; -ms-flex-order:3; order:3 } +.order-last{ -webkit-box-ordinal-group:100000; -webkit-order:99999; -ms-flex-order:99999; order:99999 } + +.relative{ position:relative } +.absolute{ position:absolute } +.fixed{ position:fixed } + +.top-0{ top:0 } +.right-0{ right:0 } +.bottom-0{ bottom:0 } +.left-0{ left:0 } + +.z1{ z-index: 1 } +.z2{ z-index: 2 } +.z3{ z-index: 3 } +.z4{ z-index: 4 } + +.border{ + border-style:solid; + border-width: 1px; +} + +.border-top{ + border-top-style:solid; + border-top-width: 1px; +} + +.border-right{ + border-right-style:solid; + border-right-width: 1px; +} + +.border-bottom{ + border-bottom-style:solid; + border-bottom-width: 1px; +} + +.border-left{ + border-left-style:solid; + border-left-width: 1px; +} + +.border-none{ border:0 } + +.rounded{ border-radius: 3px } +.circle{ border-radius:50% } + +.rounded-top{ border-radius: 3px 3px 0 0 } +.rounded-right{ border-radius: 0 3px 3px 0 } +.rounded-bottom{ border-radius: 0 0 3px 3px } +.rounded-left{ border-radius: 3px 0 0 3px } + +.not-rounded{ border-radius:0 } + +.hide{ + position:absolute !important; + height:1px; + width:1px; + overflow:hidden; + clip:rect(1px, 1px, 1px, 1px); +} + +@media (max-width: 40em){ + .xs-hide{ display:none !important } +} + +@media (min-width: 40em) and (max-width: 52em){ + .sm-hide{ display:none !important } +} + +@media (min-width: 52em) and (max-width: 64em){ + .md-hide{ display:none !important } +} + +@media (min-width: 64em){ + .lg-hide{ display:none !important } +} + +.display-none{ display:none !important } + diff --git a/documentation/html/assets/fonts/EOT/SourceCodePro-Bold.eot b/documentation/html/assets/fonts/EOT/SourceCodePro-Bold.eot new file mode 100755 index 0000000..d24cc39 Binary files /dev/null and b/documentation/html/assets/fonts/EOT/SourceCodePro-Bold.eot differ diff --git a/documentation/html/assets/fonts/EOT/SourceCodePro-Regular.eot b/documentation/html/assets/fonts/EOT/SourceCodePro-Regular.eot new file mode 100755 index 0000000..09e9473 Binary files /dev/null and b/documentation/html/assets/fonts/EOT/SourceCodePro-Regular.eot differ diff --git a/documentation/html/assets/fonts/LICENSE.txt b/documentation/html/assets/fonts/LICENSE.txt new file mode 100755 index 0000000..d154618 --- /dev/null +++ b/documentation/html/assets/fonts/LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/documentation/html/assets/fonts/OTF/SourceCodePro-Bold.otf b/documentation/html/assets/fonts/OTF/SourceCodePro-Bold.otf new file mode 100755 index 0000000..f4e576c Binary files /dev/null and b/documentation/html/assets/fonts/OTF/SourceCodePro-Bold.otf differ diff --git a/documentation/html/assets/fonts/OTF/SourceCodePro-Regular.otf b/documentation/html/assets/fonts/OTF/SourceCodePro-Regular.otf new file mode 100755 index 0000000..4e3b9d0 Binary files /dev/null and b/documentation/html/assets/fonts/OTF/SourceCodePro-Regular.otf differ diff --git a/documentation/html/assets/fonts/TTF/SourceCodePro-Bold.ttf b/documentation/html/assets/fonts/TTF/SourceCodePro-Bold.ttf new file mode 100755 index 0000000..e0c576f Binary files /dev/null and b/documentation/html/assets/fonts/TTF/SourceCodePro-Bold.ttf differ diff --git a/documentation/html/assets/fonts/TTF/SourceCodePro-Regular.ttf b/documentation/html/assets/fonts/TTF/SourceCodePro-Regular.ttf new file mode 100755 index 0000000..437f472 Binary files /dev/null and b/documentation/html/assets/fonts/TTF/SourceCodePro-Regular.ttf differ diff --git a/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff b/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff new file mode 100755 index 0000000..cf96099 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff differ diff --git a/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff b/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff new file mode 100755 index 0000000..395436e Binary files /dev/null and b/documentation/html/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff differ diff --git a/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff b/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff new file mode 100755 index 0000000..c65ba84 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff differ diff --git a/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff b/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff new file mode 100755 index 0000000..0af792a Binary files /dev/null and b/documentation/html/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff differ diff --git a/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 b/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 new file mode 100755 index 0000000..cbe3835 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 differ diff --git a/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 b/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 new file mode 100755 index 0000000..65cd591 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 differ diff --git a/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 b/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 new file mode 100755 index 0000000..b78d523 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 differ diff --git a/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 b/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 new file mode 100755 index 0000000..18d2199 Binary files /dev/null and b/documentation/html/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 differ diff --git a/documentation/html/assets/fonts/source-code-pro.css b/documentation/html/assets/fonts/source-code-pro.css new file mode 100755 index 0000000..3abb4f0 --- /dev/null +++ b/documentation/html/assets/fonts/source-code-pro.css @@ -0,0 +1,23 @@ +@font-face{ + font-family: 'Source Code Pro'; + font-weight: 400; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceCodePro-Regular.eot') format('embedded-opentype'), + url('WOFF2/TTF/SourceCodePro-Regular.ttf.woff2') format('woff2'), + url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff'), + url('OTF/SourceCodePro-Regular.otf') format('opentype'), + url('TTF/SourceCodePro-Regular.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Code Pro'; + font-weight: 700; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceCodePro-Bold.eot') format('embedded-opentype'), + url('WOFF2/TTF/SourceCodePro-Bold.ttf.woff2') format('woff2'), + url('WOFF/OTF/SourceCodePro-Bold.otf.woff') format('woff'), + url('OTF/SourceCodePro-Bold.otf') format('opentype'), + url('TTF/SourceCodePro-Bold.ttf') format('truetype'); +} diff --git a/documentation/html/assets/github.css b/documentation/html/assets/github.css new file mode 100644 index 0000000..8852abb --- /dev/null +++ b/documentation/html/assets/github.css @@ -0,0 +1,123 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f8f8f8; + -webkit-text-size-adjust: none; +} + +.hljs-comment, +.diff .hljs-header, +.hljs-javadoc { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.css .rule .hljs-keyword, +.hljs-winutils, +.nginx .hljs-title, +.hljs-subst, +.hljs-request, +.hljs-status { + color: #1184CE; +} + +.hljs-number, +.hljs-hexcolor, +.ruby .hljs-constant { + color: #ed225d; +} + +.hljs-string, +.hljs-tag .hljs-value, +.hljs-phpdoc, +.hljs-dartdoc, +.tex .hljs-formula { + color: #ed225d; +} + +.hljs-title, +.hljs-id, +.scss .hljs-preprocessor { + color: #900; + font-weight: bold; +} + +.hljs-list .hljs-keyword, +.hljs-subst { + font-weight: normal; +} + +.hljs-class .hljs-title, +.hljs-type, +.vhdl .hljs-literal, +.tex .hljs-command { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-tag .hljs-title, +.hljs-rules .hljs-property, +.django .hljs-tag .hljs-keyword { + color: #000080; + font-weight: normal; +} + +.hljs-attribute, +.hljs-variable, +.lisp .hljs-body { + color: #008080; +} + +.hljs-regexp { + color: #009926; +} + +.hljs-symbol, +.ruby .hljs-symbol .hljs-string, +.lisp .hljs-keyword, +.clojure .hljs-keyword, +.scheme .hljs-keyword, +.tex .hljs-special, +.hljs-prompt { + color: #990073; +} + +.hljs-built_in { + color: #0086b3; +} + +.hljs-preprocessor, +.hljs-pragma, +.hljs-pi, +.hljs-doctype, +.hljs-shebang, +.hljs-cdata { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.diff .hljs-change { + background: #0086b3; +} + +.hljs-chunk { + color: #aaa; +} diff --git a/documentation/html/assets/site.js b/documentation/html/assets/site.js new file mode 100644 index 0000000..559c65e --- /dev/null +++ b/documentation/html/assets/site.js @@ -0,0 +1,108 @@ +/* global anchors */ + +// add anchor links to headers +anchors.options.placement = 'left'; +anchors.add('h3'); + +// Filter UI +var tocElements = document.getElementById('toc') + .getElementsByTagName('li'); + +document.getElementById('filter-input') + .addEventListener('keyup', function (e) { + + var i, element, children; + + // enter key + if (e.keyCode === 13) { + // go to the first displayed item in the toc + for (i = 0; i < tocElements.length; i++) { + element = tocElements[i]; + if (!element.classList.contains('display-none')) { + location.replace(element.firstChild.href); + return e.preventDefault(); + } + } + } + + var match = function () { + return true; + }; + + var value = this.value.toLowerCase(); + + if (!value.match(/^\s*$/)) { + match = function (element) { + return element.firstChild.innerHTML.toLowerCase().indexOf(value) !== -1; + }; + } + + for (i = 0; i < tocElements.length; i++) { + element = tocElements[i]; + children = Array.from(element.getElementsByTagName('li')); + if (match(element) || children.some(match)) { + element.classList.remove('display-none'); + } else { + element.classList.add('display-none'); + } + } + }); + +var toggles = document.getElementsByClassName('toggle-step-sibling'); +for (var i = 0; i < toggles.length; i++) { + toggles[i].addEventListener('click', toggleStepSibling); +} + +function toggleStepSibling() { + var stepSibling = this.parentNode.parentNode.parentNode.getElementsByClassName('toggle-target')[0]; + var klass = 'display-none'; + if (stepSibling.classList.contains(klass)) { + stepSibling.classList.remove(klass); + stepSibling.innerHTML = '▾'; + } else { + stepSibling.classList.add(klass); + stepSibling.innerHTML = '▸'; + } +} + +var items = document.getElementsByClassName('toggle-sibling'); +for (var j = 0; j < items.length; j++) { + items[j].addEventListener('click', toggleSibling); +} + +function toggleSibling() { + var stepSibling = this.parentNode.getElementsByClassName('toggle-target')[0]; + var icon = this.getElementsByClassName('icon')[0]; + var klass = 'display-none'; + if (stepSibling.classList.contains(klass)) { + stepSibling.classList.remove(klass); + icon.innerHTML = '▾'; + } else { + stepSibling.classList.add(klass); + icon.innerHTML = '▸'; + } +} + +function showHashTarget(targetId) { + var hashTarget = document.getElementById(targetId); + // new target is hidden + if (hashTarget && hashTarget.offsetHeight === 0 && + hashTarget.parentNode.parentNode.classList.contains('display-none')) { + hashTarget.parentNode.parentNode.classList.remove('display-none'); + } +} + +window.addEventListener('hashchange', function() { + showHashTarget(location.hash.substring(1)); +}); + +showHashTarget(location.hash.substring(1)); + +var toclinks = document.getElementsByClassName('pre-open'); +for (var k = 0; k < toclinks.length; k++) { + toclinks[k].addEventListener('mousedown', preOpen, false); +} + +function preOpen() { + showHashTarget(this.hash.substring(1)); +} diff --git a/documentation/html/assets/style.css b/documentation/html/assets/style.css new file mode 100644 index 0000000..d7e56e0 --- /dev/null +++ b/documentation/html/assets/style.css @@ -0,0 +1,136 @@ +.documentation { + font-family: Helvetica, sans-serif; + color: #666; + line-height: 1.5; + background: #f5f5f5; +} + +.black { + color: #666; +} + +.bg-white { + background-color: #fff; +} + +h4 { + margin: 20px 0 10px 0; +} + +.documentation h3 { + color: #000; +} + +.border-bottom { + border-color: #ddd; +} + +a { + color: #1184CE; + text-decoration: none; +} + +.documentation a[href]:hover { + text-decoration: underline; +} + +a:hover { + cursor: pointer; +} + +.py1-ul li { + padding: 5px 0; +} + +.max-height-100 { + max-height: 100%; +} + +section:target h3 { + font-weight:700; +} + +.documentation td, +.documentation th { + padding: .25rem .25rem; +} + +h1:hover .anchorjs-link, +h2:hover .anchorjs-link, +h3:hover .anchorjs-link, +h4:hover .anchorjs-link { + opacity: 1; +} + +.fix-3 { + width: 25%; + max-width: 244px; +} + +.fix-3 { + width: 25%; + max-width: 244px; +} + +@media (min-width: 52em) { + .fix-margin-3 { + margin-left: 25%; + } +} + +.pre, pre, code, .code { + font-family: Source Code Pro,Menlo,Consolas,Liberation Mono,monospace; + font-size: 14px; +} + +.fill-light { + background: #F9F9F9; +} + +.width2 { + width: 1rem; +} + +.input { + font-family: inherit; + display: block; + width: 100%; + height: 2rem; + padding: .5rem; + margin-bottom: 1rem; + border: 1px solid #ccc; + font-size: .875rem; + border-radius: 3px; + box-sizing: border-box; +} + +table { + border-collapse: collapse; +} + +.prose table th, +.prose table td { + text-align: left; + padding:8px; + border:1px solid #ddd; +} + +.prose table th:nth-child(1) { border-right: none; } +.prose table th:nth-child(2) { border-left: none; } + +.prose table { + border:1px solid #ddd; +} + +.prose-big { + font-size: 18px; + line-height: 30px; +} + +.quiet { + opacity: 0.7; +} + +.minishadow { + box-shadow: 2px 2px 10px #f3f3f3; +} diff --git a/documentation/html/index.html b/documentation/html/index.html new file mode 100644 index 0000000..9f1f4d7 --- /dev/null +++ b/documentation/html/index.html @@ -0,0 +1,5468 @@ + + + + + | Documentation + + + + + + +
+
+
+
+

+
+ +
+ +
+ +
+
+
+ + +
+ + +
+

+ ePub +

+ +
+ + +

Creates a new Book

+ + +
ePub(url: (string | ArrayBuffer), options: object): Book
+ + + + + + + + + + +
Parameters
+
+ +
+
+ url ((string | ArrayBuffer)) URL, Path or ArrayBuffer + +
+ +
+ +
+
+ options (object) to pass to the book + +
+ +
+ +
+ + + + + + +
Returns
+ Book: + a new Book object + + + + + + + + +
Example
+ + +
ePub("/path/to/book.epub", {})
+ + + + +
Static Members
+
+ +
+
+
+ + register +
+
+ +
+ +
+ + + + + + +
+ + + + +
+ + +
+

+ Book +

+ +
+ + +

Creates a new Book

+ + +
new Book(url: string, options: object): Book
+ + + + + + + + + + +
Parameters
+
+ +
+
+ url (string) +
+ +
+ +
+
+ options (object) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
options.requestMethod method + a request function to use instead of the default +
options.requestCredentials [boolean] + + (default undefined) + send the xhr request withCredentials +
options.requestHeaders [object] + + (default undefined) + send the xhr request headers +
options.encoding [string] + + (default binary) + optional to pass 'binary' or base64' for archived Epubs +
options.replacements [string] + + (default base64) + use base64, blobs, or none for replacing assets in archived Epubs +
+ +
+ +
+ + + + + + +
Returns
+ Book: + + + + + + + + + +
Example
+ + +
new Book("/path/to/book.epub", {})
+ + + + + + +
Instance Members
+
+ +
+
+
+ + opened +
+
+ +
+ +
+
+
+ + spine +
+
+ +
+ +
+
+
+ + locations +
+
+ +
+ +
+
+
+ + navigation +
+
+ +
+ +
+
+
+ + pageList +
+
+ +
+ +
+
+
+ + open(input, [what]) +
+
+ +
+ +
+
+
+ + load(path) +
+
+ +
+ +
+
+
+ + resolve(path, absolute) +
+
+ +
+ +
+
+
+ + section(target) +
+
+ +
+ +
+
+
+ + renderTo(element, options) +
+
+ +
+ +
+
+
+ + setRequestCredentials(credentials) +
+
+ +
+ +
+
+
+ + setRequestHeaders(headers) +
+
+ +
+ +
+
+
+ + coverUrl() +
+
+ +
+ +
+
+
+ + range(cfiRange) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Locations +

+ +
+ + +

Find Locations for a Book

+ + +
new Locations(spine: Spine, request: request)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ spine (Spine) +
+ +
+ +
+
+ request (request) +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + generate(chars) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Container +

+ +
+ + +

Handles Parsing and Accessing an Epub Container

+ + +
new Container(containerDocument: [document])
+ + + + + + + + + + +
Parameters
+
+ +
+
+ containerDocument ([document]) xml document + +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + parse(containerDocument) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Packaging +

+ +
+ + +

Open Packaging Format Parser

+ + +
new Packaging(packageDocument: document)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ packageDocument (document) OPF XML + +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + parse(packageDocument) +
+
+ +
+ +
+
+
+ + parseSpine(spineXml, manifest) +
+
+ +
+ +
+
+
+ + findCoverPath(packageXml) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+ + +
+ + +

Navigation Parser

+ + +
new Navigation(xml: document)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ xml (document) navigation html / xhtml / ncx + +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ + + + + +
+ + + + +
+ + + + +
+ + +
+

+ Resources +

+ +
+ + +

Handle Package Resources

+ + +
new Resources(manifest: Manifest, options: [object])
+ + + + + + + + + + +
Parameters
+
+ +
+
+ manifest (Manifest) +
+ +
+ +
+
+ options ([object]) +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
options.archive [Archive] +
options.resolver [method] +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + replacements(archive, resolver) +
+
+ +
+ +
+
+
+ + relativeTo(absolute, resolver) +
+
+ +
+ +
+
+
+ + get(path) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Archive +

+ +
+ + +

Handles Unzipping a requesting files from an Epub Archive

+ + +
new Archive()
+ + + + + + + + + + + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + open(input, isBase64) +
+
+ +
+ +
+
+
+ + openUrl(zipUrl, isBase64) +
+
+ +
+ +
+
+
+ + request(url, type) +
+
+ +
+ +
+
+
+ + getBlob(url, mimeType) +
+
+ +
+ +
+
+
+ + getText(url, encoding) +
+
+ +
+ +
+
+
+ + getBase64(url, mimeType) +
+
+ +
+ +
+
+
+ + createUrl(url, options) +
+
+ +
+ +
+
+
+ + revokeUrl(url) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ EpubCFI +

+ +
+ + +

EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html

+

Implements:

+
    +
  • Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)
  • +
  • Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)
  • +
+

Does Not Implement:

+
    +
  • Temporal Offset (~)
  • +
  • Spatial Offset (@)
  • +
  • Temporal-Spatial Offset (~ + @)
  • +
  • Text Location Assertion ([)
  • +
+ + +
new EpubCFI(cfiFrom: any, base: any, ignoreClass: any)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ cfiFrom (any) +
+ +
+ +
+
+ base (any) +
+ +
+ +
+
+ ignoreClass (any) +
+ +
+ +
+ + + + + + + + + + + + + + + +
+ + + + +
+ + +
+

+ Url +

+ +
+ + +

creates a uri object

+ + +
new Url(urlString: string, baseString: [string]): object
+ + + + + + + + + + +
Parameters
+
+ +
+
+ urlString (string) a url string (relative or absolute) + +
+ +
+ +
+
+ baseString ([string]) optional base for the url, +default to window.location.href + +
+ +
+ +
+ + + + + + +
Returns
+ object: + url + + + + + + + + + + + + + + +
+ + + + +
+ + +
+

+ content +

+ +
+ + + + +
content
+ + + + + + + + + + + + +
Properties
+
+ +
+ hooks.content (method) + + +
+ +
+ + + + + + + + + + + + + +
+ + + + +
+ + +
+

+ Rendition +

+ +
+ + +

[Rendition description]

+ + +
new Rendition(book: Book, options: object)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ book (Book) +
+ +
+ +
+
+ options (object) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
options.width int +
options.height int +
options.ignoreClass string +
options.manager string +
options.view string +
options.layout string +
options.spread string +
options.minSpreadWidth int + overridden by spread: none (never) / both (always) +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + hooks +
+
+ +
+ +
+
+
+ + setManager(manager) +
+
+ +
+ +
+
+
+ + requireManager(manager) +
+
+ +
+ +
+
+
+ + requireView(view) +
+
+ +
+ +
+
+
+ + start() +
+
+ +
+ +
+
+
+ + attachTo(element) +
+
+ +
+ +
+
+
+ + display(target) +
+
+ +
+ +
+
+
+ + moveTo(offset) +
+
+ +
+ +
+
+
+ + next() +
+
+ +
+ +
+
+
+ + prev() +
+
+ +
+ +
+
+
+ + flow(flow) +
+
+ +
+ +
+
+
+ + layout(settings) +
+
+ +
+ +
+
+
+ + spread(spread, min) +
+
+ +
+ +
+
+
+ + reportLocation() +
+
+ +
+ +
+
+
+ + destroy() +
+
+ +
+ +
+
+
+ + range(cfi, ignoreClass) +
+
+ +
+ +
+
+
+ + adjustImages(view) +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Hook +

+ +
+ + +

Hooks allow for injecting functions that must all complete in order before finishing +They will execute in parallel but all must finish before continuing +Functions may return a promise if they are asycn.

+ + +
new Hook(context: any)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ context (any) scope of this + +
+ +
+ +
+ + + + + + + + + +
Example
+ + +
this.content = new EPUBJS.Hook(this);
+ + + + + + +
Instance Members
+
+ +
+
+
+ + register() +
+
+ +
+ +
+
+
+ + trigger() +
+
+ +
+ +
+ + + + +
+ + + + +
+ + +
+

+ Layout +

+ +
+ + +

Figures out the CSS to apply for a layout

+ + +
new Layout(settings: object)
+ + + + + + + + + + +
Parameters
+
+ +
+
+ settings (object) +
+ + + + + + + + + + + + + + + + + + + + +
NameDescription
settings.spread [string] +
+ +
+ +
+ + + + + + + + + + + + + +
Instance Members
+
+ +
+
+
+ + flow(flow) +
+
+ +
+ +
+
+
+ + spread(spread, min) +
+
+ +
+ +
+
+
+ + calculate(_width, _height, _gap) +
+
+ +
+ +
+
+
+ + format(contents) +
+
+ +
+ +
+
+
+ + count(totalWidth) +
+
+ +
+ +
+ + + + +
+ + + +
+
+
+ + + + diff --git a/documentation/md/API.md b/documentation/md/API.md new file mode 100644 index 0000000..f95c273 --- /dev/null +++ b/documentation/md/API.md @@ -0,0 +1,146 @@ + + +# ePub + +Creates a new Book + +**Parameters** + +- `url` **([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer))** URL, Path or ArrayBuffer +- `options` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** to pass to the book + - `options.request` the request function to use + +**Examples** + +```javascript +ePub("/path/to/book.epub", {}) +``` + +Returns **[Book](#book)** a new Book object + +# Book + +Creates a new Book + +**Parameters** + +- `_url` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** +- `options` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** + - `options.requestMethod` **method** a request function to use instead of the default + +**Examples** + +```javascript +new Book("/path/to/book.epub", {}) +``` + +Returns **[Book](#book)** + +## url + +## loaded + +**Properties** + +- `loaded.manifest` **[promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** A child method as property defination + +## open + +open a url + +**Parameters** + +- `_url` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** URL, Path or ArrayBuffer +- `options` **\[[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** to force opening + +**Examples** + +```javascript +book.open("/path/to/book.epub", { base64: false }) +``` + +Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** of when the book has been loaded + +## unpack + +unpack the contents of the Books packageXml + +**Parameters** + +- `packageXml` **[document](https://developer.mozilla.org/en-US/docs/Web/JavaScript)** XML Document + +## section + +Alias for book.spine.get + +**Parameters** + +- `target` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** + +## renderTo + +Sugar to render a book + +**Parameters** + +- `element` +- `options` + +## requestMethod + +Switch request methods depending on if book is archived or not + +**Parameters** + +- `_url` + +## unarchive + +Unarchive a zipped epub + +**Parameters** + +- `bookUrl` +- `isBase64` + +## isArchivedUrl + +Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub) + +**Parameters** + +- `bookUrl` + +## coverUrl + +Get the cover url + +## range + +Find a DOM Range for a given CFI Range + +**Parameters** + +- `cfiRange` + +# EpubCFI + +EPUB CFI spec: + +Implements: + +- Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) +- Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) + +Does Not Implement: + +- Temporal Offset (~) +- Spatial Offset (@) +- Temporal-Spatial Offset (~ + @) +- Text Location Assertion (\[) + +**Parameters** + +- `cfiFrom` +- `base` +- `ignoreClass` diff --git a/src/archive.js b/src/archive.js index 39ab0cf..804770b 100644 --- a/src/archive.js +++ b/src/archive.js @@ -3,14 +3,22 @@ var request = require('./request'); var mime = require('../libs/mime/mime'); var Path = require('./core').Path; +/** + * Handles Unzipping a requesting files from an Epub Archive + * @class + */ function Archive() { - + this.zip = undefined; this.checkRequirements(); this.urlCache = {}; - } -Archive.prototype.checkRequirements = function(callback){ +/** + * Checks to see if JSZip exists in global namspace, + * Requires JSZip if it isn't there + * @private + */ +Archive.prototype.checkRequirements = function(){ try { if (typeof JSZip === 'undefined') { JSZip = require('jszip'); @@ -21,10 +29,22 @@ Archive.prototype.checkRequirements = function(callback){ } }; +/** + * Open an archive + * @param {binary} input + * @param {boolean} isBase64 tells JSZip if the input data is base64 encoded + * @return {Promise} zipfile + */ Archive.prototype.open = function(input, isBase64){ return this.zip.loadAsync(input, {"base64": isBase64}); }; +/** + * Load and Open an archive + * @param {string} zipUrl + * @param {boolean} isBase64 tells JSZip if the input data is base64 encoded + * @return {Promise} zipfile + */ Archive.prototype.openUrl = function(zipUrl, isBase64){ return request(zipUrl, "binary") .then(function(data){ @@ -32,6 +52,12 @@ Archive.prototype.openUrl = function(zipUrl, isBase64){ }.bind(this)); }; +/** + * Request + * @param {string} url a url to request from the archive + * @param {[string]} type specify the type of the returned result + * @return {Promise} + */ Archive.prototype.request = function(url, type){ var deferred = new core.defer(); var response; @@ -63,6 +89,13 @@ Archive.prototype.request = function(url, type){ return deferred.promise; }; +/** + * Handle the response from request + * @private + * @param {any} response + * @param {[string]} type + * @return {any} the parsed result + */ Archive.prototype.handleResponse = function(response, type){ var r; @@ -87,19 +120,30 @@ Archive.prototype.handleResponse = function(response, type){ return r; }; -Archive.prototype.getBlob = function(url, _mimeType){ +/** + * Get a Blob from Archive by Url + * @param {string} url + * @param {[string]} mimeType + * @return {Blob} + */ +Archive.prototype.getBlob = function(url, mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); + mimeType = mimeType || mime.lookup(entry.name); return entry.async("uint8array").then(function(uint8array) { return new Blob([uint8array], {type : mimeType}); }); } }; +/** + * Get Text from Archive by Url + * @param {string} url + * @param {[string]} encoding + * @return {string} + */ Archive.prototype.getText = function(url, encoding){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); @@ -111,19 +155,30 @@ Archive.prototype.getText = function(url, encoding){ } }; -Archive.prototype.getBase64 = function(url, _mimeType){ +/** + * Get a base64 encoded result from Archive by Url + * @param {string} url + * @param {[string]} mimeType + * @return {string} base64 encoded + */ +Archive.prototype.getBase64 = function(url, mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); + mimeType = mimeType || mime.lookup(entry.name); return entry.async("base64").then(function(data) { return "data:" + mimeType + ";base64," + data; }); } }; +/** + * Create a Url from an unarchived item + * @param {string} url + * @param {[object]} options.base64 use base64 encoding or blob url + * @return {Promise} url promise with Url string + */ Archive.prototype.createUrl = function(url, options){ var deferred = new core.defer(); var _URL = window.URL || window.webkitURL || window.mozURL; @@ -177,6 +232,10 @@ Archive.prototype.createUrl = function(url, options){ return deferred.promise; }; +/** + * Revoke Temp Url for a achive item + * @param {string} url url of the item in the archive + */ Archive.prototype.revokeUrl = function(url){ var _URL = window.URL || window.webkitURL || window.mozURL; var fromCache = this.urlCache[url]; diff --git a/src/book.js b/src/book.js index e970366..97f8cec 100644 --- a/src/book.js +++ b/src/book.js @@ -10,6 +10,7 @@ var Container = require('./container'); var Packaging = require('./packaging'); var Navigation = require('./navigation'); var Resources = require('./resources'); +var PageList = require('./pagelist'); var Rendition = require('./rendition'); var Archive = require('./archive'); var request = require('./request'); @@ -21,19 +22,24 @@ var CONTAINER_PATH = "META-INF/container.xml"; /** * Creates a new Book * @class - * @param {string} _url + * @param {string} url * @param {object} options * @param {method} options.requestMethod a request function to use instead of the default + * @param {boolean} [options.requestCredentials=undefined] send the xhr request withCredentials + * @param {object} [options.requestHeaders=undefined] send the xhr request headers + * @param {string} [options.encoding=binary] optional to pass 'binary' or base64' for archived Epubs + * @param {string} [options.replacements=base64] use base64, blobs, or none for replacing assets in archived Epubs * @returns {Book} * @example new Book("/path/to/book.epub", {}) */ function Book(url, options){ this.settings = core.extend(this.settings || {}, { - requestMethod: this.requestMethod, + requestMethod: undefined, requestCredentials: undefined, - encoding: undefined, // optional to pass 'binary' or base64' for archived Epubs - base64: true + requestHeaders: undefined, + encoding: undefined, + replacements: 'base64' }); core.extend(this.settings, options); @@ -70,6 +76,7 @@ function Book(url, options){ // this.ready = RSVP.hash(this.loaded); /** * @property {promise} ready returns after the book is loaded and parsed + * @private */ this.ready = Promise.all([this.loaded.manifest, this.loaded.spine, @@ -85,6 +92,7 @@ function Book(url, options){ /** * @property {method} request + * @private */ this.request = this.settings.requestMethod || request; @@ -103,9 +111,27 @@ function Book(url, options){ */ this.navigation = undefined; + /** + * @property {PageList} pagelist + */ + this.pageList = new PageList(); + + /** + * @property {Url} url + * @private + */ this.url = undefined; + + /** + * @property {Path} path + * @private + */ this.path = undefined; + /** + * @property {boolean} archived + * @private + */ this.archived = false; if(url) { @@ -119,7 +145,7 @@ function Book(url, options){ }; /** - * open a url + * Open a epub or url * @param {string} input URL, Path or ArrayBuffer * @param {string} [what] to force opening * @returns {Promise} of when the book has been loaded @@ -150,6 +176,13 @@ Book.prototype.open = function(input, what){ return opening; }; +/** + * Open an archived epub + * @private + * @param {binary} data + * @param {[string]} encoding + * @return {Promise} + */ Book.prototype.openEpub = function(data, encoding){ return this.unarchive(data, encoding || this.settings.encoding) .then(function() { @@ -160,6 +193,12 @@ Book.prototype.openEpub = function(data, encoding){ }.bind(this)); }; +/** + * Open the epub container + * @private + * @param {string} url + * @return {string} packagePath + */ Book.prototype.openContainer = function(url){ return this.load(url) .then(function(xml) { @@ -168,6 +207,12 @@ Book.prototype.openContainer = function(url){ }.bind(this)); }; +/** + * Open the Open Packaging Format Xml + * @private + * @param {string} url + * @return {Promise} + */ Book.prototype.openPackaging = function(url){ var packageUrl; this.path = new Path(url); @@ -179,6 +224,11 @@ Book.prototype.openPackaging = function(url){ }.bind(this)); }; +/** + * Load a resource from the Book + * @param {string} path path to the resource to load + * @return {Promise} returns a promise with the requested resource + */ Book.prototype.load = function (path) { var resolved; if(this.archived) { @@ -186,10 +236,16 @@ Book.prototype.load = function (path) { return this.archive.request(resolved); } else { resolved = this.resolve(path); - return this.request(resolved, null, this.requestCredentials, this.requestHeaders); + return this.request(resolved, null, this.settings.requestCredentials, this.settings.requestHeaders); } }; +/** + * Resolve a path to it's absolute position in the Book + * @param {string} path + * @param {[boolean]} absolute force resolving the full URL + * @return {string} the resolved path string + */ Book.prototype.resolve = function (path, absolute) { var resolved = path; var isAbsolute = (path.indexOf('://') > -1); @@ -209,6 +265,12 @@ Book.prototype.resolve = function (path, absolute) { return resolved; } +/** + * Determine the type of they input passed to open + * @private + * @param {string} input + * @return {string} binary | directory | epub | opf + */ Book.prototype.determineType = function(input) { var url; var path; @@ -238,6 +300,7 @@ Book.prototype.determineType = function(input) { /** * unpack the contents of the Books packageXml + * @private * @param {document} packageXml XML Document */ Book.prototype.unpack = function(opf){ @@ -248,7 +311,7 @@ Book.prototype.unpack = function(opf){ this.resources = new Resources(this.package.manifest, { archive: this.archive, resolver: this.resolve.bind(this), - base64: this.settings.base64 + replacements: this.settings.replacements }); this.loadNavigation(this.package).then(function(toc){ @@ -264,6 +327,7 @@ Book.prototype.unpack = function(opf){ this.loading.spine.resolve(this.spine); this.loading.cover.resolve(this.cover); this.loading.resources.resolve(this.resources); + this.loading.pageList.resolve(this.pageList); this.isOpen = true; @@ -279,6 +343,11 @@ Book.prototype.unpack = function(opf){ }; +/** + * Load Navigation and PageList from package + * @private + * @param {document} opf XML Document + */ Book.prototype.loadNavigation = function(opf){ var navPath = opf.navPath || opf.ncxPath; @@ -289,6 +358,7 @@ Book.prototype.loadNavigation = function(opf){ return this.load(navPath, 'xml') .then(function(xml) { this.navigation = new Navigation(xml); + this.pageList = new PageList(xml); }.bind(this)); }; @@ -302,6 +372,9 @@ Book.prototype.section = function(target) { /** * Sugar to render a book + * @param {element} element element to add the views to + * @param {[object]} options + * @return {Rendition} */ Book.prototype.renderTo = function(element, options) { // var renderMethod = (options && options.method) ? @@ -314,31 +387,44 @@ Book.prototype.renderTo = function(element, options) { return this.rendition; }; - -Book.prototype.setRequestCredentials = function(_credentials) { - this.requestCredentials = _credentials; +/** + * Set if request should use withCredentials + * @param {boolean} credentials + */ +Book.prototype.setRequestCredentials = function(credentials) { + this.settings.requestCredentials = credentials; }; -Book.prototype.setRequestHeaders = function(_headers) { - this.requestHeaders = _headers; +/** + * Set headers request should use + * @param {object} headers + */ +Book.prototype.setRequestHeaders = function(headers) { + this.settings.requestHeaders = headers; }; /** * Unarchive a zipped epub + * @private + * @param {binary} input epub data + * @param {[string]} encoding + * @return {Archive} */ -Book.prototype.unarchive = function(bookUrl, encoding){ +Book.prototype.unarchive = function(input, encoding){ this.archive = new Archive(); - return this.archive.open(bookUrl, encoding); + return this.archive.open(input, encoding); }; /** * Get the cover url + * @return {string} coverUrl */ Book.prototype.coverUrl = function(){ var retrieved = this.loaded.cover. then(function(url) { if(this.archived) { - return this.archive.createUrl(this.cover); + // return this.archive.createUrl(this.cover); + return this.resources.get(this.cover); }else{ return this.cover; } @@ -349,6 +435,11 @@ Book.prototype.coverUrl = function(){ return retrieved; }; +/** + * load replacement urls + * @private + * @return {Promise} completed loading urls + */ Book.prototype.replacements = function(){ this.spine.hooks.serialize.register(function(output, section) { section.output = this.resources.substitute(output, section.url); @@ -362,6 +453,8 @@ Book.prototype.replacements = function(){ /** * Find a DOM Range for a given CFI Range + * @param {EpubCFI} cfiRange a epub cfi range + * @return {Range} */ Book.prototype.range = function(cfiRange) { var cfi = new EpubCFI(cfiRange); diff --git a/src/container.js b/src/container.js index 2f7088e..db70622 100644 --- a/src/container.js +++ b/src/container.js @@ -2,13 +2,21 @@ var path = require('path'); var core = require('./core'); var EpubCFI = require('./epubcfi'); - +/** + * Handles Parsing and Accessing an Epub Container + * @class + * @param {[document]} containerDocument xml document + */ function Container(containerDocument) { if (containerDocument) { this.parse(containerDocument); } }; +/** + * Parse the Container XML + * @param {document} containerDocument + */ Container.prototype.parse = function(containerDocument){ //-- var rootfile, fullpath, folder, encoding; diff --git a/src/core.js b/src/core.js index 57f2d57..fd25c0a 100644 --- a/src/core.js +++ b/src/core.js @@ -592,7 +592,7 @@ function defer() { } // Handle IE not supporting namespaced epub:type in querySelector if(!query || query.length === 0) { - query = core.qsa(html, element); + query = this.qsa(html, element); for (var i = 0; i < query.length; i++) { if(query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type) { return query[i]; diff --git a/src/epub.js b/src/epub.js index 2a8089b..c249a90 100644 --- a/src/epub.js +++ b/src/epub.js @@ -7,7 +7,6 @@ var Contents = require('./contents'); * Creates a new Book * @param {string|ArrayBuffer} url URL, Path or ArrayBuffer * @param {object} options to pass to the book - * @param options.requestMethod the request function to use * @returns {Book} a new Book object * @example ePub("/path/to/book.epub", {}) */ diff --git a/src/hook.js b/src/hook.js index d5021cc..27e774d 100644 --- a/src/hook.js +++ b/src/hook.js @@ -1,17 +1,19 @@ -//-- Hooks allow for injecting functions that must all complete in order before finishing -// They will execute in parallel but all must finish before continuing -// Functions may return a promise if they are asycn. - -// this.content = new EPUBJS.Hook(); -// this.content.register(function(){}); -// this.content.trigger(args).then(function(){}); - +/** + * Hooks allow for injecting functions that must all complete in order before finishing + * They will execute in parallel but all must finish before continuing + * Functions may return a promise if they are asycn. + * @param {any} context scope of this + * @example this.content = new EPUBJS.Hook(this); + */ function Hook(context){ this.context = context || this; this.hooks = []; }; -// Adds a function to be run before a hook completes +/** + * Adds a function to be run before a hook completes + * @example this.content.register(function(){...}); + */ Hook.prototype.register = function(){ for(var i = 0; i < arguments.length; ++i) { if (typeof arguments[i] === "function") { @@ -25,7 +27,10 @@ Hook.prototype.register = function(){ } }; -// Triggers a hook to run all functions +/** + * Triggers a hook to run all functions + * @example this.content.trigger(args).then(function(){...}); + */ Hook.prototype.trigger = function(){ var args = arguments; var context = this.context; diff --git a/src/layout.js b/src/layout.js index 2673182..b7a2d98 100644 --- a/src/layout.js +++ b/src/layout.js @@ -1,9 +1,18 @@ var core = require('./core'); +/** + * Figures out the CSS to apply for a layout + * @class + * @param {object} settings + * @param {[string=reflowable]} settings.layout + * @param {[string]} settings.spread + * @param {[int=800]} settings.minSpreadWidth + * @param {[boolean=false]} settings.evenSpreads + */ function Layout(settings){ this.name = settings.layout || "reflowable"; this._spread = (settings.spread === "none") ? false : true; - this._minSpreadWidth = settings.spread || 800; + this._minSpreadWidth = settings.minSpreadWidth || 800; this._evenSpreads = settings.evenSpreads || false; if (settings.flow === "scrolled-continuous" || @@ -24,12 +33,20 @@ function Layout(settings){ this.divisor = 1; }; -// paginated | scrolled +/** + * Switch the flow between paginated and scrolled + * @param {string} flow paginated | scrolled + */ Layout.prototype.flow = function(flow) { this._flow = (flow === "paginated") ? "paginated" : "scrolled"; } -// true | false +/** + * Switch between using spreads or not, and set the + * width at which they switch to single. + * @param {string} spread true | false + * @param {boolean} min integer in pixels + */ Layout.prototype.spread = function(spread, min) { this._spread = (spread === "none") ? false : true; @@ -39,6 +56,12 @@ Layout.prototype.spread = function(spread, min) { } } +/** + * Calculate the dimensions of the pagination + * @param {number} _width [description] + * @param {number} _height [description] + * @param {number} _gap [description] + */ Layout.prototype.calculate = function(_width, _height, _gap){ var divisor = 1; @@ -93,6 +116,11 @@ Layout.prototype.calculate = function(_width, _height, _gap){ this.divisor = divisor; }; +/** + * Apply Css to a Document + * @param {Contents} contents + * @return {[Promise]} + */ Layout.prototype.format = function(contents){ var formating; @@ -107,6 +135,12 @@ Layout.prototype.format = function(contents){ return formating; // might be a promise in some View Managers }; +/** + * Count number of pages + * @param {number} totalWidth + * @return {number} spreads + * @return {number} pages + */ Layout.prototype.count = function(totalWidth) { // var totalWidth = contents.scrollWidth(); var spreads = Math.ceil( totalWidth / this.spreadWidth); diff --git a/src/locations.js b/src/locations.js index 985898d..f6fe60f 100644 --- a/src/locations.js +++ b/src/locations.js @@ -3,6 +3,11 @@ var Queue = require('./queue'); var EpubCFI = require('./epubcfi'); var EventEmitter = require('event-emitter'); +/** + * Find Locations for a Book + * @param {Spine} spine + * @param {request} request + */ function Locations(spine, request) { this.spine = spine; this.request = request; @@ -19,7 +24,11 @@ function Locations(spine, request) { }; -// Load all of sections in the book +/** + * Load all of sections in the book to generate locations + * @param {int} chars how many chars to split on + * @return {object} locations + */ Locations.prototype.generate = function(chars) { if (chars) { diff --git a/src/navigation.js b/src/navigation.js index 4000aea..0c21486 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -1,6 +1,10 @@ var core = require('./core'); var path = require('path'); +/** + * Navigation Parser + * @param {document} xml navigation html / xhtml / ncx + */ function Navigation(xml){ this.toc = []; this.tocByHref = {}; @@ -11,6 +15,10 @@ function Navigation(xml){ } }; +/** + * Parse out the navigation items + * @param {document} xml navigation html / xhtml / ncx + */ Navigation.prototype.parse = function(xml) { var html = core.qs(xml, "html"); var ncx = core.qs(xml, "ncx"); @@ -24,6 +32,11 @@ Navigation.prototype.parse = function(xml) { this.unpack(this.toc); }; +/** + * Unpack navigation items + * @private + * @param {array} toc + */ Navigation.prototype.unpack = function(toc) { var item; @@ -35,7 +48,11 @@ Navigation.prototype.unpack = function(toc) { }; -// Get an item from the navigation +/** + * Get an item from the navigation + * @param {string} target + * @return {object} navItems + */ Navigation.prototype.get = function(target) { var index; @@ -52,9 +69,14 @@ Navigation.prototype.get = function(target) { return this.toc[index]; }; -Navigation.prototype.parseNav = function(navHtml, spineIndexByURL, bookSpine){ +/** + * Parse from a Epub > 3.0 Nav + * @private + * @param {document} navHtml + * @return {array} navigation list + */ +Navigation.prototype.parseNav = function(navHtml){ var navElement = core.querySelectorByType(navHtml, "nav", "toc"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; var navItems = navElement ? core.qsa(navElement, "li") : []; var length = navItems.length; var i; @@ -65,7 +87,7 @@ Navigation.prototype.parseNav = function(navHtml, spineIndexByURL, bookSpine){ if(!navItems || length === 0) return list; for (i = 0; i < length; ++i) { - item = this.navItem(navItems[i], spineIndexByURL, bookSpine); + item = this.navItem(navItems[i]); toc[item.id] = item; if(!item.parent) { list.push(item); @@ -78,38 +100,25 @@ Navigation.prototype.parseNav = function(navHtml, spineIndexByURL, bookSpine){ return list; }; -Navigation.prototype.navItem = function(item, spineIndexByURL, bookSpine){ +/** + * Create a navItem + * @private + * @param {element} item + * @return {object} navItem + */ +Navigation.prototype.navItem = function(item){ var id = item.getAttribute('id') || false, - // content = item.querySelector("a, span"), content = core.qs(item, "a"), src = content.getAttribute('href') || '', text = content.textContent || "", - // split = src.split("#"), - // baseUrl = split[0], - // spinePos = spineIndexByURL[baseUrl], - // spineItem = bookSpine[spinePos], subitems = [], parentNode = item.parentNode, parent; - // cfi = spineItem ? spineItem.cfi : ''; if(parentNode && parentNode.nodeName === "navPoint") { parent = parentNode.getAttribute('id'); } - /* - if(!id) { - if(spinePos) { - spineItem = bookSpine[spinePos]; - id = spineItem.id; - cfi = spineItem.cfi; - } else { - id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid(); - item.setAttribute('id', id); - } - } - */ - return { "id": id, "href": src, @@ -119,8 +128,13 @@ Navigation.prototype.navItem = function(item, spineIndexByURL, bookSpine){ }; }; -Navigation.prototype.parseNcx = function(tocXml, spineIndexByURL, bookSpine){ - // var navPoints = tocXml.querySelectorAll("navMap navPoint"); +/** + * Parse from a Epub > 3.0 NC + * @private + * @param {document} navHtml + * @return {array} navigation list + */ +Navigation.prototype.parseNcx = function(tocXml){ var navPoints = core.qsa(tocXml, "navPoint"); var length = navPoints.length; var i; @@ -131,7 +145,7 @@ Navigation.prototype.parseNcx = function(tocXml, spineIndexByURL, bookSpine){ if(!navPoints || length === 0) return list; for (i = 0; i < length; ++i) { - item = this.ncxItem(navPoints[i], spineIndexByURL, bookSpine); + item = this.ncxItem(navPoints[i]); toc[item.id] = item; if(!item.parent) { list.push(item); @@ -144,39 +158,26 @@ Navigation.prototype.parseNcx = function(tocXml, spineIndexByURL, bookSpine){ return list; }; -Navigation.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ +/** + * Create a ncxItem + * @private + * @param {element} item + * @return {object} ncxItem + */ +Navigation.prototype.ncxItem = function(item){ var id = item.getAttribute('id') || false, - // content = item.querySelector("content"), content = core.qs(item, "content"), src = content.getAttribute('src'), - // navLabel = item.querySelector("navLabel"), navLabel = core.qs(item, "navLabel"), text = navLabel.textContent ? navLabel.textContent : "", - // split = src.split("#"), - // baseUrl = split[0], - // spinePos = spineIndexByURL[baseUrl], - // spineItem = bookSpine[spinePos], subitems = [], parentNode = item.parentNode, parent; - // cfi = spineItem ? spineItem.cfi : ''; if(parentNode && parentNode.nodeName === "navPoint") { parent = parentNode.getAttribute('id'); } - /* - if(!id) { - if(spinePos) { - spineItem = bookSpine[spinePos]; - id = spineItem.id; - cfi = spineItem.cfi; - } else { - id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid(); - item.setAttribute('id', id); - } - } - */ return { "id": id, diff --git a/src/packaging.js b/src/packaging.js index 2a2f6db..27138ba 100644 --- a/src/packaging.js +++ b/src/packaging.js @@ -2,13 +2,22 @@ var path = require('path'); var core = require('./core'); var EpubCFI = require('./epubcfi'); - +/** + * Open Packaging Format Parser + * @class + * @param {document} packageDocument OPF XML + */ function Packaging(packageDocument) { if (packageDocument) { this.parse(packageDocument); } }; +/** + * Parse OPF XML + * @param {document} packageDocument OPF XML + * @return {object} parsed package parts + */ Packaging.prototype.parse = function(packageDocument){ var metadataNode, manifestNode, spineNode; @@ -60,6 +69,12 @@ Packaging.prototype.parse = function(packageDocument){ }; }; +/** + * Parse Metadata + * @private + * @param {document} xml + * @return {object} metadata + */ Packaging.prototype.parseMetadata = function(xml){ var metadata = {}; @@ -86,6 +101,12 @@ Packaging.prototype.parseMetadata = function(xml){ return metadata; }; +/** + * Parse Manifest + * @private + * @param {document} manifestXml + * @return {object} manifest + */ Packaging.prototype.parseManifest = function(manifestXml){ var manifest = {}; @@ -114,6 +135,12 @@ Packaging.prototype.parseManifest = function(manifestXml){ }; +/** + * Parse Spine + * @param {document} spineXml + * @param {Packaging.manifest} manifest + * @return {object} spine + */ Packaging.prototype.parseSpine = function(spineXml, manifest){ var spine = []; @@ -148,6 +175,7 @@ Packaging.prototype.parseSpine = function(spineXml, manifest){ /** * Find TOC NAV + * @private */ Packaging.prototype.findNavPath = function(manifestNode){ // Find item with property 'nav' @@ -160,6 +188,7 @@ Packaging.prototype.findNavPath = function(manifestNode){ /** * Find TOC NCX * media-type="application/x-dtbncx+xml" href="toc.ncx" + * @private */ Packaging.prototype.findNcxPath = function(manifestNode, spineNode){ // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); @@ -180,8 +209,13 @@ Packaging.prototype.findNcxPath = function(manifestNode, spineNode){ return node ? node.getAttribute('href') : false; }; -//-- Find Cover: -//-- Fallback for Epub 2.0 +/** + * Find the Cover Path + * + * Fallback for Epub 2.0 + * @param {document} packageXml + * @return {string} href + */ Packaging.prototype.findCoverPath = function(packageXml){ var pkg = core.qs(packageXml, "package"); var epubVersion = pkg.getAttribute('version'); @@ -205,6 +239,13 @@ Packaging.prototype.findCoverPath = function(packageXml){ } }; +/** + * Get text of a namespaced element + * @private + * @param {document} xml + * @param {string} tag + * @return {string} text + */ Packaging.prototype.getElementText = function(xml, tag){ var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag), el; @@ -221,6 +262,13 @@ Packaging.prototype.getElementText = function(xml, tag){ }; +/** + * Get text by property + * @private + * @param {document} xml + * @param {string} property + * @return {string} text + */ Packaging.prototype.getPropertyText = function(xml, property){ var el = core.qsp(xml, "meta", {"property":property}); diff --git a/src/pagelist.js b/src/pagelist.js new file mode 100644 index 0000000..4035251 --- /dev/null +++ b/src/pagelist.js @@ -0,0 +1,249 @@ +var EpubCFI = require('./epubcfi'); +var core = require('./core'); + +/** + * Page List Parser + * @param {[document]} xml + */ +function PageList(xml) { + this.pages = []; + this.locations = []; + this.epubcfi = new EpubCFI(); + + if (xml) { + this.pageList = this.parse(xml); + } + + if(this.pageList && this.pageList.length) { + this.process(this.pageList); + } +}; + +/** + * Parse PageList Xml + * @param {document} xml + */ +PageList.prototype.parse = function(xml) { + var html = core.qs(xml, "html"); + // var ncx = core.qs(xml, "ncx"); + + if(html) { + this.toc = this.parseNav(xml); + } else if(ncx){ // Not supported + // this.toc = this.parseNcx(xml); + return; + } + +}; + +/** + * Parse a Nav PageList + * @private + * @param {document} navHtml + * @return {PageList.item[]} list + */ +PageList.prototype.parseNav = function(navHtml){ + var navElement = core.querySelectorByType(navHtml, "nav", "page-list"); + var navItems = navElement ? core.qsa(navElement, "li") : []; + var length = navItems.length; + var i; + var toc = {}; + var list = []; + var item; + + if(!navItems || length === 0) return list; + + for (i = 0; i < length; ++i) { + item = this.item(navItems[i]); + list.push(item); + } + + return list; +}; + +/** + * Page List Item + * @private + * @param {object} item + * @return {object} pageListItem + */ +PageList.prototype.item = function(item){ + var id = item.getAttribute('id') || false, + content = core.qs(item, "a"), + href = content.getAttribute('href') || '', + text = content.textContent || "", + page = parseInt(text), + isCfi = href.indexOf("epubcfi"), + split, + packageUrl, + cfi; + + if(isCfi != -1) { + split = href.split("#"); + packageUrl = split[0]; + cfi = split.length > 1 ? split[1] : false; + return { + "cfi" : cfi, + "href" : href, + "packageUrl" : packageUrl, + "page" : page + }; + } else { + return { + "href" : href, + "page" : page + }; + } +}; + +/** + * Process pageList items + * @private + * @param {array} pageList + */ +PageList.prototype.process = function(pageList){ + pageList.forEach(function(item){ + this.pages.push(item.page); + if (item.cfi) { + this.locations.push(item.cfi); + } + }, this); + this.firstPage = parseInt(this.pages[0]); + this.lastPage = parseInt(this.pages[this.pages.length-1]); + this.totalPages = this.lastPage - this.firstPage; +}; + + +/** + * Replace HREFs with CFI + * TODO: implement getting CFI from Href + */ +PageList.prototype.addCFIs = function() { + this.pageList.forEach(function(pg){ + if(!pg.cfi) { + // epubcfi.generateCfiFromHref(pg.href, book).then(function(cfi){ + // pg.cfi = cfi; + // pg.packageUrl = book.settings.packageUrl; + // }); + } + }); +} + +/* +EPUBJS.EpubCFI.prototype.generateCfiFromHref = function(href, book) { + var uri = EPUBJS.core.uri(href); + var path = uri.path; + var fragment = uri.fragment; + var spinePos = book.spineIndexByURL[path]; + var loaded; + var deferred = new RSVP.defer(); + var epubcfi = new EPUBJS.EpubCFI(); + var spineItem; + + if(typeof spinePos !== "undefined"){ + spineItem = book.spine[spinePos]; + loaded = book.loadXml(spineItem.url); + loaded.then(function(doc){ + var element = doc.getElementById(fragment); + var cfi; + cfi = epubcfi.generateCfiFromElement(element, spineItem.cfiBase); + deferred.resolve(cfi); + }); + } + + return deferred.promise; +}; +*/ + +/** + * Get a PageList result from a EpubCFI + * @param {string} cfi EpubCFI String + * @return {string} page + */ +PageList.prototype.pageFromCfi = function(cfi){ + var pg = -1; + + // Check if the pageList has not been set yet + if(this.locations.length === 0) { + return -1; + } + + // TODO: check if CFI is valid? + + // check if the cfi is in the location list + // var index = this.locations.indexOf(cfi); + var index = core.indexOfSorted(cfi, this.locations, this.epubcfi.compare); + if(index != -1) { + pg = this.pages[index]; + } else { + // Otherwise add it to the list of locations + // Insert it in the correct position in the locations page + //index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare); + index = EPUBJS.core.locationOf(cfi, this.locations, this.epubcfi.compare); + // Get the page at the location just before the new one, or return the first + pg = index-1 >= 0 ? this.pages[index-1] : this.pages[0]; + if(pg !== undefined) { + // Add the new page in so that the locations and page array match up + //this.pages.splice(index, 0, pg); + } else { + pg = -1; + } + + } + return pg; +}; + +/** + * Get an EpubCFI from a Page List Item + * @param {string} pg + * @return {string} cfi + */ +PageList.prototype.cfiFromPage = function(pg){ + var cfi = -1; + // check that pg is an int + if(typeof pg != "number"){ + pg = parseInt(pg); + } + + // check if the cfi is in the page list + // Pages could be unsorted. + var index = this.pages.indexOf(pg); + if(index != -1) { + cfi = this.locations[index]; + } + // TODO: handle pages not in the list + return cfi; +}; + +/** + * Get a Page from Book percentage + * @param {number} percent + * @return {string} page + */ +PageList.prototype.pageFromPercentage = function(percent){ + var pg = Math.round(this.totalPages * percent); + return pg; +}; + +/** + * Returns a value between 0 - 1 corresponding to the location of a page + * @param {int} pg the page + * @return {number} percentage + */ +PageList.prototype.percentageFromPage = function(pg){ + var percentage = (pg - this.firstPage) / this.totalPages; + return Math.round(percentage * 1000) / 1000; +}; + +/** + * Returns a value between 0 - 1 corresponding to the location of a cfi + * @param {string} cfi EpubCFI String + * @return {number} percentage + */ +PageList.prototype.percentageFromCfi = function(cfi){ + var pg = this.pageFromCfi(cfi); + var percentage = this.percentageFromPage(pg); + return percentage; +}; + +module.exports = PageList; diff --git a/src/parser.js b/src/parser.js deleted file mode 100644 index 0735f14..0000000 --- a/src/parser.js +++ /dev/null @@ -1,90 +0,0 @@ -var path = require('path'); -var core = require('./core'); -var EpubCFI = require('./epubcfi'); - - -function Parser(){}; - -/* -Parser.prototype.querySelectorText = function(xml, q){ - var el = xml.querySelector(q); - - if(el && el.childNodes.length){ - return el.childNodes[0].nodeValue; - } - - return ''; -}; -*/ - -Parser.prototype.querySelectorByType = function(html, element, type){ - var query; - if (typeof html.querySelector != "undefined") { - query = html.querySelector(element+'[*|type="'+type+'"]'); - } - // Handle IE not supporting namespaced epub:type in querySelector - if(!query || query.length === 0) { - query = core.qsa(html, element); - for (var i = 0; i < query.length; i++) { - if(query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type) { - return query[i]; - } - } - } else { - return query; - } -}; - - - -Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){ - var navElement = this.querySelectorByType(navHtml, "nav", "page-list"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; - var navItems = navElement ? core.qsa(navElement, "li") : []; - var length = navItems.length; - var i; - var toc = {}; - var list = []; - var item; - - if(!navItems || length === 0) return list; - - for (i = 0; i < length; ++i) { - item = this.pageListItem(navItems[i], spineIndexByURL, bookSpine); - list.push(item); - } - - return list; -}; - -Parser.prototype.pageListItem = function(item, spineIndexByURL, bookSpine){ - var id = item.getAttribute('id') || false, - // content = item.querySelector("a"), - content = core.qs(item, "a"), - href = content.getAttribute('href') || '', - text = content.textContent || "", - page = parseInt(text), - isCfi = href.indexOf("epubcfi"), - split, - packageUrl, - cfi; - - if(isCfi != -1) { - split = href.split("#"); - packageUrl = split[0]; - cfi = split.length > 1 ? split[1] : false; - return { - "cfi" : cfi, - "href" : href, - "packageUrl" : packageUrl, - "page" : page - }; - } else { - return { - "href" : href, - "page" : page - }; - } -}; - -module.exports = Parser; diff --git a/src/queue.js b/src/queue.js index 9fb7aae..5b9a39d 100644 --- a/src/queue.js +++ b/src/queue.js @@ -1,14 +1,22 @@ var core = require('./core'); -function Queue(_context){ +/** + * Queue for handling tasks one at a time + * @class + * @param {scope} context what this will resolve to in the tasks + */ +function Queue(context){ this._q = []; - this.context = _context; + this.context = context; this.tick = core.requestAnimationFrame; this.running = false; this.paused = false; }; -// Add an item to the queue +/** + * Add an item to the queue + * @return {Promise} + */ Queue.prototype.enqueue = function() { var deferred, promise; var queued; @@ -56,7 +64,10 @@ Queue.prototype.enqueue = function() { return queued.promise; }; -// Run one item +/** + * Run one item + * @return {Promise} + */ Queue.prototype.dequeue = function(){ var inwait, task, result; @@ -101,8 +112,10 @@ Queue.prototype.dump = function(){ } }; -// Run all sequentially, at convince - +/** + * Run all tasks sequentially, at convince + * @return {Promise} + */ Queue.prototype.run = function(){ if(!this.running){ @@ -134,7 +147,10 @@ Queue.prototype.run = function(){ return this.defered.promise; }; -// Flush all, as quickly as possible +/** + * Flush all, as quickly as possible + * @return {Promise} + */ Queue.prototype.flush = function(){ if(this.running){ @@ -153,21 +169,38 @@ Queue.prototype.flush = function(){ }; -// Clear all items in wait +/** + * Clear all items in wait + */ Queue.prototype.clear = function(){ this._q = []; this.running = false; }; +/** + * Get the number of tasks in the queue + * @return {int} tasks + */ Queue.prototype.length = function(){ return this._q.length; }; +/** + * Pause a running queue + */ Queue.prototype.pause = function(){ this.paused = true; }; -// Create a new task from a callback +/** + * Create a new task from a callback + * @class + * @private + * @param {function} task + * @param {array} args + * @param {scope} context + * @return {function} task + */ function Task(task, args, context){ return function(){ diff --git a/src/rendition.js b/src/rendition.js index fcf5f72..6fc0c27 100644 --- a/src/rendition.js +++ b/src/rendition.js @@ -9,6 +9,20 @@ var Layout = require('./layout'); var Mapping = require('./mapping'); var Path = require('./core').Path; +/** + * [Rendition description] + * @class + * @param {Book} book + * @param {object} options + * @param {int} options.width + * @param {int} options.height + * @param {string} options.ignoreClass + * @param {string} options.manager + * @param {string} options.view + * @param {string} options.layout + * @param {string} options.spread + * @param {int} options.minSpreadWidth overridden by spread: none (never) / both (always) + */ function Rendition(book, options) { this.settings = core.extend(this.settings || {}, { @@ -20,8 +34,7 @@ function Rendition(book, options) { flow: null, layout: null, spread: null, - minSpreadWidth: 800, //-- overridden by spread: none (never) / both (always), - useBase64: true + minSpreadWidth: 800 }); core.extend(this.settings, options); @@ -34,10 +47,17 @@ function Rendition(book, options) { this.views = null; - //-- Adds Hook methods to the Rendition prototype + /** + * Adds Hook methods to the Rendition prototype + * @property {Hook} hooks + */ this.hooks = {}; this.hooks.display = new Hook(this); this.hooks.serialize = new Hook(this); + /** + * @property {method} hooks.content + * @type {Hook} + */ this.hooks.content = new Hook(this); this.hooks.layout = new Hook(this); this.hooks.render = new Hook(this); @@ -55,15 +75,24 @@ function Rendition(book, options) { this.q.enqueue(this.book.opened); // Block the queue until rendering is started - // this.starting = new core.defer(); - // this.started = this.starting.promise; + this.starting = new core.defer(); + this.started = this.starting.promise; this.q.enqueue(this.start); }; +/** + * Set the manager function + * @param {function} manager + */ Rendition.prototype.setManager = function(manager) { this.manager = manager; }; +/** + * Require the manager from passed string, or as a function + * @param {string|function} manager [description] + * @return {method} + */ Rendition.prototype.requireManager = function(manager) { var viewManager; @@ -80,6 +109,11 @@ Rendition.prototype.requireManager = function(manager) { return viewManager; }; +/** + * Require the view from passed string, or as a function + * @param {string|function} view + * @return {view} + */ Rendition.prototype.requireView = function(view) { var View; @@ -93,6 +127,10 @@ Rendition.prototype.requireView = function(view) { return View; }; +/** + * Start the rendering + * @return {Promise} rendering has started + */ Rendition.prototype.start = function(){ if(!this.manager) { @@ -130,11 +168,15 @@ Rendition.prototype.start = function(){ this.emit("started"); // Start processing queue - // this.starting.resolve(); + this.starting.resolve(); }; -// Call to attach the container to an element in the dom -// Container must be attached before rendering can begin +/** + * Call to attach the container to an element in the dom + * Container must be attached before rendering can begin + * @param {element} element to attach to + * @return {Promise} + */ Rendition.prototype.attachTo = function(element){ return this.q.enqueue(function () { @@ -152,6 +194,14 @@ Rendition.prototype.attachTo = function(element){ }; +/** + * Display a point in the book + * The request will be added to the rendering Queue, + * so it will wait until book is opened, rendering started + * and all other rendering tasks have finished to be called. + * @param {string} target Url or EpubCFI + * @return {Promise} + */ Rendition.prototype.display = function(target){ // if (!this.book.spine.spineItems.length > 0) { @@ -163,6 +213,12 @@ Rendition.prototype.display = function(target){ }; +/** + * Tells the manager what to display immediately + * @private + * @param {string} target Url or EpubCFI + * @return {Promise} + */ Rendition.prototype._display = function(target){ var isCfiString = this.epubcfi.isCfiString(target); var displaying = new core.defer(); @@ -240,13 +296,22 @@ Rendition.prototype.render = function(view, show) { }; */ +/** + * Report what has been displayed + * @private + * @param {*} view + */ Rendition.prototype.afterDisplayed = function(view){ this.hooks.content.trigger(view, this); this.emit("rendered", view.section); this.reportLocation(); }; -Rendition.prototype.onResized = function(size){ +/** + * Report resize events and display the last seen location + * @private + */ +Rendition.prototype.onResized = function(){ if(this.location) { this.display(this.location.start); @@ -259,23 +324,42 @@ Rendition.prototype.onResized = function(size){ }; +/** + * Move the Rendition to a specific offset + * Usually you would be better off calling display() + * @param {object} offset + */ Rendition.prototype.moveTo = function(offset){ this.manager.moveTo(offset); }; +/** + * Go to the next "page" in the rendition + * @return {Promise} + */ Rendition.prototype.next = function(){ return this.q.enqueue(this.manager.next.bind(this.manager)) .then(this.reportLocation.bind(this)); }; +/** + * Go to the previous "page" in the rendition + * @return {Promise} + */ Rendition.prototype.prev = function(){ return this.q.enqueue(this.manager.prev.bind(this.manager)) .then(this.reportLocation.bind(this)); }; //-- http://www.idpf.org/epub/301/spec/epub-publications.html#meta-properties-rendering +/** + * Determine the Layout properties from metadata and settings + * @private + * @param {object} metadata + * @return {object} properties + */ Rendition.prototype.determineLayoutProperties = function(metadata){ - var settings; + var properties; var layout = this.settings.layout || metadata.layout || "reflowable"; var spread = this.settings.spread || metadata.spread || "auto"; var orientation = this.settings.orientation || metadata.orientation || "auto"; @@ -287,7 +371,7 @@ Rendition.prototype.determineLayoutProperties = function(metadata){ viewport = "width="+this.settings.width+", height="+this.settings.height+""; } - settings = { + properties = { layout : layout, spread : spread, orientation : orientation, @@ -296,7 +380,7 @@ Rendition.prototype.determineLayoutProperties = function(metadata){ minSpreadWidth : minSpreadWidth }; - return settings; + return properties; }; // Rendition.prototype.applyLayoutProperties = function(){ @@ -307,28 +391,34 @@ Rendition.prototype.determineLayoutProperties = function(metadata){ // this.layout(settings); // }; -// paginated | scrolled -// (scrolled-continuous vs scrolled-doc are handled by different view managers) -Rendition.prototype.flow = function(_flow){ - var flow; - if (_flow === "scrolled-doc" || _flow === "scrolled-continuous") { - flow = "scrolled"; +/** + * Adjust the flow of the rendition to paginated or scrolled + * (scrolled-continuous vs scrolled-doc are handled by different view managers) + * @param {string} flow + */ +Rendition.prototype.flow = function(flow){ + var _flow; + if (flow === "scrolled-doc" || flow === "scrolled-continuous") { + _flow = "scrolled"; } - if (_flow === "auto" || _flow === "paginated") { - flow = "paginated"; + if (flow === "auto" || flow === "paginated") { + _flow = "paginated"; } if (this._layout) { - this._layout.flow(flow); + this._layout.flow(_flow); } if (this.manager) { - this.manager.updateFlow(flow); + this.manager.updateFlow(_flow); } }; -// reflowable | pre-paginated +/** + * Adjust the layout of the rendition to reflowable or pre-paginated + * @param {object} settings + */ Rendition.prototype.layout = function(settings){ if (settings) { this._layout = new Layout(settings); @@ -344,7 +434,11 @@ Rendition.prototype.layout = function(settings){ return this._layout; }; -// none | auto (TODO: implement landscape, portrait, both) +/** + * Adjust if the rendition uses spreads + * @param {string} spread none | auto (TODO: implement landscape, portrait, both) + * @param {int} min min width to use spreads at + */ Rendition.prototype.spread = function(spread, min){ this._layout.spread(spread, min); @@ -354,7 +448,9 @@ Rendition.prototype.spread = function(spread, min){ } }; - +/** + * Report the current location + */ Rendition.prototype.reportLocation = function(){ return this.q.enqueue(function(){ var location = this.manager.currentLocation(); @@ -371,7 +467,9 @@ Rendition.prototype.reportLocation = function(){ }.bind(this)); }; - +/** + * Remove and Clean Up the Rendition + */ Rendition.prototype.destroy = function(){ // Clear the queue this.q.clear(); @@ -379,6 +477,11 @@ Rendition.prototype.destroy = function(){ this.manager.destroy(); }; +/** + * Pass the events from a view + * @private + * @param {View} view + */ Rendition.prototype.passViewEvents = function(view){ view.contents.listenedEvents.forEach(function(e){ view.on(e, this.triggerViewEvent.bind(this)); @@ -387,26 +490,46 @@ Rendition.prototype.passViewEvents = function(view){ view.on("selected", this.triggerSelectedEvent.bind(this)); }; +/** + * Emit events passed by a view + * @private + * @param {event} e + */ Rendition.prototype.triggerViewEvent = function(e){ this.emit(e.type, e); }; +/** + * Emit a selection event's CFI Range passed from a a view + * @private + * @param {EpubCFI} cfirange + */ Rendition.prototype.triggerSelectedEvent = function(cfirange){ this.emit("selected", cfirange); }; -Rendition.prototype.range = function(_cfi, ignoreClass){ - var cfi = new EpubCFI(_cfi); +/** + * Get a Range from a Visible CFI + * @param {string} cfi EpubCfi String + * @param {string} ignoreClass + * @return {range} + */ +Rendition.prototype.range = function(cfi, ignoreClass){ + var _cfi = new EpubCFI(cfi); var found = this.visible().filter(function (view) { - if(cfi.spinePos === view.index) return true; + if(_cfi.spinePos === view.index) return true; }); // Should only every return 1 item if (found.length) { - return found[0].range(cfi, ignoreClass); + return found[0].range(_cfi, ignoreClass); } }; +/** + * Hook to adjust images to fit in columns + * @param {View} view + */ Rendition.prototype.adjustImages = function(view) { view.addStylesheetRules([ diff --git a/src/resources.js b/src/resources.js index 3fbf242..7572daf 100644 --- a/src/resources.js +++ b/src/resources.js @@ -3,9 +3,18 @@ var core = require('./core'); var Path = require('./core').Path; var path = require('path'); +/** + * Handle Package Resources + * @class + * @param {Manifest} manifest + * @param {[object]} options + * @param {[string='base64']} options.replacements + * @param {[Archive]} options.archive + * @param {[method]} options.resolver + */ function Resources(manifest, options) { this.settings = { - base64: (options && options.base64) || true, + replacements: (options && options.replacements) || 'base64', archive: (options && options.archive), resolver: (options && options.resolver) }; @@ -15,12 +24,16 @@ function Resources(manifest, options) { return manifest[key]; }); - this.replacementUrls = undefined; + this.replacementUrls = []; this.split(); - this.urls(); + this.splitUrls(); } +/** + * Split resources by type + * @private + */ Resources.prototype.split = function(){ // HTML @@ -50,7 +63,11 @@ Resources.prototype.split = function(){ }); }; -Resources.prototype.urls = function(){ +/** + * Convert split resources into Urls + * @private + */ +Resources.prototype.splitUrls = function(){ // All Assets Urls this.urls = this.assets. @@ -74,11 +91,18 @@ Resources.prototype.urls = function(){ Resources.prototype.replacements = function(archive, resolver){ archive = archive || this.settings.archive; resolver = resolver || this.settings.resolver; + + if (this.settings.replacements === "none") { + return new Promise(function(resolve, reject) { + resolve(this.urls); + }.bind(this)); + } + var replacements = this.urls. map(function(url) { var absolute = resolver(url); - return archive.createUrl(absolute, {"base64": this.settings.base64}); + return archive.createUrl(absolute, {"base64": (this.settings.replacements === "base64")}); }.bind(this)) return Promise.all(replacements) @@ -88,12 +112,19 @@ Resources.prototype.replacements = function(archive, resolver){ }.bind(this)); }; +/** + * Replace URLs in CSS resources + * @private + * @param {[Archive]} archive + * @param {[method]} resolver + * @return {Promise} + */ Resources.prototype.replaceCss = function(archive, resolver){ var replaced = []; archive = archive || this.settings.archive; resolver = resolver || this.settings.resolver; this.cssUrls.forEach(function(href) { - var replacment = this.createCssFile(href, archive, resolver) + var replacement = this.createCssFile(href, archive, resolver) .then(function (replacementUrl) { // switch the url in the replacementUrls var indexInUrls = this.urls.indexOf(href); @@ -102,11 +133,19 @@ Resources.prototype.replaceCss = function(archive, resolver){ } }.bind(this)); - replaced.push(replacment); + replaced.push(replacement); }.bind(this)); return Promise.all(replaced); }; +/** + * Create a new CSS file with the replaced URLs + * @private + * @param {string} href the original css file + * @param {[Archive]} archive + * @param {[method]} resolver + * @return {Promise} returns a BlobUrl to the new CSS file or a data url + */ Resources.prototype.createCssFile = function(href, archive, resolver){ var newUrl; var indexInUrls; @@ -136,7 +175,7 @@ Resources.prototype.createCssFile = function(href, archive, resolver){ text = replace.substitute(text, relUrls, this.replacementUrls); // Get the new url - if (this.settings.base64) { + if (this.settings.replacements === "base64") { newUrl = core.createBase64Url(text, 'text/css'); } else { newUrl = core.createBlobUrl(text, 'text/css'); @@ -147,6 +186,12 @@ Resources.prototype.createCssFile = function(href, archive, resolver){ }; +/** + * Resolve all resources URLs relative to an absolute URL + * @param {string} absolute to be resolved to + * @param {[resolver]} resolver + * @return {string[]} array with relative Urls + */ Resources.prototype.relativeTo = function(absolute, resolver){ resolver = resolver || this.settings.resolver; @@ -159,14 +204,24 @@ Resources.prototype.relativeTo = function(absolute, resolver){ }.bind(this)); }; -Resources.prototype.substitute = function(content, url) { - var relUrls; - if (url) { - relUrls = this.relativeTo(url); - } else { - relUrls = this.urls; +/** + * Get a URL for a resource + * @param {string} path + * @return {string} url + */ +Resources.prototype.get = function(path) { + var indexInUrls = this.urls.indexOf(path); + if (indexInUrls === -1) { + return; } - return replace.substitute(content, relUrls, this.replacementUrls); -}; + if (this.replacementUrls.length) { + return new Promise(function(resolve, reject) { + resolve(this.replacementUrls[indexInUrls]); + }.bind(this)); + } else { + return archive.createUrl(absolute, + {"base64": (this.settings.replacements === "base64")}) + } +} module.exports = Resources; diff --git a/src/section.js b/src/section.js index 21cf09e..acffaa3 100644 --- a/src/section.js +++ b/src/section.js @@ -3,6 +3,12 @@ var EpubCFI = require('./epubcfi'); var Hook = require('./hook'); var Url = require('./core').Url; +/** + * Represents a Section of the Book + * In most books this is equivelent to a Chapter + * @param {object} item The spine item representing the section + * @param {object} hooks hooks for serialize and content + */ function Section(item, hooks){ this.idref = item.idref; this.linear = item.linear; @@ -25,7 +31,11 @@ function Section(item, hooks){ }; - +/** + * Load the section from its url + * @param {method} _request a request method to use for loading + * @return {document} a promise with the xml document + */ Section.prototype.load = function(_request){ var request = _request || this.request || require('./request'); var loading = new core.defer(); @@ -55,6 +65,11 @@ Section.prototype.load = function(_request){ return loaded; }; +/** + * Adds a base tag for resolving urls in the section + * @private + * @param {document} _document + */ Section.prototype.base = function(_document){ var task = new core.defer(); var base = _document.createElement("base"); // TODO: check if exists @@ -76,10 +91,11 @@ Section.prototype.base = function(_document){ return task.promise; }; -Section.prototype.beforeSectionLoad = function(){ - // Stub for a hook - replace me for now -}; - +/** + * Render the contents of a section + * @param {method} _request a request method to use for loading + * @return {string} output a serialized XML Document + */ Section.prototype.render = function(_request){ var rendering = new core.defer(); var rendered = rendering.promise; @@ -109,15 +125,21 @@ Section.prototype.render = function(_request){ return rendered; }; -Section.prototype.find = function(_query){ +/** + * Find a string in a section + * TODO: need reimplementation from v0.2 + * @param {string} query [description] + * @return {[type]} [description] + */ +Section.prototype.find = function(query){ }; -/* +/** * Reconciles the current chapters layout properies with * the global layout properities. -* Takes: global layout settings object, chapter properties string -* Returns: Object with layout properties +* @param {object} global The globa layout settings object, chapter properties string +* @return {object} layoutProperties Object with layout properties */ Section.prototype.reconcileLayoutSettings = function(global){ //-- Get the global defaults @@ -143,10 +165,20 @@ Section.prototype.reconcileLayoutSettings = function(global){ return settings; }; +/** + * Get a CFI from a Range in the Section + * @param {range} _range + * @return {string} cfi an EpubCFI string + */ Section.prototype.cfiFromRange = function(_range) { return new EpubCFI(_range, this.cfiBase).toString(); }; +/** + * Get a CFI from an Element in the Section + * @param {element} el + * @return {string} cfi an EpubCFI string + */ Section.prototype.cfiFromElement = function(el) { return new EpubCFI(el, this.cfiBase).toString(); }; diff --git a/src/spine.js b/src/spine.js index 9cf8450..382433f 100644 --- a/src/spine.js +++ b/src/spine.js @@ -4,6 +4,9 @@ var Hook = require('./hook'); var Section = require('./section'); var replacements = require('./replacements'); +/** + * A collection of Spine Items + */ function Spine(){ this.spineItems = []; this.spineByHref = {}; @@ -22,6 +25,11 @@ function Spine(){ this.loaded = false; }; +/** + * Unpack items from a opf into spine items + * @param {Package} _package + * @param {method} resolver URL resolver + */ Spine.prototype.unpack = function(_package, resolver) { this.items = _package.spine; @@ -46,13 +54,8 @@ Spine.prototype.unpack = function(_package, resolver) { } } - // if(index > 0) { - item.prev = function(){ return this.get(index-1); }.bind(this); - // } - - // if(index+1 < this.items.length) { - item.next = function(){ return this.get(index+1); }.bind(this); - // } + item.prev = function(){ return this.get(index-1); }.bind(this); + item.next = function(){ return this.get(index+1); }.bind(this); spineItem = new Section(item, this.hooks); @@ -64,10 +67,15 @@ Spine.prototype.unpack = function(_package, resolver) { this.loaded = true; }; -// book.spine.get(); -// book.spine.get(1); -// book.spine.get("chap1.html"); -// book.spine.get("#id1234"); +/** + * Get an item from the spine + * @param {[string|int]} target + * @return {Section} section + * @example spine.get(); + * @example spine.get(1); + * @example spine.get("chap1.html"); + * @example spine.get("#id1234"); + */ Spine.prototype.get = function(target) { var index = 0; @@ -87,6 +95,11 @@ Spine.prototype.get = function(target) { return this.spineItems[index] || null; }; +/** + * Append a Section to the Spine + * @private + * @param {Section} section + */ Spine.prototype.append = function(section) { var index = this.spineItems.length; section.index = index; @@ -99,6 +112,11 @@ Spine.prototype.append = function(section) { return index; }; +/** + * Prepend a Section to the Spine + * @private + * @param {Section} section + */ Spine.prototype.prepend = function(section) { var index = this.spineItems.unshift(section); this.spineByHref[section.href] = 0; @@ -112,10 +130,15 @@ Spine.prototype.prepend = function(section) { return 0; }; -Spine.prototype.insert = function(section, index) { - -}; +// Spine.prototype.insert = function(section, index) { +// +// }; +/** + * Remove a Section from the Spine + * @private + * @param {Section} section + */ Spine.prototype.remove = function(section) { var index = this.spineItems.indexOf(section); @@ -127,6 +150,10 @@ Spine.prototype.remove = function(section) { } }; +/** + * Loop over the Sections in the Spine + * @return {method} forEach + */ Spine.prototype.each = function() { return this.spineItems.forEach.apply(this.spineItems, arguments); };