diff --git a/.eslintrc.js b/.eslintrc.js index f4bf68a..1bfd1ae 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -37,6 +37,7 @@ module.exports = { "error", { "vars": "all", "args": "none" } ], - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"] + "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], + "valid-jsdoc": ["warn"] } }; diff --git a/.gitignore b/.gitignore index e600f6d..689df6c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ books lib dist documentation/html +types/*.js \ No newline at end of file diff --git a/examples/spreads.html b/examples/spreads.html index efe696a..e086b33 100644 --- a/examples/spreads.html +++ b/examples/spreads.html @@ -148,6 +148,9 @@ }); + + + diff --git a/package-lock.json b/package-lock.json index a4bca4c..51a86ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "epubjs", - "version": "0.3.64", + "version": "0.3.66", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2519,6 +2519,15 @@ "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", "dev": true }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", + "dev": true, + "requires": { + "underscore-contrib": "~0.3.0" + } + }, "ccount": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.3.tgz", @@ -5114,6 +5123,12 @@ "domelementtype": "1" } }, + "dts-dom": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dts-dom/-/dts-dom-3.1.0.tgz", + "integrity": "sha512-DXi4f32CeSbgXZ/iPUHOCj+Sq7D5jVWPk7Sn/O+TDAn7/A0qntq9AcmQPuV8JwfGFAAfssegJhOVs6mV020AxQ==", + "dev": true + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -5749,7 +5764,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -9897,7 +9912,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -10110,6 +10125,15 @@ "esprima": "^4.0.0" } }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "dev": true, + "requires": { + "xmlcreate": "^1.0.1" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -10117,6 +10141,49 @@ "dev": true, "optional": true }, + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "dev": true, + "requires": { + "babylon": "7.0.0-beta.19", + "bluebird": "~3.5.0", + "catharsis": "~0.8.9", + "escape-string-regexp": "~1.0.5", + "js2xmlparser": "~3.0.0", + "klaw": "~2.0.0", + "marked": "~0.3.6", + "mkdirp": "~0.5.1", + "requizzle": "~0.2.1", + "strip-json-comments": "~2.0.1", + "taffydb": "2.6.2", + "underscore": "~1.8.3" + }, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", + "dev": true + }, + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + } + } + }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", @@ -10462,7 +10529,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "^1.0.0", @@ -11151,6 +11218,12 @@ "integrity": "sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw==", "dev": true }, + "marked": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "dev": true + }, "marks-pane": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.9.tgz", @@ -14092,6 +14165,23 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "dev": true, + "requires": { + "underscore": "~1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "resolve": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", @@ -15548,6 +15638,12 @@ } } }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "dev": true + }, "tapable": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", @@ -15892,6 +15988,15 @@ "integrity": "sha512-FHkoUZvG6Egrv9XZAyYGKEyb1JMsFphgPjoczkZC2y6W93U1jswcVURB8MUvtsahEPEVACyxD47JAL63vF4JsQ==", "dev": true }, + "tsd-jsdoc": { + "version": "2.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tsd-jsdoc/-/tsd-jsdoc-2.0.0-beta.6.tgz", + "integrity": "sha512-qEhk//Sn2iPiz+ZDWF+r9IiatxshVz/MyOMx9Ph1cFOr7jGj0F1xAaPWC6z+3Tg2bqCuh6h89FV2JsFax0znNw==", + "dev": true, + "requires": { + "dts-dom": "^3.1.0" + } + }, "tsscmp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", @@ -16068,6 +16173,23 @@ "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", "dev": true }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "dev": true, + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "underscore.string": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", @@ -19101,6 +19223,12 @@ "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", "dev": true }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", + "dev": true + }, "xmldom": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", diff --git a/package.json b/package.json index b1dea55..425f658 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Parse and Render Epubs", "main": "lib/index.js", "module": "src/index.js", + "types": "types/index.d.ts", "repository": "https://github.com/futurepress/epub.js", "directories": { "test": "test" @@ -49,6 +50,7 @@ "gulp-sourcemaps": "^2.6.4", "gulp-uglify": "^3.0.0", "gulp-util": "^3.0.8", + "jsdoc": "^3.5.5", "jshint": "^2.9.5", "karma": "^1.7.1", "karma-chrome-launcher": "^2.2.0", @@ -64,6 +66,7 @@ "portfinder": "^1.0.13", "raw-loader": "^0.5.1", "serve-static": "^1.13.2", + "tsd-jsdoc": "^2.0.0-beta.6", "uglify": "^0.1.5", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^1.1.2", diff --git a/src/contents.js b/src/contents.js index 6b35061..47e0f20 100644 --- a/src/contents.js +++ b/src/contents.js @@ -511,7 +511,11 @@ class Contents { this.observer.observe(this.document, config); } - imageLoadListeners(target) { + /** + * Test if images are loaded or add listener for when they load + * @private + */ + imageLoadListeners() { var images = this.document.querySelectorAll("img"); var img; for (var i = 0; i < images.length; i++) { @@ -528,7 +532,7 @@ class Contents { * Listen for font load and check for resize when loaded * @private */ - fontLoadListeners(target) { + fontLoadListeners() { if (!this.document || !this.document.fonts) { return; } diff --git a/src/locations.js b/src/locations.js index 3bb38a2..f632ce8 100644 --- a/src/locations.js +++ b/src/locations.js @@ -8,6 +8,7 @@ import EventEmitter from "event-emitter"; * Find Locations for a Book * @param {Spine} spine * @param {request} request + * @param {number} [pause=100] */ class Locations { constructor(spine, request, pause) { diff --git a/src/mapping.js b/src/mapping.js index 294e05e..bf7dd96 100644 --- a/src/mapping.js +++ b/src/mapping.js @@ -1,8 +1,13 @@ import EpubCFI from "./epubcfi"; +import { nodeBounds } from "./utils/core"; /** * Map text locations to CFI ranges * @class + * @param {Layout} layout Layout to apply + * @param {string} [direction="ltr"] Text direction + * @param {string} [axis="horizontal"] vertical or horizontal axis + * @param {boolean} [dev] toggle developer highlighting */ class Mapping { constructor(layout, direction, axis, dev) { @@ -24,6 +29,10 @@ class Mapping { /** * Find CFI pairs for a page + * @param {Contents} contents Contents from view + * @param {string} cfiBase string of the base for a cfi + * @param {number} start position to start at + * @param {number} end position to end at */ page(contents, cfiBase, start, end) { var root = contents && contents.document ? contents.document.body : false; @@ -54,6 +63,13 @@ class Mapping { return result; } + /** + * Walk a node, preforming a function on each node it finds + * @private + * @param {Node} root Node to walkToNode + * @param {function} func walk function + * @return {*} returns the result of the walk function + */ walk(root, func) { // IE11 has strange issue, if root is text node IE throws exception on // calling treeWalker.nextNode(), saying @@ -107,6 +123,14 @@ class Mapping { return columns; } + /** + * Find Start Range + * @private + * @param {Node} root root node + * @param {number} start position to start at + * @param {number} end position to end at + * @return {Range} + */ findStart(root, start, end){ var stack = [root]; var $el; @@ -123,7 +147,7 @@ class Mapping { var elRange; - elPos = this.getBounds(node); + elPos = nodeBounds(node); if (this.horizontal && this.direction === "ltr") { @@ -182,6 +206,14 @@ class Mapping { return this.findTextStartRange($prev, start, end); } + /** + * Find End Range + * @private + * @param {Node} root root node + * @param {number} start position to start at + * @param {number} end position to end at + * @return {Range} + */ findEnd(root, start, end){ var stack = [root]; var $el; @@ -198,7 +230,7 @@ class Mapping { var elPos; var elRange; - elPos = this.getBounds(node); + elPos = nodeBounds(node); if (this.horizontal && this.direction === "ltr") { @@ -257,7 +289,14 @@ class Mapping { return this.findTextEndRange($prev, start, end); } - + /** + * Find Text Start Range + * @private + * @param {Node} root root node + * @param {number} start position to start at + * @param {number} end position to end at + * @return {Range} + */ findTextStartRange(node, start, end){ var ranges = this.splitTextNodeIntoRanges(node); var range; @@ -299,6 +338,14 @@ class Mapping { return ranges[0]; } + /** + * Find Text End Range + * @private + * @param {Node} root root node + * @param {number} start position to start at + * @param {number} end position to end at + * @return {Range} + */ findTextEndRange(node, start, end){ var ranges = this.splitTextNodeIntoRanges(node); var prev; @@ -356,6 +403,13 @@ class Mapping { } + /** + * Split up a text node into ranges for each word + * @private + * @param {Node} root root node + * @param {string} [_splitter] what to split on + * @return {Range[]} + */ splitTextNodeIntoRanges(node, _splitter){ var ranges = []; var textContent = node.textContent || ""; @@ -402,7 +456,13 @@ class Mapping { } - + /** + * Turn a pair of ranges into a pair of CFIs + * @private + * @param {string} cfiBase base string for an EpubCFI + * @param {object} rangePair { start: Range, end: Range } + * @return {object} { start: "epubcfi(...)", end: "epubcfi(...)" } + */ rangePairToCfiPair(cfiBase, rangePair){ var startRange = rangePair.start; @@ -435,18 +495,11 @@ class Mapping { return map; } - getBounds(node) { - let elPos; - if(node.nodeType == Node.TEXT_NODE){ - let elRange = document.createRange(); - elRange.selectNodeContents(node); - elPos = elRange.getBoundingClientRect(); - } else { - elPos = node.getBoundingClientRect(); - } - return elPos; - } - + /** + * Set the axis for mapping + * @param {string} axis horizontal | vertical + * @return {boolean} is it horizontal? + */ axis(axis) { if (axis) { this.horizontal = (axis === "horizontal") ? true : false; diff --git a/src/navigation.js b/src/navigation.js index 2bbcd34..82f77c4 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -78,7 +78,7 @@ class Navigation { /** * Get an item from the navigation * @param {string} target - * @return {object} navItems + * @return {object} navItem */ get(target) { var index; @@ -100,7 +100,7 @@ class Navigation { * Get a landmark by type * List of types: https://idpf.github.io/epub-vocabs/structure/ * @param {string} type - * @return {object} landmarkItems + * @return {object} landmarkItem */ landmark(type) { var index; @@ -301,6 +301,7 @@ class Navigation { /** * Load Spine Items * @param {object} json the items to be loaded + * @return {Array} navItems */ load(json) { return json.map(item => { diff --git a/src/packaging.js b/src/packaging.js index c9e3bc1..5faeef1 100644 --- a/src/packaging.js +++ b/src/packaging.js @@ -75,7 +75,7 @@ class Packaging { /** * Parse Metadata * @private - * @param {document} xml + * @param {node} xml * @return {object} metadata */ parseMetadata(xml){ @@ -107,7 +107,7 @@ class Packaging { /** * Parse Manifest * @private - * @param {document} manifestXml + * @param {node} manifestXml * @return {object} manifest */ parseManifest(manifestXml){ @@ -140,7 +140,8 @@ class Packaging { /** * Parse Spine - * @param {document} spineXml + * @private + * @param {node} spineXml * @param {Packaging.manifest} manifest * @return {object} spine */ @@ -179,6 +180,8 @@ class Packaging { /** * Find TOC NAV * @private + * @param {element} manifestNode + * @return {string} */ findNavPath(manifestNode){ // Find item with property "nav" @@ -192,6 +195,9 @@ class Packaging { * Find TOC NCX * media-type="application/x-dtbncx+xml" href="toc.ncx" * @private + * @param {element} manifestNode + * @param {element} spineNode + * @return {string} */ findNcxPath(manifestNode, spineNode){ // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); @@ -216,7 +222,8 @@ class Packaging { * Find the Cover Path * * Fallback for Epub 2.0 - * @param {document} packageXml + * @private + * @param {node} packageXml * @return {string} href */ findCoverPath(packageXml){ @@ -245,7 +252,7 @@ class Packaging { /** * Get text of a namespaced element * @private - * @param {document} xml + * @param {node} xml * @param {string} tag * @return {string} text */ @@ -268,7 +275,7 @@ class Packaging { /** * Get text by property * @private - * @param {document} xml + * @param {node} xml * @param {string} property * @return {string} text */ diff --git a/src/pagelist.js b/src/pagelist.js index 55b4a81..69ef957 100644 --- a/src/pagelist.js +++ b/src/pagelist.js @@ -53,7 +53,7 @@ class PageList { /** * Parse a Nav PageList * @private - * @param {document} navHtml + * @param {node} navHtml * @return {PageList.item[]} list */ parseNav(navHtml){ @@ -77,7 +77,7 @@ class PageList { /** * Page List Item * @private - * @param {object} item + * @param {node} item * @return {object} pageListItem */ item(item){ @@ -128,7 +128,7 @@ class PageList { /** * Get a PageList result from a EpubCFI * @param {string} cfi EpubCFI String - * @return {string} page + * @return {number} page */ pageFromCfi(cfi){ var pg = -1; @@ -165,7 +165,7 @@ class PageList { /** * Get an EpubCFI from a Page List Item - * @param {string} pg + * @param {string | number} pg * @return {string} cfi */ cfiFromPage(pg){ @@ -188,7 +188,7 @@ class PageList { /** * Get a Page from Book percentage * @param {number} percent - * @return {string} page + * @return {number} page */ pageFromPercentage(percent){ var pg = Math.round(this.totalPages * percent); @@ -197,7 +197,7 @@ class PageList { /** * Returns a value between 0 - 1 corresponding to the location of a page - * @param {int} pg the page + * @param {number} pg the page * @return {number} percentage */ percentageFromPage(pg){ @@ -216,6 +216,9 @@ class PageList { return percentage; } + /** + * Destroy + */ destroy() { this.pages = undefined; this.locations = undefined; diff --git a/src/rendition.js b/src/rendition.js index 6be1333..63ffd4e 100644 --- a/src/rendition.js +++ b/src/rendition.js @@ -839,7 +839,7 @@ class Rendition { /** * Pass the events from a view's Contents * @private - * @param {View} view + * @param {Contents} view contents */ passEvents(contents){ var listenedEvents = Contents.listenedEvents; diff --git a/src/resources.js b/src/resources.js index 995cf76..3f25317 100644 --- a/src/resources.js +++ b/src/resources.js @@ -9,10 +9,10 @@ import path from "path-webpack"; * Handle Package Resources * @class * @param {Manifest} manifest - * @param {[object]} options - * @param {[string="base64"]} options.replacements - * @param {[Archive]} options.archive - * @param {[method]} options.resolver + * @param {object} [options] + * @param {string} [options.replacements="base64"] + * @param {Archive} [options.archive] + * @param {method} [options.resolver] */ class Resources { constructor(manifest, options) { @@ -93,6 +93,11 @@ class Resources { } + /** + * Create a url to a resource + * @param {string} url + * @return {Promise} Promise resolves with url string + */ createUrl (url) { var parsedUrl = new Url(url); var mimeType = mime.lookup(parsedUrl.filename); @@ -239,7 +244,7 @@ class Resources { /** * Resolve all resources URLs relative to an absolute URL * @param {string} absolute to be resolved to - * @param {[resolver]} resolver + * @param {resolver} [resolver] * @return {string[]} array with relative Urls */ relativeTo(absolute, resolver){ diff --git a/src/section.js b/src/section.js index d6cd22c..a461bad 100644 --- a/src/section.js +++ b/src/section.js @@ -40,7 +40,7 @@ class Section { /** * Load the section from its url - * @param {method} _request a request method to use for loading + * @param {method} [_request] a request method to use for loading * @return {document} a promise with the xml document */ load(_request){ @@ -81,7 +81,7 @@ class Section { /** * Render the contents of a section - * @param {method} _request a request method to use for loading + * @param {method} [_request] a request method to use for loading * @return {string} output a serialized XML Document */ render(_request){ @@ -176,15 +176,15 @@ class Section { /** * Reconciles the current chapters layout properies with * the global layout properities. - * @param {object} global The globa layout settings object, chapter properties string + * @param {object} globalLayout The global layout settings object, chapter properties string * @return {object} layoutProperties Object with layout properties */ - reconcileLayoutSettings(global){ + reconcileLayoutSettings(globalLayout){ //-- Get the global defaults var settings = { - layout : global.layout, - spread : global.spread, - orientation : global.orientation + layout : globalLayout.layout, + spread : globalLayout.spread, + orientation : globalLayout.orientation }; //-- Get the chapter's display type diff --git a/src/spine.js b/src/spine.js index f3d8931..519b67c 100644 --- a/src/spine.js +++ b/src/spine.js @@ -34,8 +34,9 @@ class Spine { /** * Unpack items from a opf into spine items - * @param {Package} _package + * @param {Packaging} _package * @param {method} resolver URL resolver + * @param {method} canonical Resolve canonical url */ unpack(_package, resolver, canonical) { @@ -112,7 +113,7 @@ class Spine { /** * Get an item from the spine - * @param {string|int} [target] + * @param {string|number} [target] * @return {Section} section * @example spine.get(); * @example spine.get(1); @@ -214,6 +215,10 @@ class Spine { return this.spineItems.forEach.apply(this.spineItems, arguments); } + /** + * Find the first Section in the Spine + * @return {Section} first section + */ first() { let index = 0; @@ -227,6 +232,10 @@ class Spine { } while (index < this.spineItems.length) ; } + /** + * Find the last Section in the Spine + * @return {Section} last section + */ last() { let index = this.spineItems.length-1; diff --git a/src/themes.js b/src/themes.js index d1f05b7..c2e72be 100644 --- a/src/themes.js +++ b/src/themes.js @@ -66,6 +66,10 @@ class Themes { } } + /** + * Register themes object + * @param {object} themes + */ registerThemes (themes) { for (var theme in themes) { if (themes.hasOwnProperty(theme)) { @@ -78,6 +82,11 @@ class Themes { } } + /** + * Register a url + * @param {string} name + * @param {string} input + */ registerUrl (name, input) { var url = new Url(input); this._themes[name] = { "url": url.toString() }; @@ -86,6 +95,11 @@ class Themes { } } + /** + * Register rule + * @param {string} name + * @param {object} rules + */ registerRules (name, rules) { this._themes[name] = { "rules": rules }; // TODO: serialize css rules @@ -94,6 +108,10 @@ class Themes { } } + /** + * Select a theme + * @param {string} name + */ select (name) { var prev = this._current; var contents; @@ -108,6 +126,10 @@ class Themes { }); } + /** + * Update a theme + * @param {string} name + */ update (name) { var contents = this.rendition.getContents(); contents.forEach( (content) => { @@ -115,6 +137,10 @@ class Themes { }); } + /** + * Inject all themes into contents + * @param {Contents} contents + */ inject (contents) { var links = []; var themes = this._themes; @@ -135,6 +161,11 @@ class Themes { } } + /** + * Add Theme to contents + * @param {string} name + * @param {Contents} contents + */ add (name, contents) { var theme = this._themes[name]; @@ -152,6 +183,12 @@ class Themes { } } + /** + * Add override + * @param {string} name + * @param {string} value + * @param {boolean} priority + */ override (name, value, priority) { var contents = this.rendition.getContents(); @@ -165,6 +202,10 @@ class Themes { }); } + /** + * Add all overrides + * @param {Content} content + */ overrides (contents) { var overrides = this._overrides; diff --git a/src/utils/core.js b/src/utils/core.js index 1be0fed..1e8af8a 100644 --- a/src/utils/core.js +++ b/src/utils/core.js @@ -48,6 +48,7 @@ export function documentHeight() { /** * Checks if a node is an element + * @param {object} obj * @returns {boolean} * @memberof Core */ @@ -56,6 +57,7 @@ export function isElement(obj) { } /** + * @param {any} n * @returns {boolean} * @memberof Core */ @@ -64,6 +66,7 @@ export function isNumber(n) { } /** + * @param {any} n * @returns {boolean} * @memberof Core */ @@ -83,6 +86,7 @@ export function isFloat(n) { /** * Get a prefixed css property + * @param {string} unprefixed * @returns {string} * @memberof Core */ @@ -296,6 +300,26 @@ export function borders(el) { } +/** + * Find the bounds of any node + * allows for getting bounds of text nodes by wrapping them in a range + * @param {node} node + * @returns {BoundingClientRect} + * @memberof Core + */ +export function nodeBounds(node) { + let elPos; + let doc = node.ownerDocument; + if(node.nodeType == Node.TEXT_NODE){ + let elRange = doc.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } + return elPos; +} + /** * Find the equivelent of getBoundingClientRect of a browser window * @returns {{ width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }} @@ -319,7 +343,9 @@ export function windowBounds() { /** * Gets the index of a node in its parent - * @private + * @param {Node} node + * @param {string} typeId + * @return {number} index * @memberof Core */ export function indexOfNode(node, typeId) { @@ -509,7 +535,7 @@ export function qsa(el, sel) { * querySelector by property * @param {element} el * @param {string} sel selector string - * @param {props[]} props + * @param {object[]} props * @returns {element[]} elements * @memberof Core */ @@ -558,6 +584,13 @@ export function sprint(root, func) { } } +/** + * Create a treeWalker + * @memberof Core + * @param {element} root element to start with + * @param {function} func function to run on each element + * @param {function | object} filter funtion or object to filter with + */ export function treeWalker(root, func, filter) { var treeWalker = document.createTreeWalker(root, filter, null, false); let node; diff --git a/types/annotations.d.ts b/types/annotations.d.ts new file mode 100644 index 0000000..718319d --- /dev/null +++ b/types/annotations.d.ts @@ -0,0 +1,53 @@ +import Rendition from "./rendition"; +import View from "./managers/view"; + +export default class Annotations { + constructor(rendition: Rendition); + + add(type: string, cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): Annotation; + + remove(cfiRange: string, type: string): void; + + highlight(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; + + underline(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; + + mark(cfiRange: string, data?: object, cb?: Function): void; + + each(): Array + + private _removeFromAnnotationBySectionIndex(sectionIndex: number, hash: string): void; + + private _annotationsAt(index: number): void; + + private inject(view: View): void; + + private clear(view: View): void; +} + +declare class Annotation { + constructor(options: { + type: string, + cfiRange: string, + data?: object, + sectionIndex?: number, + cb?: Function, + className?: string, + styles?: object + }); + + update(data: object): void; + + attach(view: View): any; + + detach(view: View): any; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; +} diff --git a/types/archive.d.ts b/types/archive.d.ts new file mode 100644 index 0000000..c705aa4 --- /dev/null +++ b/types/archive.d.ts @@ -0,0 +1,27 @@ +import JSZip = require('jszip'); + +export default class Archive { + constructor(); + + open(input: BinaryType, isBase64?: boolean): Promise; + + openUrl(zipUrl: string, isBase64?: boolean): Promise; + + request(url: string, type?: string): Promise; + + getBlob(url: string, mimeType?: string): Promise; + + getText(url: string): Promise; + + getBase64(url: string, mimeType?: string): Promise; + + createUrl(url: string, options: { base64: boolean }): Promise; + + revokeUrl(url: string): void; + + destroy(): void; + + private checkRequirements(): void; + + private handleResponse(response: any, type?: string): Blob | string | JSON | Document | XMLDocument; +} diff --git a/types/book.d.ts b/types/book.d.ts new file mode 100644 index 0000000..8d79262 --- /dev/null +++ b/types/book.d.ts @@ -0,0 +1,116 @@ +import { + PackagingManifestObject, + PackagingMetadataObject, + PackagingSpineItem, + PackagingObject +} from "./packaging"; +import Rendition, { RenditionOptions } from "./rendition"; +import Section, { SpineItem } from "./section"; +import Archive from "./archive"; +import Navigation from "./navigation"; +import PageList, {PageListItem} from "./pagelist"; +import Spine from "./spine"; +import Locations from "./locations"; +import Url from "./utils/url"; +import Path from "./utils/path"; +import Resources from "./resources"; +import Container from "./container"; +import Packaging from "./packaging"; +export interface BookOptions { + requestMethod?: (url: string, type: string, withCredentials: object, headers: object) => Promise; + requestCredentials?: object, + requestHeaders?: object, + encoding?: string, + replacements?: string, + canonical?: (path: string) => string, + openAs?: string +} + +export default class Book { + constructor(url: string, options?: BookOptions); + constructor(options?: BookOptions); + + settings: BookOptions; + opening: any; // should be core.defer + opened: Promise + isOpen: boolean; + loaded: { + metadata: Promise, + spine: Promise, + manifest: Promise, + cover: Promise, + navigation: Promise, + pageList: Promise, + resources: Promise, + } + ready: Promise; + request: Function; + spine: Spine; + locations: Locations; + navigation: Navigation; + pageList: PageList; + url: Url; + path: Path; + archived: boolean; + archive: Archive; + resources: Resources; + rendition: Rendition + container: Container; + packaging: Packaging; + + + canonical(path: string): string; + + coverUrl(): string; + + destroy(): void; + + determineType(input: string): string; + + getRange(cfiRange: string): Range; + + key(identifier: string): string; + + load(path: string): Promise; + + loadNavigation(opf: XMLDocument): Promise; + + open(input: string, what?: string): Promise; + open(input: ArrayBuffer, what?: string): Promise; + + openContainer(url: string): Promise; + + openEpub(data: BinaryType, encoding?: string): Promise; + + openManifest(url: string): Promise; + + openPackaging(url: string): Promise; + + renderTo(element: Element, options?: RenditionOptions): Rendition; + renderTo(element: string, options?: RenditionOptions): Rendition; + + private replacements(): Promise; + + resolve(path: string, absolute?: boolean): string; + + section(target: string): Section; + section(target: number): Section; + + setRequestCredentials(credentials: object): void; + + setRequestHeaders(headers: object): void; + + unarchive(input: BinaryType, encoding?: string): Promise; + + unpack(opf: XMLDocument): Promise; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; + +} diff --git a/types/container.d.ts b/types/container.d.ts new file mode 100644 index 0000000..139c941 --- /dev/null +++ b/types/container.d.ts @@ -0,0 +1,7 @@ +export default class Container { + constructor(containerDocument: Document); + + parse(containerDocument: Document): void; + + destroy(): void; +} diff --git a/types/contents.d.ts b/types/contents.d.ts new file mode 100644 index 0000000..c64f173 --- /dev/null +++ b/types/contents.d.ts @@ -0,0 +1,137 @@ +import EpubCFI from "./epubcfi"; + +export interface ViewportSettings { + width: string, + height: string, + scale: string, + scalable: string, + minimum: string, + maximum: string +} + +export default class Contents { + constructor(doc: Document, content: Element, cfiBase: string, sectionIndex: number); + + epubcfi: EpubCFI; + document: Document; + documentElement: Element; + content: Element; + window: Window; + sectionIndex: number; + cfiBase: string; + + static listenedEvents: string[]; + + addClass(className: string): void; + + addScript(src: string): Promise; + + addStylesheet(src: string): Promise; + + addStylesheetRules(rules: Array | object): Promise; + + cfiFromNode(node: Node, ignoreClass?: string): string; + + cfiFromRange(range: Range, ignoreClass?: string): string; + + columns(width: number, height: number, columnWidth: number, gap: number): void; + + contentHeight(h: number): number; + + contentWidth(w: number): number; + + css(property: string, value: string, priority?: boolean): string; + + destroy(): void; + + direction(dir: string): void; + + fit(width: number, height: number): void; + + height(h: number): number; + + locationOf(target: string | EpubCFI, ignoreClass?: string): Promise<{ top: number, left: number }>; + + map(layout: any): any; + + mapPage(cfiBase: string, layout: object, start: number, end: number, dev: boolean): any; + + overflow(overflow: string): string; + + overflowX(overflow: string): string; + + overflowY(overflow: string): string; + + range(cfi: string, ignoreClass?: string): Range; + + removeClass(className: any): void; + + root(): Element; + + scaler(scale: number, offsetX: number, offsetY: number): void; + + scrollHeight(): number; + + scrollWidth(): number; + + size(width: number, height: number): void; + + textHeight(): number; + + textWidth(): number; + + viewport(options: ViewportSettings): ViewportSettings; + + width(w: number): number; + + writingMode(mode: string): string; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; + + private addEventListeners(): void; + + private addSelectionListeners(): void; + + private epubReadingSystem(name: string, version: string): object; + + private expand(): void; + + private fontLoadListeners(): void; + + private imageLoadListeners(): void; + + private layoutStyle(style: string): string; + + private linksHandler(): void; + + private listeners(): void; + + private mediaQueryListeners(): void; + + private onSelectionChange(e: Event): void; + + private removeEventListeners(): void; + + private removeListeners(): void; + + private removeSelectionListeners(): void; + + private resizeCheck(): void; + + private resizeListeners(): void; + + private resizeObservers(): void; + + private transitionListeners(): void; + + private triggerEvent(e: Event): void; + + private triggerSelectedEvent(selection: Selection): void; +} diff --git a/types/core.d.ts b/types/core.d.ts new file mode 100644 index 0000000..1858cd4 --- /dev/null +++ b/types/core.d.ts @@ -0,0 +1,83 @@ +export module Core { + + export function uuid(): string; + + export function documentHeight(): number; + + export function isElement(obj: object): boolean; + + export function isNumber(n: any): boolean; + + export function isFloat(n: any): boolean; + + export function prefixed(unprefixed: string): string; + + export function defaults(obj: object): object; + + export function extend(target: object): object; + + export function insert(item: any, array: Array, compareFunction: Function): number; + + export function locationOf(item: any, array: Array, compareFunction: Function, _start: Function, _end: Function): number; + + export function indexOfSorted(item: any, array: Array, compareFunction: Function, _start: Function, _end: Function): number; + + export function bounds(el: Element): { width: Number, height: Number}; + + export function borders(el: Element): { width: Number, height: Number}; + + export function nodeBounds(node: Node): object; + + export function windowBounds(): { width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }; + + export function indexOfNode(node: Node, typeId: string): number; + + export function indexOfTextNode(textNode: Node): number; + + export function indexOfElementNode(elementNode: Element): number; + + export function isXml(ext: string): boolean; + + export function createBlob(content: any, mime: string): Blob; + + export function createBlobUrl(content: any, mime: string): string; + + export function revokeBlobUrl(url: string): void; + + export function createBase64Url(content: any, mime: string): string + + export function type(obj: object): string; + + export function parse(markup: string, mime: string, forceXMLDom: boolean): Document; + + export function qs(el: Element, sel: string): Element; + + export function qsa(el: Element, sel: string): ArrayLike; + + export function qsp(el: Element, sel: string, props: Array): ArrayLike; + + export function sprint(root: Node, func: Function): void; + + export function treeWalker(root: Node, func: Function, filter: object | Function): void; + + export function walk(node: Node, callback: Function): void; + + export function blob2base64(blob: Blob): string; + + export function defer(): Promise; + + export function querySelectorByType(html: Element, element: string, type: string): Array; + + export function findChildren(el: Element): Array; + + export function parents(node: Element): Array; + + export function filterChildren(el: Element, nodeName: string, single: boolean): Array; + + export function getParentByTagName(node: Element, tagname: string): Array; + + export class RangeObject extends Range { + + } + +} diff --git a/types/epub.d.ts b/types/epub.d.ts new file mode 100644 index 0000000..18064fa --- /dev/null +++ b/types/epub.d.ts @@ -0,0 +1,6 @@ +import Book, { BookOptions } from "./book"; + +export default Epub; + +declare function Epub(url: string, options?: BookOptions) : Book; +declare function Epub(options?: BookOptions) : Book; diff --git a/types/epubcfi.d.ts b/types/epubcfi.d.ts new file mode 100644 index 0000000..2875ab1 --- /dev/null +++ b/types/epubcfi.d.ts @@ -0,0 +1,85 @@ +interface EpubCFISegment { + steps: Array, + terminal: { + offset: number, + assertion: string + } +} + +interface EpubCFIStep { + id: string, + tagName: string, + type: number, + index: number +} + +export default class EpubCFI { + constructor(cfiFrom?: string | Range | Node, base?: string | object, ignoreClass?: string); + + isCfiString(str: string): boolean; + + fromNode(anchor: Node, base: string | object, ignoreClass?: string): EpubCFI; + + fromRange(range: Range, base: string | object, ignoreClass?: string): EpubCFI; + + parse(cfiStr: string): EpubCFI; + + collapse(toStart?: boolean): void; + + compare(cfiOne: string | EpubCFI, cfiTwo: string | EpubCFI): number; + + equalStep(stepA: object, stepB: object): boolean; + + filter(anchor: Element, ignoreClass?: string): Element | false; + + toRange(_doc?: Document, ignoreClass?: string): Range; + + toString(): string; + + private filteredStep(node: Node, ignoreClass?: string): any; + + private findNode(steps: Array, _doc?: Document, ignoreClass?: string): Node; + + private fixMiss(steps: Array, offset: number, _doc?: Document, ignoreClass?: string): any; + + private checkType(cfi: string | Range | Node): string | false; + + private generateChapterComponent(_spineNodeIndex: number, _pos: number, id: string): string; + + private getChapterComponent(cfiStr: string): string; + + private getCharecterOffsetComponent(cfiStr: string): string; + + private getPathComponent(cfiStr: string): string; + + private getRange(cfiStr: string): string; + + private joinSteps(steps: Array): Array; + + private normalizedMap(children: Array, nodeType: number, ignoreClass?: string): object; + + private parseComponent(componentStr: string): object; + + private parseStep(stepStr: string): object; + + private parseTerminal(termialStr: string): object; + + private patchOffset(anchor: Node, offset: number, ignoreClass?: string): number; + + private pathTo(node: Node, offset: number, ignoreClass?: string): EpubCFISegment; + + private position(anchor: Node): number; + + private segmentString(segment: EpubCFISegment): string; + + private step(node: Node): EpubCFIStep; + + private stepsToQuerySelector(steps: Array): string; + + private stepsToXpath(steps: Array): string; + + private textNodes(container: Node, ignoreClass?: string): Array; + + private walkToNode(steps: Array, _doc?: Document, ignoreClass?: string): Node; + +} diff --git a/types/epubjs-tests.ts b/types/epubjs-tests.ts new file mode 100644 index 0000000..e64bb87 --- /dev/null +++ b/types/epubjs-tests.ts @@ -0,0 +1,9 @@ +import ePub, { Book } from '../'; + +function testEpub() { + const epub = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub"); + + const book = new Book("https://s3.amazonaws.com/moby-dick/moby-dick.epub", {}); +} + +testEpub(); diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..6b0a7c6 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,19 @@ +// Type definitions for epubjs 0.3 +// Project: https://github.com/futurepress/epub.js#readme +// Definitions by: Fred Chasen +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +import Epub from "./epub"; + +export as namespace ePub; + +export default Epub; + +export { default as Book } from './book'; +export { default as EpubCFI } from './epubcfi'; +export { default as Rendition } from './rendition'; +export { default as Contents } from './contents'; +export { default as Layout } from './layout'; + +declare namespace ePub { + +} diff --git a/types/layout.d.ts b/types/layout.d.ts new file mode 100644 index 0000000..04d373d --- /dev/null +++ b/types/layout.d.ts @@ -0,0 +1,48 @@ +import Contents from "./contents"; + +interface LayoutSettings { + layout: string, + spread: string, + minSpreadWidth: number, + evenSpreads: boolean +} + +export default class Layout { + constructor(settings: LayoutSettings); + + settings: LayoutSettings; + name: string; + props: { + name: string, + spread: string, + flow: string, + width: number, + height: number, + spreadWidth: number, + delta: number, + columnWidth: number, + gap: number, + divisor: number + }; + + flow(flow: string): string; + + spread(spread: string, min: number): boolean; + + calculate(_width:number, _height:number, _gap?:number): void; + + format(contents: Contents): void | Promise; + + count(totalLength: number, pageLength: number): {spreads: Number, pages: Number}; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; + + private update(props: object): void; +} diff --git a/types/locations.d.ts b/types/locations.d.ts new file mode 100644 index 0000000..ef8b44e --- /dev/null +++ b/types/locations.d.ts @@ -0,0 +1,41 @@ +import Spine from "./spine"; +import Section from "./section"; +import EpubCFI from "./epubcfi"; + +export default class Locations { + constructor(spine: Spine, request?: Function, pause?: number); + + generate(chars: number): object; + + process(section: Section): Promise>; + + locationFromCfi(cfi: string | EpubCFI): Location; + + percentageFromCfi(cfi: string | EpubCFI): number; + + percentageFromLocation(loc: number): number; + + cfiFromLocation(loc: number): string; + + cfiFromPercentage(percentage: number): string; + + load(locations: JSON): Array; + + save(): JSON; + + currentLocation(): Location; + currentLocation(curr: string | number): void; + + length(): number; + + destroy(): void; + + private createRange(): { + startContainer: Element, + startOffset: number, + endContainer: Element, + endOffset: number + }; + + private parse(contents: Node, cfiBase: string, chars: number) : Array; +} diff --git a/types/managers/manager.d.ts b/types/managers/manager.d.ts new file mode 100644 index 0000000..5486fb1 --- /dev/null +++ b/types/managers/manager.d.ts @@ -0,0 +1,90 @@ +import Section from "../section"; +import Layout from "../layout"; +import Contents from "../contents"; +import View, { ViewSettings } from "./view"; +import { EpubCFIPair } from "../mapping"; + +export interface ViewLocation { + index: number, + href: string, + pages: number[], + totalPages: number, + mapping: EpubCFIPair +} + +export interface ManagerOptions extends ViewSettings { + infinite?: boolean, + overflow?: string, + [key: string]: any +} + +export default class Manager { + constructor(options: object); + + render(element: Element, size?: { width: Number, height: Number }): void; + + resize(width: Number, height: Number): void; + + onOrientationChange(e: Event): void; + + private createView(section: Section): View; + + display(section: Section, target: string | number): Promise; + + private afterDisplayed(view: View): void; + + private afterResized(view: View): void; + + private moveTo(offset: {top: Number, left: Number}): void; + + private append(section: Section): Promise; + + private prepend(section: Section): Promise; + + next(): Promise; + + prev(): Promise; + + current(): View; + + clear(): void; + + currentLocation(): ViewLocation[]; + + visible(): View[]; + + private scrollBy(x: number, y: number, silent: boolean): void; + + private scrollTo(x: number, y: number, silent: boolean): void; + + private onScroll(): void; + + bounds(): object; + + applyLayout(layout: Layout): void; + + updateLayout(): void; + + setLayout(layout: Layout): void; + + updateAxis(axis: string, forceUpdate: boolean): void; + + updateFlow(flow: string): void; + + getContents(): Contents[]; + + direction(dir: string): void; + + isRendered(): boolean; + + destroy(): void; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; +} diff --git a/types/managers/view.d.ts b/types/managers/view.d.ts new file mode 100644 index 0000000..559e954 --- /dev/null +++ b/types/managers/view.d.ts @@ -0,0 +1,79 @@ +import Section from "../section"; +import Contents from "../contents"; +import Layout from "../layout"; + +export interface ViewSettings { + ignoreClass?: string, + axis?: string, + flow?: string, + layout?: Layout, + method?: string, + width?: number, + height?: number, + forceEvenPages?: boolean +} + +export default class View { + constructor(section: Section, options: ViewSettings); + + create(): any; + + render(request?: Function, show?: boolean): Promise; + + reset(): void; + + size(_width: Number, _height: Number): void; + + load(content: Contents): Promise; + + setLayout(layout: Layout): void; + + setAxis(axis: string): void; + + display(request?: Function): Promise; + + show(): void; + + hide(): void; + + offset(): { top: Number, left: Number }; + + width(): Number; + + height(): Number; + + position(): object; + + locationOf(target: string): { top: Number, left: Number }; + + onDisplayed(view: View): void; + + onResize(view: View): void; + + bounds(force?: boolean): object; + + highlight(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; + + underline(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; + + mark(cfiRange: string, data?: object, cb?: Function): void; + + unhighlight(cfiRange: string): void; + + ununderline(cfiRange: string): void; + + unmark(cfiRange: string): void; + + destroy(): void; + + private onLoad(event: Event, promise: Promise): void; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; +} diff --git a/types/mapping.d.ts b/types/mapping.d.ts new file mode 100644 index 0000000..00f6bb4 --- /dev/null +++ b/types/mapping.d.ts @@ -0,0 +1,34 @@ +import Layout from "./layout"; +import Contents from "./contents"; + +export interface EpubCFIPair { + start: string, + end: string +} + +export interface RangePair { + start: Range, + end: Range +} + +export default class Mapping { + constructor(layout: Layout, direction?: string, axis?: string, dev?: boolean); + + page(contents: Contents, cfiBase: string, start: number, end: number): EpubCFIPair; + + axis(axis: string): boolean; + + private walk(root: Node, func: Function); + + private findStart(root: Node, start: number, end: number): Range; + + private findEnd(root: Node, start: number, end: number): Range; + + private findTextStartRange(node: Node, start: number, end: number): Range; + + private findTextEndRange(node: Node, start: number, end: number): Range; + + private splitTextNodeIntoRanges(node: Node, _splitter?: string): Array; + + private rangePairToCfiPair(cfiBase: string, rangePair: RangePair): EpubCFIPair; +} diff --git a/types/navigation.d.ts b/types/navigation.d.ts new file mode 100644 index 0000000..477487d --- /dev/null +++ b/types/navigation.d.ts @@ -0,0 +1,41 @@ +export interface NavItem { + id?: string, + href?: string, + label?: string, + subitems?: Array, + parent?: NavItem +} + +export interface LandmarkItem { + href?: string, + label?: string, + type?: string +} + +export default class Navigation { + constructor(xml: XMLDocument); + + parse(xml: XMLDocument): void; + + get(target: string) : NavItem; + + landmark(type: string) : LandmarkItem; + + load(json: JSON): Array; + + forEach(fn: (item: NavItem) => {}): any; + + private unpack(toc: Array): void; + + private parseNav(navHtml: XMLDocument): Array; + + private navItem(item: Element): NavItem; + + private parseLandmarks(navHtml: XMLDocument): Array; + + private landmarkItem(item: Element): LandmarkItem; + + private parseNcx(navHtml: XMLDocument): Array; + + private ncxItem(item: Element): NavItem; +} diff --git a/types/packaging.d.ts b/types/packaging.d.ts new file mode 100644 index 0000000..252698b --- /dev/null +++ b/types/packaging.d.ts @@ -0,0 +1,69 @@ +import { SpineItem } from "./section"; + +export interface PackagingObject { + metadata: PackagingMetadataObject, + spine: Array, + manifest: PackagingManifestObject, + navPath: string, + ncxPath: string, + coverPath: string, + spineNodeIndex: number +} + +export interface PackagingMetadataObject { + title: string, + creator: string, + description: string, + pubdate: string, + publisher: string, + identifier: string, + language: string, + rights: string, + modified_date: string, + layout: string, + orientation: string, + flow: string, + viewport: string +} + +export interface PackagingSpineItem { + idref: string, + properties: Array, + index: number +} + +export interface PackagingManifestItem { + href: string, + type: string, + properties: Array +} + +export interface PackagingManifestObject { + [key: string]: PackagingManifestItem +} + +export default class Packaging { + constructor(packageDocument: XMLDocument); + + parse(packageDocument: XMLDocument): PackagingObject; + + load(json: JSON): PackagingObject; + + destroy(): void; + + private parseMetadata(xml: Node): PackagingMetadataObject; + + private parseManifest(xml: Node): PackagingManifestObject; + + private parseSpine(xml: Node, manifest: PackagingManifestObject): Array; + + private findNavPath(manifestNode: Node): string | false; + + private findNcxPath(manifestNode: Node, spineNode: Node): string | false; + + private findCoverPath(packageXml: Node): string; + + private getElementText(xml: Node, tag: string): string + + private getPropertyText(xml: Node, property: string): string +} diff --git a/types/pagelist.d.ts b/types/pagelist.d.ts new file mode 100644 index 0000000..5104098 --- /dev/null +++ b/types/pagelist.d.ts @@ -0,0 +1,29 @@ +export interface PageListItem { + href: string, + page: string, + cfi?: string, + packageUrl?: string +} + +export default class Pagelist { + constructor(xml: XMLDocument); + + parse(xml: XMLDocument): Array; + + pageFromCfi(cfi: string): number; + + cfiFromPage(pg: string | number): string; + + pageFromPercentage(percent: number): number; + + percentageFromPage(pg: number): number; + + destroy(): void; + + private parseNav(navHtml: Node): Array; + + private item(item: Node): PageListItem; + + private process(pageList: Array): void; + +} diff --git a/types/rendition.d.ts b/types/rendition.d.ts new file mode 100644 index 0000000..cefdaf4 --- /dev/null +++ b/types/rendition.d.ts @@ -0,0 +1,145 @@ +import Book from "./book"; +import Contents from "./contents"; +import Section from "./section"; +import View from "./managers/view"; +import Hook from "./utils/hook"; +import Themes from "./themes"; +import EpubCFI from "./epubcfi"; +import Annotations from "./annotations"; +import Queue from "./utils/queue"; + +export interface RenditionOptions { + width?: number, + height?: number, + ignoreClass?: string, + manager?: string | Function | object, + view?: string | Function | object, + layout?: string, + spread?: string, + minSpreadWidth?: number, + stylesheet?: string, + script?: string +} + +export interface DisplayedLocation { + index: number, + href: string, + cfi: string, + displayed: { + page: number, + total: number + } +} + +export interface Location { + start: DisplayedLocation, + end: DisplayedLocation, + atStart: boolean, + atEnd: boolean +} + +export default class Rendition { + constructor(book: Book, options: RenditionOptions); + + settings: RenditionOptions; + book: Book; + hooks: { + display: Hook, + serialize: Hook, + content: Hook, + unloaded: Hook, + layout: Hook, + render: Hook, + show: Hook + } + themes: Themes; + annotations: Annotations; + epubcfi: EpubCFI; + q: Queue; + location: Location; + started: Promise; + + adjustImages(contents: Contents): Promise; + + attachTo(element: Element): Promise; + + clear(): void; + + currentLocation(): DisplayedLocation; + currentLocation(): Promise; + + destroy(): void; + + determineLayoutProperties(metadata: object): object; + + direction(dir: string): void; + + display(target?: string): Promise; + display(target?: number): Promise; + + flow(flow: string): void; + + getContents(): Contents; + + getRange(cfi: string, ignoreClass?: string): Range; + + handleLinks(contents: Contents): void; + + injectIdentifier(doc: Document, section: Section): void; + + injectScript(doc: Document, section: Section): void; + + injectStylesheet(doc: Document, section: Section): void; + + layout(settings: any): any; + + located(location: Location): DisplayedLocation; + + moveTo(offset: number): void; + + next(): Promise; + + onOrientationChange(orientation: string): void; + + passEvents(contents: Contents): void; + + prev(): Promise; + + reportLocation(): Promise; + + requireManager(manager: string | Function | object): any; + + requireView(view: string | Function | object): any; + + resize(width: number, height: number): void; + + setManager(manager: Function): void; + + spread(spread: string, min?: number): void; + + start(): void; + + views(): Array; + + // Event emitters + emit(type: any, ...args: any[]): void; + + off(type: any, listener: any): any; + + on(type: any, listener: any): any; + + once(type: any, listener: any, ...args: any[]): any; + + private triggerMarkEvent(cfiRange: string, data: object, contents: Contents): void; + + private triggerSelectedEvent(cfirange: string, contents: Contents): void; + + private triggerViewEvent(e: Event, contents: Contents): void; + + private onResized(size: { width: number, height: number }): void; + + private afterDisplayed(view: any): void; + + private afterRemoved(view: any): void; + +} diff --git a/types/resources.d.ts b/types/resources.d.ts new file mode 100644 index 0000000..ba2a679 --- /dev/null +++ b/types/resources.d.ts @@ -0,0 +1,31 @@ +import { PackagingManifestObject } from "./packaging"; +import Archive from "./archive"; + +export default class Resources { + constructor(manifest: PackagingManifestObject, options: { + replacements?: string, + archive?: Archive, + resolver?: Function, + request?: Function + }); + + createUrl(url: string): Promise; + + replacements(): Promise>; + + relativeTo(absolute: boolean, resolver?: Function): Array; + + get(path: string): string; + + substitute(content: string, url?: string): string; + + destroy(): void; + + private split(): void; + + private splitUrls(): void; + + private replaceCss(archive: Archive, resolver?: Function): Promise>; + + private createCssFile(href: string): Promise; +} diff --git a/types/section.d.ts b/types/section.d.ts new file mode 100644 index 0000000..06b34ee --- /dev/null +++ b/types/section.d.ts @@ -0,0 +1,64 @@ +import { HooksObject } from "./utils/hook"; + +export interface GlobalLayout { + layout: string, + spread: string, + orientation: string +} + +export interface LayoutSettings { + layout: string, + spread: string, + orientation: string +} + +export interface SpineItem { + index: number, + cfiBase: string, + href?: string, + url?: string, + canonical?: string, + properties?: Array, + linear?: string, + next: () => SpineItem, + prev: () => SpineItem, +} + +export default class Section { + constructor(item: SpineItem, hooks: HooksObject); + + idref: string; + linear: string; + properties: Array; + index: number; + href: string; + url: string; + canonical: string; + next: () => SpineItem; + prev: () => SpineItem; + cfiBase: string; + + document: Document; + contents: Element; + output: string; + + hooks: HooksObject; + + load(_request?: Function): Document; + + render(_request?: Function): string; + + find(_query: string): Array; + + reconcileLayoutSettings(globalLayout: GlobalLayout): LayoutSettings; + + cfiFromRange(_range: Range): string; + + cfiFromElement(el: Element): string; + + unload(): void; + + destroy(): void; + + private base(): void; +} diff --git a/types/spine.d.ts b/types/spine.d.ts new file mode 100644 index 0000000..6cd59ce --- /dev/null +++ b/types/spine.d.ts @@ -0,0 +1,30 @@ +import Packaging from "./packaging"; +import Section from "./section"; +import Hook from "./utils/hook"; + +export default class Spine { + constructor(); + + hooks: { + serialize: Hook, + content: Hook + }; + + unpack(_package: Packaging, resolver: Function, canonical: Function): void; + + get(target?: string | number): Section; + + each(...args: any[]): any; + + first(): Section; + + last(): Section; + + destroy(): void; + + private append(section: Section): number; + + private prepend(section: Section): number; + + private remove(section: Section): number; +} diff --git a/types/themes.d.ts b/types/themes.d.ts new file mode 100644 index 0000000..3068ebd --- /dev/null +++ b/types/themes.d.ts @@ -0,0 +1,38 @@ +import Rendition from "./rendition"; +import Contents from "./contents"; + +export default class Themes { + constructor(rendition: Rendition); + + register( themeObject: object ): void; + + register( theme: string, url: string ): void; + + register( theme: string, themeObject: object ): void; + + default( theme: object | string ): void; + + registerThemes( themes: object ): void; + + registerUrl( name: string, input: string ): void; + + registerRules( name: string, rules: object ): void; + + select( name: string ): void; + + update( name: string ): void; + + inject( content: Contents ): void; + + add( name: string, contents: Contents ): void; + + override(name: string, value: string, priority: boolean): void; + + overrides(contents: Contents): void; + + fontSize(size: string): void; + + font(f: string): void; + + destroy(): void; +} diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..546c5a3 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "epubjs-tests.ts" + ] +} diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 0000000..e26ec8f --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,4 @@ +{ + "extends": "dtslint/dt.json", + "rules": {} +} diff --git a/types/utils/constants.d.ts b/types/utils/constants.d.ts new file mode 100644 index 0000000..1c5c5c5 --- /dev/null +++ b/types/utils/constants.d.ts @@ -0,0 +1,9 @@ +export const EPUBJS_VERSION: string; + +export const DOM_EVENTS: Array; + +export const EVENTS: { + [key: string]: { + [key: string]: string + } +} diff --git a/types/utils/core.d.ts b/types/utils/core.d.ts new file mode 100644 index 0000000..6469a66 --- /dev/null +++ b/types/utils/core.d.ts @@ -0,0 +1,79 @@ +export function uuid(): string; + +export function documentHeight(): number; + +export function isElement(obj: object): boolean; + +export function isNumber(n: any): boolean; + +export function isFloat(n: any): boolean; + +export function prefixed(unprefixed: string): string; + +export function defaults(obj: object): object; + +export function extend(target: object): object; + +export function insert(item: any, array: Array, compareFunction: Function): number; + +export function locationOf(item: any, array: Array, compareFunction: Function, _start: Function, _end: Function): number; + +export function indexOfSorted(item: any, array: Array, compareFunction: Function, _start: Function, _end: Function): number; + +export function bounds(el: Element): { width: Number, height: Number}; + +export function borders(el: Element): { width: Number, height: Number}; + +export function nodeBounds(node: Node): object; + +export function windowBounds(): { width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }; + +export function indexOfNode(node: Node, typeId: string): number; + +export function indexOfTextNode(textNode: Node): number; + +export function indexOfElementNode(elementNode: Element): number; + +export function isXml(ext: string): boolean; + +export function createBlob(content: any, mime: string): Blob; + +export function createBlobUrl(content: any, mime: string): string; + +export function revokeBlobUrl(url: string): void; + +export function createBase64Url(content: any, mime: string): string + +export function type(obj: object): string; + +export function parse(markup: string, mime: string, forceXMLDom: boolean): Document; + +export function qs(el: Element, sel: string): Element; + +export function qsa(el: Element, sel: string): ArrayLike; + +export function qsp(el: Element, sel: string, props: Array): ArrayLike; + +export function sprint(root: Node, func: Function): void; + +export function treeWalker(root: Node, func: Function, filter: object | Function): void; + +export function walk(node: Node, callback: Function): void; + +export function blob2base64(blob: Blob): string; + +export function defer(): Promise; + +export function querySelectorByType(html: Element, element: string, type: string): Array; + +export function findChildren(el: Element): Array; + +export function parents(node: Element): Array; + +export function filterChildren(el: Element, nodeName: string, single: boolean): Array; + +export function getParentByTagName(node: Element, tagname: string): Array; + +export class RangeObject extends Range { + +} diff --git a/types/utils/hook.d.ts b/types/utils/hook.d.ts new file mode 100644 index 0000000..05834ce --- /dev/null +++ b/types/utils/hook.d.ts @@ -0,0 +1,16 @@ +interface HooksObject { + [key: string]: Hook +} + +export default class Hook { + constructor(context: any); + + register(func: Function): void; + register(arr: Array): void; + + trigger(...args: any[]): Promise; + + list(): Array; + + clear(): void; +} diff --git a/types/utils/path.d.ts b/types/utils/path.d.ts new file mode 100644 index 0000000..b91e88b --- /dev/null +++ b/types/utils/path.d.ts @@ -0,0 +1,17 @@ +export default class Path { + constructor(pathString: string); + + parse(what: string): object; + + isAbsolute(what: string): boolean; + + isDirectory(what: string): boolean; + + resolve(what: string): string; + + relative(what: string): string; + + splitPath(filename: string): string; + + toString(): string; +} diff --git a/types/utils/queue.d.ts b/types/utils/queue.d.ts new file mode 100644 index 0000000..4813ef6 --- /dev/null +++ b/types/utils/queue.d.ts @@ -0,0 +1,34 @@ +import { defer } from "./core"; + +export interface QueuedTask { + task: any | Task, + args: any[], + deferred: any, // should be defer, but not working + promise: Promise +} + +export default class Queue { + constructor(context: any); + + enqueue(func: Promise | Function, ...args: any[]): Promise; + + dequeue(): Promise; + + dump(): void; + + run(): Promise; + + flush(): Promise; + + clear(): void; + + length(): number; + + pause(): void; + + stop(): void; +} + +declare class Task { + constructor(task: any, args: any[], context: any); +} diff --git a/types/utils/replacements.d.ts b/types/utils/replacements.d.ts new file mode 100644 index 0000000..9728ee4 --- /dev/null +++ b/types/utils/replacements.d.ts @@ -0,0 +1,12 @@ +import Section from "../section"; +import Contents from "../contents"; + +export function replaceBase(doc: Document, section: Section): void; + +export function replaceCanonical(doc: Document, section: Section): void; + +export function replaceMeta(doc: Document, section: Section): void; + +export function replaceLinks(contents: Contents, fn: Function): void; + +export function substitute(contents: Contents, urls: string[], replacements: string[]): void; diff --git a/types/utils/request.d.ts b/types/utils/request.d.ts new file mode 100644 index 0000000..a18f58c --- /dev/null +++ b/types/utils/request.d.ts @@ -0,0 +1 @@ +export default function request(url: string, type: string, withCredentials: boolean, headers: object): Promise; diff --git a/types/utils/url.d.ts b/types/utils/url.d.ts new file mode 100644 index 0000000..bf30dfb --- /dev/null +++ b/types/utils/url.d.ts @@ -0,0 +1,13 @@ +import Path from "./path"; + +export default class Url { + constructor(urlString: string, baseString: string); + + path(): Path; + + resolve(what: string): string; + + relative(what: string): string; + + toString(): string; +}