1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-02 14:49:16 +02:00
This commit is contained in:
Valdrin Trena 2024-06-08 20:14:31 +02:00
parent f09089cf77
commit 7c7c554ee7
84 changed files with 13879 additions and 14510 deletions

View file

@ -1,11 +1,14 @@
{ {
"presets": [ "presets": [
["@babel/preset-env", { [
"@babel/preset-env",
{
"targets": "last 2 Chrome versions, last 2 Safari versions, last 2 ChromeAndroid versions, last 2 iOS versions, last 2 Firefox versions, last 2 Edge versions", "targets": "last 2 Chrome versions, last 2 Safari versions, last 2 ChromeAndroid versions, last 2 iOS versions, last 2 Firefox versions, last 2 Edge versions",
"corejs": 3, "corejs": 3,
"useBuiltIns": "usage", "useBuiltIns": "usage",
"bugfixes": true, "bugfixes": true,
"modules": "auto" "modules": "auto"
}] }
], ]
]
} }

View file

@ -1,43 +1,25 @@
module.exports = { module.exports = {
"env": { env: {
"browser": true, browser: true,
"commonjs": true, commonjs: true,
"es6": true, es6: true,
"node": true node: true,
}, },
"globals": { globals: {
"ePub": true, ePub: true,
"JSZip": true JSZip: true,
}, },
"extends": "eslint:recommended", extends: "eslint:recommended",
"parserOptions": { parserOptions: {
"sourceType": "module" sourceType: "module",
}, },
"rules": { rules: {
"indent": [ "linebreak-style": ["error", "unix"],
"error", quotes: ["warn", "double"],
"tab", semi: ["error", "always"],
{ "VariableDeclarator": { "var": 2, "let": 2, "const": 3 } } "no-console": ["warn"],
], "no-unused-vars": ["error", { vars: "all", args: "none" }],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"warn",
"double"
],
"semi": [
"error",
"always"
],
"no-unused-vars" : ["warn"],
"no-console" : ["warn"],
"no-unused-vars": [
"error",
{ "vars": "all", "args": "none" }
],
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"], "no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"valid-jsdoc": ["warn"] "no-prototype-builtins": "off",
} },
}; };

View file

@ -2,10 +2,8 @@
"browser": true, "browser": true,
"devel": true, "devel": true,
"worker": true, "worker": true,
"trailing": true, "trailing": true,
"strict": false, "strict": false,
"boss": true, "boss": true,
"funcscope": true, "funcscope": true,
"globalstrict": true, "globalstrict": true,
@ -14,10 +12,9 @@
"nonstandard": true, "nonstandard": true,
"sub": true, "sub": true,
"validthis": true, "validthis": true,
"globals": { "globals": {
"_": false, "_": false,
"define" : false, "define": false,
"module" : false "module": false
} }
} }

View file

@ -1,6 +1,3 @@
{ {
"ignore_dirs": [ "ignore_dirs": [".git", "node_modules"]
".git",
"node_modules"
]
} }

View file

@ -43,7 +43,7 @@ Create the new ePub, and then render it to that element:
```html ```html
<script> <script>
var book = ePub("url/to/book/package.opf"); var book = ePub("url/to/book/package.opf");
var rendition = book.renderTo("area", {width: 600, height: 400}); var rendition = book.renderTo("area", { width: 600, height: 400 });
var displayed = rendition.display(); var displayed = rendition.display();
</script> </script>
``` ```
@ -65,6 +65,7 @@ The default manager only displays a single section at a time.
```js ```js
book.renderTo("area", { method: "continuous", width: "100%", height: "100%" }); book.renderTo("area", { method: "continuous", width: "100%", height: "100%" });
``` ```
[View example](http://futurepress.github.io/epub.js/examples/continuous-scrolled.html) [View example](http://futurepress.github.io/epub.js/examples/continuous-scrolled.html)
The continuous manager will display as many sections as need to fill the screen, and preload the next section offscreen. This enables seamless swiping / scrolling between pages on mobile and desktop, but is less performant than the default method. The continuous manager will display as many sections as need to fill the screen, and preload the next section offscreen. This enables seamless swiping / scrolling between pages on mobile and desktop, but is less performant than the default method.
@ -72,6 +73,7 @@ The continuous manager will display as many sections as need to fill the screen,
## Flow Overrides ## Flow Overrides
### Auto (Default) ### Auto (Default)
`book.renderTo("area", { flow: "auto", width: "900", height: "600" });` `book.renderTo("area", { flow: "auto", width: "900", height: "600" });`
Flow will be based on the settings in the OPF, defaults to `paginated`. Flow will be based on the settings in the OPF, defaults to `paginated`.
@ -101,7 +103,7 @@ If a trusted ePub contains interactivity, it can be enabled by passing `allowScr
var rendition = book.renderTo("area", { var rendition = book.renderTo("area", {
width: 600, width: 600,
height: 400, height: 400,
allowScriptedContent: true allowScriptedContent: true,
}); });
</script> </script>
``` ```
@ -132,11 +134,11 @@ npm start
## Examples ## Examples
+ [Spreads](http://futurepress.github.io/epub.js/examples/spreads.html) - [Spreads](http://futurepress.github.io/epub.js/examples/spreads.html)
+ [Scrolled](http://futurepress.github.io/epub.js/examples/scrolled.html) - [Scrolled](http://futurepress.github.io/epub.js/examples/scrolled.html)
+ [Swipe](http://futurepress.github.io/epub.js/examples/swipe.html) - [Swipe](http://futurepress.github.io/epub.js/examples/swipe.html)
+ [Input](http://futurepress.github.io/epub.js/examples/input.html) - [Input](http://futurepress.github.io/epub.js/examples/input.html)
+ [Highlights](http://futurepress.github.io/epub.js/examples/highlights.html) - [Highlights](http://futurepress.github.io/epub.js/examples/highlights.html)
[View All Examples](http://futurepress.github.io/epub.js/examples/) [View All Examples](http://futurepress.github.io/epub.js/examples/)
@ -175,29 +177,28 @@ Hooks require an event to register to and a can return a promise to block until
Example hook: Example hook:
```javascript ```javascript
rendition.hooks.content.register(function(contents, view) { rendition.hooks.content.register(function (contents, view) {
var elements = contents.document.querySelectorAll("[video]");
var elements = contents.document.querySelectorAll('[video]');
var items = Array.prototype.slice.call(elements); var items = Array.prototype.slice.call(elements);
items.forEach(function(item){ items.forEach(function (item) {
// do something with the video item // do something with the video item
}); });
});
})
``` ```
The parts of the rendering process that can be hooked into are below. The parts of the rendering process that can be hooked into are below.
```js ```js
book.spine.hooks.serialize // Section is being converted to text book.spine.hooks.serialize; // Section is being converted to text
book.spine.hooks.content // Section has been loaded and parsed book.spine.hooks.content; // Section has been loaded and parsed
rendition.hooks.render // Section is rendered to the screen rendition.hooks.render; // Section is rendered to the screen
rendition.hooks.content // Section contents have been loaded rendition.hooks.content; // Section contents have been loaded
rendition.hooks.unloaded // Section contents are being unloaded rendition.hooks.unloaded; // Section contents are being unloaded
``` ```
## Reader ## Reader
The reader has moved to its own repo at: https://github.com/futurepress/epubjs-reader/ The reader has moved to its own repo at: https://github.com/futurepress/epubjs-reader/
## Additional Resources ## Additional Resources
@ -210,7 +211,7 @@ IRC Server: freenode.net Channel: #epub.js
Follow us on twitter: @Epubjs Follow us on twitter: @Epubjs
+ http://twitter.com/#!/Epubjs - http://twitter.com/#!/Epubjs
## Other ## Other

View file

@ -1,19 +1,11 @@
{ {
"name": "epubjs", "name": "epubjs",
"version": "0.3.0", "version": "0.3.0",
"authors": [ "authors": ["Fred Chasen <fchasen@gmail.com>"],
"Fred Chasen <fchasen@gmail.com>"
],
"description": "Enhanced eBooks in the browser.", "description": "Enhanced eBooks in the browser.",
"main": "dist/epub.js", "main": "dist/epub.js",
"moduleType": [ "moduleType": ["amd", "globals", "node"],
"amd", "keywords": ["epub"],
"globals",
"node"
],
"keywords": [
"epub"
],
"license": "MIT", "license": "MIT",
"homepage": "http://futurepress.org", "homepage": "http://futurepress.org",
"ignore": [ "ignore": [

View file

@ -3,115 +3,75 @@ webpackConfig.mode = "development";
webpackConfig.externals = {}; webpackConfig.externals = {};
webpackConfig.module.rules.push({ webpackConfig.module.rules.push({
test: /\.xhtml$/i, test: /\.xhtml$/i,
use: 'raw-loader', use: "raw-loader",
}); });
module.exports = function(config) { module.exports = function (config) {
config.set({ config.set({
// base path that will be used to resolve all patterns (eg. files, exclude) // base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '', basePath: "",
// frameworks to use // frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha'], frameworks: ["mocha"],
// list of files / patterns to load in the browser // list of files / patterns to load in the browser
files: [ files: [
{ pattern: "src/*.js", watched: true, included: false, served: false },
{pattern: 'src/*.js', watched: true, included: false, served: false}, { pattern: "test/*.js", watched: false },
{pattern: 'test/*.js', watched: false}, {
pattern: "test/fixtures/**/*",
{pattern: 'test/fixtures/**/*', watched: false, included: false, served: true}, watched: false,
included: false,
served: true,
},
// {pattern: 'node_modules/jszip/dist/jszip.js', watched: false, included: true, served: true}, // {pattern: 'node_modules/jszip/dist/jszip.js', watched: false, included: true, served: true},
// {pattern: 'node_modules/es6-promise/dist/es6-promise.auto.js', watched: false, included: true, served: true}, // {pattern: 'node_modules/es6-promise/dist/es6-promise.auto.js', watched: false, included: true, served: true},
// {pattern: 'libs/url/url-polyfill.js', watched: false, included: true, served: true} // {pattern: 'libs/url/url-polyfill.js', watched: false, included: true, served: true}
], ],
// list of files to exclude // list of files to exclude
exclude: [ exclude: [],
],
// preprocess matching files before serving them to the browser // preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: { preprocessors: {
// add webpack as preprocessor // add webpack as preprocessor
'test/*.js': ['webpack', 'sourcemap'], "test/*.js": ["webpack", "sourcemap"],
// 'test/**/*.js': ['webpack', 'sourcemap']
}, },
webpack: webpackConfig, webpack: webpackConfig,
// {
// mode: "development",
// externals: {
// "jszip": "JSZip"
// // "xmldom": "xmldom"
// },
// devtool: 'inline-source-map',
// resolve: {
// alias: {
// path: "path-webpack"
// }
// },
// module: {
// rules: [
// {
// test: /\.js$/,
// exclude: /node_modules/,
// loader: "babel-loader",
// query: {
// presets: [["@babel/preset-env", {
// targets: "defaults",
// }]],
// }
// },
// {
// test: /\.xhtml$/i,
// use: 'raw-loader',
// }
// ]
// }
// },
webpackMiddleware: { webpackMiddleware: {
stats: 'errors-only' stats: "errors-only",
}, },
// test results reporter to use // test results reporter to use
// possible values: 'dots', 'progress' // possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter // available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['mocha'], reporters: ["mocha"],
// web server port // web server port
port: 9876, port: 9876,
// enable / disable colors in the output (reporters and logs) // enable / disable colors in the output (reporters and logs)
colors: true, colors: true,
// level of logging // level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes // enable / disable watching file and executing tests whenever any file changes
autoWatch: true, autoWatch: true,
// start these browsers // start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadless', 'ChromeHeadlessNoSandbox'], browsers: ["ChromeHeadless", "ChromeHeadlessNoSandbox"],
// Continuous Integration mode // Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits // if true, Karma captures browsers, runs the tests and exits
@ -121,27 +81,19 @@ module.exports = function(config) {
// how many browser should be started simultaneous // how many browser should be started simultaneous
concurrency: Infinity, concurrency: Infinity,
proxies: { proxies: { "/fixtures/": "/base/test/fixtures/" },
"/fixtures/": "/base/test/fixtures/"
},
client: { client: {
config: { config: { browserConsoleLogOptions: true },
browserConsoleLogOptions: true
},
captureConsole: true, captureConsole: true,
mocha: { mocha: { reporter: "html" },
reporter: 'html'
// bail: true
}
}, },
customLaunchers: { customLaunchers: {
ChromeHeadlessNoSandbox: { ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless', base: "ChromeHeadless",
flags: ['--no-sandbox'] flags: ["--no-sandbox"],
} },
} },
});
}) };
}

View file

@ -8,8 +8,7 @@ import { EVENTS } from "./utils/constants";
* @class * @class
*/ */
class Annotations { class Annotations {
constructor(rendition) {
constructor (rendition) {
this.rendition = rendition; this.rendition = rendition;
this.highlights = []; this.highlights = [];
this.underlines = []; this.underlines = [];
@ -31,7 +30,7 @@ class Annotations {
* @param {object} styles CSS styles to assign to annotation * @param {object} styles CSS styles to assign to annotation
* @returns {Annotation} annotation * @returns {Annotation} annotation
*/ */
add (type, cfiRange, data, cb, className, styles) { add(type, cfiRange, data, cb, className, styles) {
let hash = encodeURI(cfiRange + type); let hash = encodeURI(cfiRange + type);
let cfi = new EpubCFI(cfiRange); let cfi = new EpubCFI(cfiRange);
let sectionIndex = cfi.spinePos; let sectionIndex = cfi.spinePos;
@ -42,7 +41,7 @@ class Annotations {
sectionIndex, sectionIndex,
cb, cb,
className, className,
styles styles,
}); });
this._annotations[hash] = annotation; this._annotations[hash] = annotation;
@ -55,7 +54,7 @@ class Annotations {
let views = this.rendition.views(); let views = this.rendition.views();
views.forEach( (view) => { views.forEach((view) => {
if (annotation.sectionIndex === view.index) { if (annotation.sectionIndex === view.index) {
annotation.attach(view); annotation.attach(view);
} }
@ -69,7 +68,7 @@ class Annotations {
* @param {EpubCFI} cfiRange EpubCFI range the annotation is attached to * @param {EpubCFI} cfiRange EpubCFI range the annotation is attached to
* @param {string} type Type of annotation to add: "highlight", "underline", "mark" * @param {string} type Type of annotation to add: "highlight", "underline", "mark"
*/ */
remove (cfiRange, type) { remove(cfiRange, type) {
let hash = encodeURI(cfiRange + type); let hash = encodeURI(cfiRange + type);
if (hash in this._annotations) { if (hash in this._annotations) {
@ -80,7 +79,7 @@ class Annotations {
} }
let views = this.rendition.views(); let views = this.rendition.views();
views.forEach( (view) => { views.forEach((view) => {
this._removeFromAnnotationBySectionIndex(annotation.sectionIndex, hash); this._removeFromAnnotationBySectionIndex(annotation.sectionIndex, hash);
if (annotation.sectionIndex === view.index) { if (annotation.sectionIndex === view.index) {
annotation.detach(view); annotation.detach(view);
@ -95,19 +94,20 @@ class Annotations {
* Remove an annotations by Section Index * Remove an annotations by Section Index
* @private * @private
*/ */
_removeFromAnnotationBySectionIndex (sectionIndex, hash) { _removeFromAnnotationBySectionIndex(sectionIndex, hash) {
this._annotationsBySectionIndex[sectionIndex] = this._annotationsAt(sectionIndex).filter(h => h !== hash); this._annotationsBySectionIndex[sectionIndex] = this._annotationsAt(
sectionIndex
).filter((h) => h !== hash);
} }
/** /**
* Get annotations by Section Index * Get annotations by Section Index
* @private * @private
*/ */
_annotationsAt (index) { _annotationsAt(index) {
return this._annotationsBySectionIndex[index]; return this._annotationsBySectionIndex[index];
} }
/** /**
* Add a highlight to the store * Add a highlight to the store
* @param {EpubCFI} cfiRange EpubCFI range to attach annotation to * @param {EpubCFI} cfiRange EpubCFI range to attach annotation to
@ -116,7 +116,7 @@ class Annotations {
* @param {string} className CSS class to assign to annotation * @param {string} className CSS class to assign to annotation
* @param {object} styles CSS styles to assign to annotation * @param {object} styles CSS styles to assign to annotation
*/ */
highlight (cfiRange, data, cb, className, styles) { highlight(cfiRange, data, cb, className, styles) {
return this.add("highlight", cfiRange, data, cb, className, styles); return this.add("highlight", cfiRange, data, cb, className, styles);
} }
@ -128,7 +128,7 @@ class Annotations {
* @param {string} className CSS class to assign to annotation * @param {string} className CSS class to assign to annotation
* @param {object} styles CSS styles to assign to annotation * @param {object} styles CSS styles to assign to annotation
*/ */
underline (cfiRange, data, cb, className, styles) { underline(cfiRange, data, cb, className, styles) {
return this.add("underline", cfiRange, data, cb, className, styles); return this.add("underline", cfiRange, data, cb, className, styles);
} }
@ -138,14 +138,14 @@ class Annotations {
* @param {object} data Data to assign to annotation * @param {object} data Data to assign to annotation
* @param {function} cb Callback after annotation is clicked * @param {function} cb Callback after annotation is clicked
*/ */
mark (cfiRange, data, cb) { mark(cfiRange, data, cb) {
return this.add("mark", cfiRange, data, cb); return this.add("mark", cfiRange, data, cb);
} }
/** /**
* iterate over annotations in the store * iterate over annotations in the store
*/ */
each () { each() {
return this._annotations.forEach.apply(this._annotations, arguments); return this._annotations.forEach.apply(this._annotations, arguments);
} }
@ -154,7 +154,7 @@ class Annotations {
* @param {View} view * @param {View} view
* @private * @private
*/ */
inject (view) { inject(view) {
let sectionIndex = view.index; let sectionIndex = view.index;
if (sectionIndex in this._annotationsBySectionIndex) { if (sectionIndex in this._annotationsBySectionIndex) {
let annotations = this._annotationsBySectionIndex[sectionIndex]; let annotations = this._annotationsBySectionIndex[sectionIndex];
@ -170,7 +170,7 @@ class Annotations {
* @param {View} view * @param {View} view
* @private * @private
*/ */
clear (view) { clear(view) {
let sectionIndex = view.index; let sectionIndex = view.index;
if (sectionIndex in this._annotationsBySectionIndex) { if (sectionIndex in this._annotationsBySectionIndex) {
let annotations = this._annotationsBySectionIndex[sectionIndex]; let annotations = this._annotationsBySectionIndex[sectionIndex];
@ -185,18 +185,13 @@ class Annotations {
* [Not Implemented] Show annotations * [Not Implemented] Show annotations
* @TODO: needs implementation in View * @TODO: needs implementation in View
*/ */
show () { show() {}
}
/** /**
* [Not Implemented] Hide annotations * [Not Implemented] Hide annotations
* @TODO: needs implementation in View * @TODO: needs implementation in View
*/ */
hide () { hide() {}
}
} }
/** /**
@ -213,16 +208,7 @@ class Annotations {
* @returns {Annotation} annotation * @returns {Annotation} annotation
*/ */
class Annotation { class Annotation {
constructor({ type, cfiRange, data, sectionIndex, cb, className, styles }) {
constructor ({
type,
cfiRange,
data,
sectionIndex,
cb,
className,
styles
}) {
this.type = type; this.type = type;
this.cfiRange = cfiRange; this.cfiRange = cfiRange;
this.data = data; this.data = data;
@ -237,7 +223,7 @@ class Annotation {
* Update stored data * Update stored data
* @param {object} data * @param {object} data
*/ */
update (data) { update(data) {
this.data = data; this.data = data;
} }
@ -245,8 +231,8 @@ class Annotation {
* Add to a view * Add to a view
* @param {View} view * @param {View} view
*/ */
attach (view) { attach(view) {
let {cfiRange, data, type, mark, cb, className, styles} = this; let { cfiRange, data, type, cb, className, styles } = this;
let result; let result;
if (type === "highlight") { if (type === "highlight") {
@ -266,8 +252,8 @@ class Annotation {
* Remove from a view * Remove from a view
* @param {View} view * @param {View} view
*/ */
detach (view) { detach(view) {
let {cfiRange, type} = this; let { cfiRange, type } = this;
let result; let result;
if (view) { if (view) {
@ -289,13 +275,9 @@ class Annotation {
* [Not Implemented] Get text of an annotation * [Not Implemented] Get text of an annotation
* @TODO: needs implementation in contents * @TODO: needs implementation in contents
*/ */
text () { text() {}
}
} }
EventEmitter(Annotation.prototype); EventEmitter(Annotation.prototype);
export default Annotations;
export default Annotations

View file

@ -1,21 +1,19 @@
import {defer, isXml, parse} from "./utils/core"; import JSZip from "jszip/dist/jszip";
import request from "./utils/request"; import { defer, isXml, parse } from "./utils/core";
import mime from "./utils/mime"; import mime from "./utils/mime";
import Path from "./utils/path"; import Path from "./utils/path";
import JSZip from "jszip/dist/jszip"; import request from "./utils/request";
/** /**
* Handles Unzipping a requesting files from an Epub Archive * Handles Unzipping a requesting files from an Epub Archive
* @class * @class
*/ */
class Archive { class Archive {
constructor() { constructor() {
this.zip = undefined; this.zip = undefined;
this.urlCache = {}; this.urlCache = {};
this.checkRequirements(); this.checkRequirements();
} }
/** /**
@ -23,7 +21,7 @@ class Archive {
* Requires JSZip if it isn't there * Requires JSZip if it isn't there
* @private * @private
*/ */
checkRequirements(){ checkRequirements() {
try { try {
this.zip = new JSZip(); this.zip = new JSZip();
} catch (e) { } catch (e) {
@ -37,8 +35,8 @@ class Archive {
* @param {boolean} [isBase64] tells JSZip if the input data is base64 encoded * @param {boolean} [isBase64] tells JSZip if the input data is base64 encoded
* @return {Promise} zipfile * @return {Promise} zipfile
*/ */
open(input, isBase64){ open(input, isBase64) {
return this.zip.loadAsync(input, {"base64": isBase64}); return this.zip.loadAsync(input, { base64: isBase64 });
} }
/** /**
@ -47,11 +45,12 @@ class Archive {
* @param {boolean} [isBase64] tells JSZip if the input data is base64 encoded * @param {boolean} [isBase64] tells JSZip if the input data is base64 encoded
* @return {Promise} zipfile * @return {Promise} zipfile
*/ */
openUrl(zipUrl, isBase64){ openUrl(zipUrl, isBase64) {
return request(zipUrl, "binary") return request(zipUrl, "binary").then(
.then(function(data){ function (data) {
return this.zip.loadAsync(data, {"base64": isBase64}); return this.zip.loadAsync(data, { base64: isBase64 });
}.bind(this)); }.bind(this)
);
} }
/** /**
@ -60,31 +59,33 @@ class Archive {
* @param {string} [type] specify the type of the returned result * @param {string} [type] specify the type of the returned result
* @return {Promise<Blob | string | JSON | Document | XMLDocument>} * @return {Promise<Blob | string | JSON | Document | XMLDocument>}
*/ */
request(url, type){ request(url, type) {
var deferred = new defer(); var deferred = new defer();
var response; var response;
var path = new Path(url); var path = new Path(url);
// If type isn't set, determine it from the file extension // If type isn't set, determine it from the file extension
if(!type) { if (!type) {
type = path.extension; type = path.extension;
} }
if(type == "blob"){ if (type == "blob") {
response = this.getBlob(url); response = this.getBlob(url);
} else { } else {
response = this.getText(url); response = this.getText(url);
} }
if (response) { if (response) {
response.then(function (r) { response.then(
function (r) {
let result = this.handleResponse(r, type); let result = this.handleResponse(r, type);
deferred.resolve(result); deferred.resolve(result);
}.bind(this)); }.bind(this)
);
} else { } else {
deferred.reject({ deferred.reject({
message : "File not found in the epub: " + url, message: "File not found in the epub: " + url,
stack : new Error().stack stack: new Error().stack,
}); });
} }
return deferred.promise; return deferred.promise;
@ -97,22 +98,16 @@ class Archive {
* @param {string} [type] * @param {string} [type]
* @return {any} the parsed result * @return {any} the parsed result
*/ */
handleResponse(response, type){ handleResponse(response, type) {
var r; var r;
if(type == "json") { if (type == "json") {
r = JSON.parse(response); r = JSON.parse(response);
} } else if (isXml(type)) {
else
if(isXml(type)) {
r = parse(response, "text/xml"); r = parse(response, "text/xml");
} } else if (type == "xhtml") {
else
if(type == "xhtml") {
r = parse(response, "application/xhtml+xml"); r = parse(response, "application/xhtml+xml");
} } else if (type == "html" || type == "htm") {
else
if(type == "html" || type == "htm") {
r = parse(response, "text/html"); r = parse(response, "text/html");
} else { } else {
r = response; r = response;
@ -127,14 +122,14 @@ class Archive {
* @param {string} [mimeType] * @param {string} [mimeType]
* @return {Blob} * @return {Blob}
*/ */
getBlob(url, mimeType){ getBlob(url, mimeType) {
var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash
var entry = this.zip.file(decodededUrl); var entry = this.zip.file(decodededUrl);
if(entry) { if (entry) {
mimeType = mimeType || mime.lookup(entry.name); mimeType = mimeType || mime.lookup(entry.name);
return entry.async("uint8array").then(function(uint8array) { return entry.async("uint8array").then(function (uint8array) {
return new Blob([uint8array], {type : mimeType}); return new Blob([uint8array], { type: mimeType });
}); });
} }
} }
@ -145,12 +140,12 @@ class Archive {
* @param {string} [encoding] * @param {string} [encoding]
* @return {string} * @return {string}
*/ */
getText(url, encoding){ getText(url, encoding) {
var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash
var entry = this.zip.file(decodededUrl); var entry = this.zip.file(decodededUrl);
if(entry) { if (entry) {
return entry.async("string").then(function(text) { return entry.async("string").then(function (text) {
return text; return text;
}); });
} }
@ -162,13 +157,13 @@ class Archive {
* @param {string} [mimeType] * @param {string} [mimeType]
* @return {string} base64 encoded * @return {string} base64 encoded
*/ */
getBase64(url, mimeType){ getBase64(url, mimeType) {
var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash
var entry = this.zip.file(decodededUrl); var entry = this.zip.file(decodededUrl);
if(entry) { if (entry) {
mimeType = mimeType || mime.lookup(entry.name); mimeType = mimeType || mime.lookup(entry.name);
return entry.async("base64").then(function(data) { return entry.async("base64").then(function (data) {
return "data:" + mimeType + ";base64," + data; return "data:" + mimeType + ";base64," + data;
}); });
} }
@ -180,14 +175,14 @@ class Archive {
* @param {object} [options.base64] use base64 encoding or blob url * @param {object} [options.base64] use base64 encoding or blob url
* @return {Promise} url promise with Url string * @return {Promise} url promise with Url string
*/ */
createUrl(url, options){ createUrl(url, options) {
var deferred = new defer(); var deferred = new defer();
var _URL = window.URL || window.webkitURL || window.mozURL; var _URL = window.URL || window.webkitURL || window.mozURL;
var tempUrl; var tempUrl;
var response; var response;
var useBase64 = options && options.base64; var useBase64 = options && options.base64;
if(url in this.urlCache) { if (url in this.urlCache) {
deferred.resolve(this.urlCache[url]); deferred.resolve(this.urlCache[url]);
return deferred.promise; return deferred.promise;
} }
@ -196,36 +191,31 @@ class Archive {
response = this.getBase64(url); response = this.getBase64(url);
if (response) { if (response) {
response.then(function(tempUrl) { response.then(
function (tempUrl) {
this.urlCache[url] = tempUrl; this.urlCache[url] = tempUrl;
deferred.resolve(tempUrl); deferred.resolve(tempUrl);
}.bind(this)
}.bind(this)); );
} }
} else { } else {
response = this.getBlob(url); response = this.getBlob(url);
if (response) { if (response) {
response.then(function(blob) { response.then(
function (blob) {
tempUrl = _URL.createObjectURL(blob); tempUrl = _URL.createObjectURL(blob);
this.urlCache[url] = tempUrl; this.urlCache[url] = tempUrl;
deferred.resolve(tempUrl); deferred.resolve(tempUrl);
}.bind(this)
}.bind(this)); );
} }
} }
if (!response) { if (!response) {
deferred.reject({ deferred.reject({
message : "File not found in the epub: " + url, message: "File not found in the epub: " + url,
stack : new Error().stack stack: new Error().stack,
}); });
} }
@ -236,10 +226,10 @@ class Archive {
* Revoke Temp Url for a archive item * Revoke Temp Url for a archive item
* @param {string} url url of the item in the archive * @param {string} url url of the item in the archive
*/ */
revokeUrl(url){ revokeUrl(url) {
var _URL = window.URL || window.webkitURL || window.mozURL; var _URL = window.URL || window.webkitURL || window.mozURL;
var fromCache = this.urlCache[url]; var fromCache = this.urlCache[url];
if(fromCache) _URL.revokeObjectURL(fromCache); if (fromCache) _URL.revokeObjectURL(fromCache);
} }
destroy() { destroy() {

View file

@ -1,24 +1,25 @@
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import {extend, defer} from "./utils/core"; import Archive from "./archive";
import Url from "./utils/url";
import Path from "./utils/path";
import Spine from "./spine";
import Locations from "./locations";
import Container from "./container"; import Container from "./container";
import Packaging from "./packaging"; import DisplayOptions from "./displayoptions";
import EpubCFI from "./epubcfi";
import Locations from "./locations";
import Navigation from "./navigation"; import Navigation from "./navigation";
import Resources from "./resources"; import Packaging from "./packaging";
import PageList from "./pagelist"; import PageList from "./pagelist";
import Rendition from "./rendition"; import Rendition from "./rendition";
import Archive from "./archive"; import Resources from "./resources";
import request from "./utils/request"; import Spine from "./spine";
import EpubCFI from "./epubcfi";
import Store from "./store"; import Store from "./store";
import DisplayOptions from "./displayoptions";
import { EPUBJS_VERSION, EVENTS } from "./utils/constants"; import { EPUBJS_VERSION, EVENTS } from "./utils/constants";
import { defer, extend } from "./utils/core";
import Path from "./utils/path";
import request from "./utils/request";
import Url from "./utils/url";
const CONTAINER_PATH = "META-INF/container.xml"; const CONTAINER_PATH = "META-INF/container.xml";
const IBOOKS_DISPLAY_OPTIONS_PATH = "META-INF/com.apple.ibooks.display-options.xml"; const IBOOKS_DISPLAY_OPTIONS_PATH =
"META-INF/com.apple.ibooks.display-options.xml";
const INPUT_TYPE = { const INPUT_TYPE = {
BINARY: "binary", BINARY: "binary",
@ -26,7 +27,7 @@ const INPUT_TYPE = {
EPUB: "epub", EPUB: "epub",
OPF: "opf", OPF: "opf",
MANIFEST: "json", MANIFEST: "json",
DIRECTORY: "directory" DIRECTORY: "directory",
}; };
/** /**
@ -50,10 +51,12 @@ const INPUT_TYPE = {
class Book { class Book {
constructor(url, options) { constructor(url, options) {
// Allow passing just options to the Book // Allow passing just options to the Book
if (typeof(options) === "undefined" && if (
typeof(url) !== "string" && typeof options === "undefined" &&
typeof url !== "string" &&
url instanceof Blob === false && url instanceof Blob === false &&
url instanceof ArrayBuffer === false) { url instanceof ArrayBuffer === false
) {
options = url; options = url;
url = undefined; url = undefined;
} }
@ -66,12 +69,11 @@ class Book {
replacements: undefined, replacements: undefined,
canonical: undefined, canonical: undefined,
openAs: undefined, openAs: undefined,
store: undefined store: undefined,
}); });
extend(this.settings, options); extend(this.settings, options);
// Promises // Promises
this.opening = new defer(); this.opening = new defer();
/** /**
@ -89,7 +91,7 @@ class Book {
navigation: new defer(), navigation: new defer(),
pageList: new defer(), pageList: new defer(),
resources: new defer(), resources: new defer(),
displayOptions: new defer() displayOptions: new defer(),
}; };
this.loaded = { this.loaded = {
@ -100,7 +102,7 @@ class Book {
navigation: this.loading.navigation.promise, navigation: this.loading.navigation.promise,
pageList: this.loading.pageList.promise, pageList: this.loading.pageList.promise,
resources: this.loading.resources.promise, resources: this.loading.resources.promise,
displayOptions: this.loading.displayOptions.promise displayOptions: this.loading.displayOptions.promise,
}; };
/** /**
@ -115,10 +117,9 @@ class Book {
this.loaded.cover, this.loaded.cover,
this.loaded.navigation, this.loaded.navigation,
this.loaded.resources, this.loaded.resources,
this.loaded.displayOptions this.loaded.displayOptions,
]); ]);
// Queue for methods used before opening // Queue for methods used before opening
this.isRendered = false; this.isRendered = false;
// this._q = queue(this); // this._q = queue(this);
@ -229,9 +230,9 @@ class Book {
this.store(this.settings.store); this.store(this.settings.store);
} }
if(url) { if (url) {
this.open(url, this.settings.openAs).catch((error) => { this.open(url, this.settings.openAs).catch((error) => {
var err = new Error("Cannot load book at "+ url ); var err = new Error("Cannot load book at " + url);
this.emit(EVENTS.BOOK.OPEN_FAILED, err); this.emit(EVENTS.BOOK.OPEN_FAILED, err);
}); });
} }
@ -259,18 +260,23 @@ class Book {
} else if (type === INPUT_TYPE.EPUB) { } else if (type === INPUT_TYPE.EPUB) {
this.archived = true; this.archived = true;
this.url = new Url("/", ""); this.url = new Url("/", "");
opening = this.request(input, "binary", this.settings.requestCredentials, this.settings.requestHeaders) opening = this.request(
.then(this.openEpub.bind(this)); input,
} else if(type == INPUT_TYPE.OPF) { "binary",
this.settings.requestCredentials,
this.settings.requestHeaders
).then(this.openEpub.bind(this));
} else if (type == INPUT_TYPE.OPF) {
this.url = new Url(input); this.url = new Url(input);
opening = this.openPackaging(this.url.Path.toString()); opening = this.openPackaging(this.url.Path.toString());
} else if(type == INPUT_TYPE.MANIFEST) { } else if (type == INPUT_TYPE.MANIFEST) {
this.url = new Url(input); this.url = new Url(input);
opening = this.openManifest(this.url.Path.toString()); opening = this.openManifest(this.url.Path.toString());
} else { } else {
this.url = new Url(input); this.url = new Url(input);
opening = this.openContainer(CONTAINER_PATH) opening = this.openContainer(CONTAINER_PATH).then(
.then(this.openPackaging.bind(this)); this.openPackaging.bind(this)
);
} }
return opening; return opening;
@ -300,8 +306,7 @@ class Book {
* @return {string} packagePath * @return {string} packagePath
*/ */
openContainer(url) { openContainer(url) {
return this.load(url) return this.load(url).then((xml) => {
.then((xml) => {
this.container = new Container(xml); this.container = new Container(xml);
return this.resolve(this.container.packagePath); return this.resolve(this.container.packagePath);
}); });
@ -315,8 +320,7 @@ class Book {
*/ */
openPackaging(url) { openPackaging(url) {
this.path = new Path(url); this.path = new Path(url);
return this.load(url) return this.load(url).then((xml) => {
.then((xml) => {
this.packaging = new Packaging(xml); this.packaging = new Packaging(xml);
return this.unpack(this.packaging); return this.unpack(this.packaging);
}); });
@ -330,8 +334,7 @@ class Book {
*/ */
openManifest(url) { openManifest(url) {
this.path = new Path(url); this.path = new Path(url);
return this.load(url) return this.load(url).then((json) => {
.then((json) => {
this.packaging = new Packaging(); this.packaging = new Packaging();
this.packaging.load(json); this.packaging.load(json);
return this.unpack(this.packaging); return this.unpack(this.packaging);
@ -345,10 +348,15 @@ class Book {
*/ */
load(path) { load(path) {
var resolved = this.resolve(path); var resolved = this.resolve(path);
if(this.archived) { if (this.archived) {
return this.archive.request(resolved); return this.archive.request(resolved);
} else { } else {
return this.request(resolved, null, this.settings.requestCredentials, this.settings.requestHeaders); return this.request(
resolved,
null,
this.settings.requestCredentials,
this.settings.requestHeaders
);
} }
} }
@ -363,7 +371,7 @@ class Book {
return; return;
} }
var resolved = path; var resolved = path;
var isAbsolute = (path.indexOf("://") > -1); var isAbsolute = path.indexOf("://") > -1;
if (isAbsolute) { if (isAbsolute) {
return path; return path;
@ -373,7 +381,7 @@ class Book {
resolved = this.path.resolve(path); resolved = this.path.resolve(path);
} }
if(absolute != false && this.url) { if (absolute != false && this.url) {
resolved = this.url.resolve(resolved); resolved = this.url.resolve(resolved);
} }
@ -416,7 +424,7 @@ class Book {
return INPUT_TYPE.BASE64; return INPUT_TYPE.BASE64;
} }
if(typeof(input) != "string") { if (typeof input != "string") {
return INPUT_TYPE.BINARY; return INPUT_TYPE.BINARY;
} }
@ -433,20 +441,19 @@ class Book {
return INPUT_TYPE.DIRECTORY; return INPUT_TYPE.DIRECTORY;
} }
if(extension === "epub"){ if (extension === "epub") {
return INPUT_TYPE.EPUB; return INPUT_TYPE.EPUB;
} }
if(extension === "opf"){ if (extension === "opf") {
return INPUT_TYPE.OPF; return INPUT_TYPE.OPF;
} }
if(extension === "json"){ if (extension === "json") {
return INPUT_TYPE.MANIFEST; return INPUT_TYPE.MANIFEST;
} }
} }
/** /**
* unpack the contents of the Books packaging * unpack the contents of the Books packaging
* @private * @private
@ -457,10 +464,12 @@ class Book {
if (this.packaging.metadata.layout === "") { if (this.packaging.metadata.layout === "") {
// rendition:layout not set - check display options if book is pre-paginated // rendition:layout not set - check display options if book is pre-paginated
this.load(this.url.resolve(IBOOKS_DISPLAY_OPTIONS_PATH)).then((xml) => { this.load(this.url.resolve(IBOOKS_DISPLAY_OPTIONS_PATH))
.then((xml) => {
this.displayOptions = new DisplayOptions(xml); this.displayOptions = new DisplayOptions(xml);
this.loading.displayOptions.resolve(this.displayOptions); this.loading.displayOptions.resolve(this.displayOptions);
}).catch((err) => { })
.catch((err) => {
this.displayOptions = new DisplayOptions(); this.displayOptions = new DisplayOptions();
this.loading.displayOptions.resolve(this.displayOptions); this.loading.displayOptions.resolve(this.displayOptions);
}); });
@ -469,13 +478,18 @@ class Book {
this.loading.displayOptions.resolve(this.displayOptions); this.loading.displayOptions.resolve(this.displayOptions);
} }
this.spine.unpack(this.packaging, this.resolve.bind(this), this.canonical.bind(this)); this.spine.unpack(
this.packaging,
this.resolve.bind(this),
this.canonical.bind(this)
);
this.resources = new Resources(this.packaging.manifest, { this.resources = new Resources(this.packaging.manifest, {
archive: this.archive, archive: this.archive,
resolver: this.resolve.bind(this), resolver: this.resolve.bind(this),
request: this.request.bind(this), request: this.request.bind(this),
replacements: this.settings.replacements || (this.archived ? "blobUrl" : "base64") replacements:
this.settings.replacements || (this.archived ? "blobUrl" : "base64"),
}); });
this.loadNavigation(this.packaging).then(() => { this.loadNavigation(this.packaging).then(() => {
@ -496,8 +510,12 @@ class Book {
this.isOpen = true; this.isOpen = true;
if(this.archived || this.settings.replacements && this.settings.replacements != "none") { if (
this.replacements().then(() => { this.archived ||
(this.settings.replacements && this.settings.replacements != "none")
) {
this.replacements()
.then(() => {
this.loaded.displayOptions.then(() => { this.loaded.displayOptions.then(() => {
this.opening.resolve(this); this.opening.resolve(this);
}); });
@ -511,7 +529,6 @@ class Book {
this.opening.resolve(this); this.opening.resolve(this);
}); });
} }
} }
/** /**
@ -545,8 +562,7 @@ class Book {
}); });
} }
return this.load(navPath, "xml") return this.load(navPath, "xml").then((xml) => {
.then((xml) => {
this.navigation = new Navigation(xml); this.navigation = new Navigation(xml);
this.pageList = new PageList(xml); this.pageList = new PageList(xml);
return this.navigation; return this.navigation;
@ -613,7 +629,8 @@ class Book {
*/ */
store(name) { store(name) {
// Use "blobUrl" or "base64" for replacements // Use "blobUrl" or "base64" for replacements
let replacementsSetting = this.settings.replacements && this.settings.replacements !== "none"; let replacementsSetting =
this.settings.replacements && this.settings.replacements !== "none";
// Save original url // Save original url
let originalUrl = this.url; let originalUrl = this.url;
// Save original request method // Save original request method
@ -635,8 +652,7 @@ class Book {
// Set to use replacements // Set to use replacements
this.resources.settings.replacements = replacementsSetting || "blobUrl"; this.resources.settings.replacements = replacementsSetting || "blobUrl";
// Create replacement urls // Create replacement urls
this.resources.replacements(). this.resources.replacements().then(() => {
then(() => {
return this.resources.replaceCss(); return this.resources.replaceCss();
}); });
@ -653,7 +669,6 @@ class Book {
// Remove hook // Remove hook
this.spine.hooks.serialize.deregister(substituteResources); this.spine.hooks.serialize.deregister(substituteResources);
}); });
}); });
return this.storage; return this.storage;
@ -687,8 +702,7 @@ class Book {
section.output = this.resources.substitute(output, section.url); section.output = this.resources.substitute(output, section.url);
}); });
return this.resources.replacements(). return this.resources.replacements().then(() => {
then(() => {
return this.resources.replaceCss(); return this.resources.replaceCss();
}); });
} }
@ -719,7 +733,8 @@ class Book {
* @return {string} key * @return {string} key
*/ */
key(identifier) { key(identifier) {
var ident = identifier || this.packaging.metadata.identifier || this.url.filename; var ident =
identifier || this.packaging.metadata.identifier || this.url.filename;
return `epubjs:${EPUBJS_VERSION}:${ident}`; return `epubjs:${EPUBJS_VERSION}:${ident}`;
} }
@ -759,7 +774,6 @@ class Book {
this.path = undefined; this.path = undefined;
this.archived = false; this.archived = false;
} }
} }
//-- Enable binding events to book //-- Enable binding events to book

View file

@ -1,5 +1,5 @@
import path from "path-webpack"; import path from "path-webpack";
import {qs} from "./utils/core"; import { qs } from "./utils/core";
/** /**
* Handles Parsing and Accessing an Epub Container * Handles Parsing and Accessing an Epub Container
@ -8,9 +8,9 @@ import {qs} from "./utils/core";
*/ */
class Container { class Container {
constructor(containerDocument) { constructor(containerDocument) {
this.packagePath = ''; this.packagePath = "";
this.directory = ''; this.directory = "";
this.encoding = ''; this.encoding = "";
if (containerDocument) { if (containerDocument) {
this.parse(containerDocument); this.parse(containerDocument);
@ -21,17 +21,17 @@ class Container {
* Parse the Container XML * Parse the Container XML
* @param {document} containerDocument * @param {document} containerDocument
*/ */
parse(containerDocument){ parse(containerDocument) {
//-- <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/> //-- <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
var rootfile; var rootfile;
if(!containerDocument) { if (!containerDocument) {
throw new Error("Container File Not Found"); throw new Error("Container File Not Found");
} }
rootfile = qs(containerDocument, "rootfile"); rootfile = qs(containerDocument, "rootfile");
if(!rootfile) { if (!rootfile) {
throw new Error("No RootFile Found"); throw new Error("No RootFile Found");
} }

View file

@ -1,17 +1,17 @@
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import {isNumber, prefixed, borders, defaults} from "./utils/core";
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import Mapping from "./mapping"; import Mapping from "./mapping";
import {replaceLinks} from "./utils/replacements"; import { DOM_EVENTS, EPUBJS_VERSION, EVENTS } from "./utils/constants";
import { EPUBJS_VERSION, EVENTS, DOM_EVENTS } from "./utils/constants"; import { borders, defaults, isNumber, prefixed } from "./utils/core";
import { replaceLinks } from "./utils/replacements";
const hasNavigator = typeof (navigator) !== "undefined"; const hasNavigator = typeof navigator !== "undefined";
const isChrome = hasNavigator && /Chrome/.test(navigator.userAgent); const isChrome = hasNavigator && /Chrome/.test(navigator.userAgent);
const isWebkit = hasNavigator && !isChrome && /AppleWebKit/.test(navigator.userAgent); const isWebkit =
hasNavigator && !isChrome && /AppleWebKit/.test(navigator.userAgent);
const ELEMENT_NODE = 1; const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
/** /**
* Handles DOM manipulation, queries and events for View contents * Handles DOM manipulation, queries and events for View contents
@ -33,7 +33,7 @@ class Contents {
this._size = { this._size = {
width: 0, width: 0,
height: 0 height: 0,
}; };
this.sectionIndex = sectionIndex || 0; this.sectionIndex = sectionIndex || 0;
@ -71,8 +71,6 @@ class Contents {
} }
return parseInt(this.window.getComputedStyle(frame)["width"]); return parseInt(this.window.getComputedStyle(frame)["width"]);
} }
/** /**
@ -94,7 +92,6 @@ class Contents {
} }
return parseInt(this.window.getComputedStyle(frame)["height"]); return parseInt(this.window.getComputedStyle(frame)["height"]);
} }
/** /**
@ -103,7 +100,6 @@ class Contents {
* @returns {number} width * @returns {number} width
*/ */
contentWidth(w) { contentWidth(w) {
var content = this.content || this.document.body; var content = this.content || this.document.body;
if (w && isNumber(w)) { if (w && isNumber(w)) {
@ -115,8 +111,6 @@ class Contents {
} }
return parseInt(this.window.getComputedStyle(content)["width"]); return parseInt(this.window.getComputedStyle(content)["width"]);
} }
/** /**
@ -125,7 +119,6 @@ class Contents {
* @returns {number} height * @returns {number} height
*/ */
contentHeight(h) { contentHeight(h) {
var content = this.content || this.document.body; var content = this.content || this.document.body;
if (h && isNumber(h)) { if (h && isNumber(h)) {
@ -137,7 +130,6 @@ class Contents {
} }
return parseInt(this.window.getComputedStyle(content)["height"]); return parseInt(this.window.getComputedStyle(content)["height"]);
} }
/** /**
@ -208,7 +200,6 @@ class Contents {
* @param {string} [overflow] * @param {string} [overflow]
*/ */
overflow(overflow) { overflow(overflow) {
if (overflow) { if (overflow) {
this.documentElement.style.overflow = overflow; this.documentElement.style.overflow = overflow;
} }
@ -221,7 +212,6 @@ class Contents {
* @param {string} [overflow] * @param {string} [overflow]
*/ */
overflowX(overflow) { overflowX(overflow) {
if (overflow) { if (overflow) {
this.documentElement.style.overflowX = overflow; this.documentElement.style.overflowX = overflow;
} }
@ -234,7 +224,6 @@ class Contents {
* @param {string} [overflow] * @param {string} [overflow]
*/ */
overflowY(overflow) { overflowY(overflow) {
if (overflow) { if (overflow) {
this.documentElement.style.overflowY = overflow; this.documentElement.style.overflowY = overflow;
} }
@ -271,16 +260,15 @@ class Contents {
* @param {string} [options.scalable] * @param {string} [options.scalable]
*/ */
viewport(options) { viewport(options) {
var _width, _height, _scale, _minimum, _maximum, _scalable;
// var width, height, scale, minimum, maximum, scalable; // var width, height, scale, minimum, maximum, scalable;
var $viewport = this.document.querySelector("meta[name='viewport']"); var $viewport = this.document.querySelector("meta[name='viewport']");
var parsed = { var parsed = {
"width": undefined, width: undefined,
"height": undefined, height: undefined,
"scale": undefined, scale: undefined,
"minimum": undefined, minimum: undefined,
"maximum": undefined, maximum: undefined,
"scalable": undefined scalable: undefined,
}; };
var newContent = []; var newContent = [];
var settings = {}; var settings = {};
@ -289,7 +277,7 @@ class Contents {
* check for the viewport size * check for the viewport size
* <meta name="viewport" content="width=1024,height=697" /> * <meta name="viewport" content="width=1024,height=697" />
*/ */
if($viewport && $viewport.hasAttribute("content")) { if ($viewport && $viewport.hasAttribute("content")) {
let content = $viewport.getAttribute("content"); let content = $viewport.getAttribute("content");
let _width = content.match(/width\s*=\s*([^,]*)/); let _width = content.match(/width\s*=\s*([^,]*)/);
let _height = content.match(/height\s*=\s*([^,]*)/); let _height = content.match(/height\s*=\s*([^,]*)/);
@ -298,22 +286,26 @@ class Contents {
let _maximum = content.match(/maximum-scale\s*=\s*([^,]*)/); let _maximum = content.match(/maximum-scale\s*=\s*([^,]*)/);
let _scalable = content.match(/user-scalable\s*=\s*([^,]*)/); let _scalable = content.match(/user-scalable\s*=\s*([^,]*)/);
if(_width && _width.length && typeof _width[1] !== "undefined"){ if (_width && _width.length && typeof _width[1] !== "undefined") {
parsed.width = _width[1]; parsed.width = _width[1];
} }
if(_height && _height.length && typeof _height[1] !== "undefined"){ if (_height && _height.length && typeof _height[1] !== "undefined") {
parsed.height = _height[1]; parsed.height = _height[1];
} }
if(_scale && _scale.length && typeof _scale[1] !== "undefined"){ if (_scale && _scale.length && typeof _scale[1] !== "undefined") {
parsed.scale = _scale[1]; parsed.scale = _scale[1];
} }
if(_minimum && _minimum.length && typeof _minimum[1] !== "undefined"){ if (_minimum && _minimum.length && typeof _minimum[1] !== "undefined") {
parsed.minimum = _minimum[1]; parsed.minimum = _minimum[1];
} }
if(_maximum && _maximum.length && typeof _maximum[1] !== "undefined"){ if (_maximum && _maximum.length && typeof _maximum[1] !== "undefined") {
parsed.maximum = _maximum[1]; parsed.maximum = _maximum[1];
} }
if(_scalable && _scalable.length && typeof _scalable[1] !== "undefined"){ if (
_scalable &&
_scalable.length &&
typeof _scalable[1] !== "undefined"
) {
parsed.scalable = _scalable[1]; parsed.scalable = _scalable[1];
} }
} }
@ -338,7 +330,6 @@ class Contents {
newContent.push("maximum-scale=" + settings.scale); newContent.push("maximum-scale=" + settings.scale);
newContent.push("user-scalable=" + settings.scalable); newContent.push("user-scalable=" + settings.scalable);
} else { } else {
if (settings.scalable) { if (settings.scalable) {
newContent.push("user-scalable=" + settings.scalable); newContent.push("user-scalable=" + settings.scalable);
} }
@ -363,7 +354,6 @@ class Contents {
this.window.scrollTo(0, 0); this.window.scrollTo(0, 0);
} }
return settings; return settings;
} }
@ -409,7 +399,6 @@ class Contents {
* @private * @private
*/ */
removeListeners() { removeListeners() {
this.removeEventListeners(); this.removeEventListeners();
this.removeSelectionListeners(); this.removeSelectionListeners();
@ -431,10 +420,9 @@ class Contents {
let height = this.textHeight(); let height = this.textHeight();
if (width != this._size.width || height != this._size.height) { if (width != this._size.width || height != this._size.height) {
this._size = { this._size = {
width: width, width: width,
height: height height: height,
}; };
this.onResize && this.onResize(this._size); this.onResize && this.onResize(this._size);
@ -447,7 +435,6 @@ class Contents {
* @private * @private
*/ */
resizeListeners() { resizeListeners() {
var width, height;
// Test size again // Test size again
clearTimeout(this.expanding); clearTimeout(this.expanding);
requestAnimationFrame(this.resizeCheck.bind(this)); requestAnimationFrame(this.resizeCheck.bind(this));
@ -477,13 +464,14 @@ class Contents {
transitionListeners() { transitionListeners() {
let body = this.content; let body = this.content;
body.style['transitionProperty'] = "font, font-size, font-size-adjust, font-stretch, font-variation-settings, font-weight, width, height"; body.style["transitionProperty"] =
body.style['transitionDuration'] = "0.001ms"; "font, font-size, font-size-adjust, font-stretch, font-variation-settings, font-weight, width, height";
body.style['transitionTimingFunction'] = "linear"; body.style["transitionDuration"] = "0.001ms";
body.style['transitionDelay'] = "0"; body.style["transitionTimingFunction"] = "linear";
body.style["transitionDelay"] = "0";
this._resizeCheck = this.resizeCheck.bind(this); this._resizeCheck = this.resizeCheck.bind(this);
this.document.addEventListener('transitionend', this._resizeCheck); this.document.addEventListener("transitionend", this._resizeCheck);
} }
/** /**
@ -493,8 +481,8 @@ class Contents {
*/ */
mediaQueryListeners() { mediaQueryListeners() {
var sheets = this.document.styleSheets; var sheets = this.document.styleSheets;
var mediaChangeHandler = function(m){ var mediaChangeHandler = function (m) {
if(m.matches && !this._expanding) { if (m.matches && !this._expanding) {
setTimeout(this.expand.bind(this), 1); setTimeout(this.expand.bind(this), 1);
} }
}.bind(this); }.bind(this);
@ -507,10 +495,10 @@ class Contents {
} catch (e) { } catch (e) {
return; return;
} }
if(!rules) return; // Stylesheets changed if (!rules) return; // Stylesheets changed
for (var j = 0; j < rules.length; j += 1) { for (var j = 0; j < rules.length; j += 1) {
//if (rules[j].constructor === CSSMediaRule) { //if (rules[j].constructor === CSSMediaRule) {
if(rules[j].media){ if (rules[j].media) {
var mql = this.window.matchMedia(rules[j].media.mediaText); var mql = this.window.matchMedia(rules[j].media.mediaText);
mql.addListener(mediaChangeHandler); mql.addListener(mediaChangeHandler);
//mql.onchange = mediaChangeHandler; //mql.onchange = mediaChangeHandler;
@ -544,7 +532,12 @@ class Contents {
}); });
// configuration of the observer: // configuration of the observer:
let config = { attributes: true, childList: true, characterData: true, subtree: true }; let config = {
attributes: true,
childList: true,
characterData: true,
subtree: true,
};
// pass in the target node, as well as the observer options // pass in the target node, as well as the observer options
this.observer.observe(this.document, config); this.observer.observe(this.document, config);
@ -560,8 +553,7 @@ class Contents {
for (var i = 0; i < images.length; i++) { for (var i = 0; i < images.length; i++) {
img = images[i]; img = images[i];
if (typeof img.naturalWidth !== "undefined" && if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
img.naturalWidth === 0) {
img.onload = this.expand.bind(this); img.onload = this.expand.bind(this);
} }
} }
@ -576,10 +568,11 @@ class Contents {
return; return;
} }
this.document.fonts.ready.then(function () { this.document.fonts.ready.then(
function () {
this.resizeCheck(); this.resizeCheck();
}.bind(this)); }.bind(this)
);
} }
/** /**
@ -587,7 +580,7 @@ class Contents {
* @returns {element} documentElement * @returns {element} documentElement
*/ */
root() { root() {
if(!this.document) return null; if (!this.document) return null;
return this.document.documentElement; return this.document.documentElement;
} }
@ -599,30 +592,38 @@ class Contents {
*/ */
locationOf(target, ignoreClass) { locationOf(target, ignoreClass) {
var position; var position;
var targetPos = {"left": 0, "top": 0}; var targetPos = { left: 0, top: 0 };
if(!this.document) return targetPos; if (!this.document) return targetPos;
if(this.epubcfi.isCfiString(target)) { if (this.epubcfi.isCfiString(target)) {
let range = new EpubCFI(target).toRange(this.document, ignoreClass); let range = new EpubCFI(target).toRange(this.document, ignoreClass);
if(range) { if (range) {
try { try {
if (!range.endContainer || if (
(range.startContainer == range.endContainer !range.endContainer ||
&& range.startOffset == range.endOffset)) { (range.startContainer == range.endContainer &&
range.startOffset == range.endOffset)
) {
// If the end for the range is not set, it results in collapsed becoming // If the end for the range is not set, it results in collapsed becoming
// true. This in turn leads to inconsistent behaviour when calling // true. This in turn leads to inconsistent behaviour when calling
// getBoundingRect. Wrong bounds lead to the wrong page being displayed. // getBoundingRect. Wrong bounds lead to the wrong page being displayed.
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/15684911/ // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/15684911/
let pos = range.startContainer.textContent.indexOf(" ", range.startOffset); let pos = range.startContainer.textContent.indexOf(
" ",
range.startOffset
);
if (pos == -1) { if (pos == -1) {
pos = range.startContainer.textContent.length; pos = range.startContainer.textContent.length;
} }
range.setEnd(range.startContainer, pos); range.setEnd(range.startContainer, pos);
} }
} catch (e) { } catch (e) {
console.error("setting end offset to start container length failed", e); console.error(
"setting end offset to start container length failed",
e
);
} }
if (range.startContainer.nodeType === Node.ELEMENT_NODE) { if (range.startContainer.nodeType === Node.ELEMENT_NODE) {
@ -648,7 +649,8 @@ class Contents {
newRange.setStart(container, range.startOffset - 2); newRange.setStart(container, range.startOffset - 2);
newRange.setEnd(container, range.startOffset); newRange.setEnd(container, range.startOffset);
position = newRange.getBoundingClientRect(); position = newRange.getBoundingClientRect();
} else { // empty, return the parent element } else {
// empty, return the parent element
position = container.parentNode.getBoundingClientRect(); position = container.parentNode.getBoundingClientRect();
} }
} catch (e) { } catch (e) {
@ -659,13 +661,10 @@ class Contents {
} }
} }
} }
} else if (typeof target === "string" && target.indexOf("#") > -1) {
} else if(typeof target === "string" && let id = target.substring(target.indexOf("#") + 1);
target.indexOf("#") > -1) {
let id = target.substring(target.indexOf("#")+1);
let el = this.document.getElementById(id); let el = this.document.getElementById(id);
if(el) { if (el) {
if (isWebkit) { if (isWebkit) {
// Webkit reports incorrect bounding rects in Columns // Webkit reports incorrect bounding rects in Columns
let newRange = new Range(); let newRange = new Range();
@ -690,17 +689,18 @@ class Contents {
* @param {string} src url * @param {string} src url
*/ */
addStylesheet(src) { addStylesheet(src) {
return new Promise(function(resolve, reject){ return new Promise(
function (resolve, reject) {
var $stylesheet; var $stylesheet;
var ready = false; var ready = false;
if(!this.document) { if (!this.document) {
resolve(false); resolve(false);
return; return;
} }
// Check if link already exists // Check if link already exists
$stylesheet = this.document.querySelector("link[href='"+src+"']"); $stylesheet = this.document.querySelector("link[href='" + src + "']");
if ($stylesheet) { if ($stylesheet) {
resolve(true); resolve(true);
return; // already present return; // already present
@ -710,8 +710,8 @@ class Contents {
$stylesheet.type = "text/css"; $stylesheet.type = "text/css";
$stylesheet.rel = "stylesheet"; $stylesheet.rel = "stylesheet";
$stylesheet.href = src; $stylesheet.href = src;
$stylesheet.onload = $stylesheet.onreadystatechange = function() { $stylesheet.onload = $stylesheet.onreadystatechange = function () {
if ( !ready && (!this.readyState || this.readyState == "complete") ) { if (!ready && (!this.readyState || this.readyState == "complete")) {
ready = true; ready = true;
// Let apply // Let apply
setTimeout(() => { setTimeout(() => {
@ -721,15 +721,15 @@ class Contents {
}; };
this.document.head.appendChild($stylesheet); this.document.head.appendChild($stylesheet);
}.bind(this)
}.bind(this)); );
} }
_getStylesheetNode(key) { _getStylesheetNode(key) {
var styleEl; var styleEl;
key = "epubjs-inserted-css-" + (key || ''); key = "epubjs-inserted-css-" + (key || "");
if(!this.document) return false; if (!this.document) return false;
// Check if link already exists // Check if link already exists
styleEl = this.document.getElementById(key); styleEl = this.document.getElementById(key);
@ -748,7 +748,7 @@ class Contents {
* @param {string} key If the key is the same, the CSS will be replaced instead of inserted * @param {string} key If the key is the same, the CSS will be replaced instead of inserted
*/ */
addStylesheetCss(serializedCss, key) { addStylesheetCss(serializedCss, key) {
if(!this.document || !serializedCss) return false; if (!this.document || !serializedCss) return false;
var styleEl; var styleEl;
styleEl = this._getStylesheetNode(key); styleEl = this._getStylesheetNode(key);
@ -767,14 +767,17 @@ class Contents {
addStylesheetRules(rules, key) { addStylesheetRules(rules, key) {
var styleSheet; var styleSheet;
if(!this.document || !rules || rules.length === 0) return; if (!this.document || !rules || rules.length === 0) return;
// Grab style sheet // Grab style sheet
styleSheet = this._getStylesheetNode(key).sheet; styleSheet = this._getStylesheetNode(key).sheet;
if (Object.prototype.toString.call(rules) === "[object Array]") { if (Object.prototype.toString.call(rules) === "[object Array]") {
for (var i = 0, rl = rules.length; i < rl; i++) { for (var i = 0, rl = rules.length; i < rl; i++) {
var j = 1, rule = rules[i], selector = rules[i][0], propStr = ""; var j = 1,
rule = rules[i],
selector = rules[i][0],
propStr = "";
// If the second argument of a rule is an array of arrays, correct our variables. // If the second argument of a rule is an array of arrays, correct our variables.
if (Object.prototype.toString.call(rule[1][0]) === "[object Array]") { if (Object.prototype.toString.call(rule[1][0]) === "[object Array]") {
rule = rule[1]; rule = rule[1];
@ -783,11 +786,15 @@ class Contents {
for (var pl = rule.length; j < pl; j++) { for (var pl = rule.length; j < pl; j++) {
var prop = rule[j]; var prop = rule[j];
propStr += prop[0] + ":" + prop[1] + (prop[2] ? " !important" : "") + ";\n"; propStr +=
prop[0] + ":" + prop[1] + (prop[2] ? " !important" : "") + ";\n";
} }
// Insert CSS Rule // Insert CSS Rule
styleSheet.insertRule(selector + "{" + propStr + "}", styleSheet.cssRules.length); styleSheet.insertRule(
selector + "{" + propStr + "}",
styleSheet.cssRules.length
);
} }
} else { } else {
const selectors = Object.keys(rules); const selectors = Object.keys(rules);
@ -796,17 +803,27 @@ class Contents {
if (Array.isArray(definition)) { if (Array.isArray(definition)) {
definition.forEach((item) => { definition.forEach((item) => {
const _rules = Object.keys(item); const _rules = Object.keys(item);
const result = _rules.map((rule) => { const result = _rules
.map((rule) => {
return `${rule}:${item[rule]}`; return `${rule}:${item[rule]}`;
}).join(';'); })
styleSheet.insertRule(`${selector}{${result}}`, styleSheet.cssRules.length); .join(";");
styleSheet.insertRule(
`${selector}{${result}}`,
styleSheet.cssRules.length
);
}); });
} else { } else {
const _rules = Object.keys(definition); const _rules = Object.keys(definition);
const result = _rules.map((rule) => { const result = _rules
.map((rule) => {
return `${rule}:${definition[rule]}`; return `${rule}:${definition[rule]}`;
}).join(';'); })
styleSheet.insertRule(`${selector}{${result}}`, styleSheet.cssRules.length); .join(";");
styleSheet.insertRule(
`${selector}{${result}}`,
styleSheet.cssRules.length
);
} }
}); });
} }
@ -818,12 +835,12 @@ class Contents {
* @returns {Promise} loaded * @returns {Promise} loaded
*/ */
addScript(src) { addScript(src) {
return new Promise(
return new Promise(function(resolve, reject){ function (resolve, reject) {
var $script; var $script;
var ready = false; var ready = false;
if(!this.document) { if (!this.document) {
resolve(false); resolve(false);
return; return;
} }
@ -832,18 +849,18 @@ class Contents {
$script.type = "text/javascript"; $script.type = "text/javascript";
$script.async = true; $script.async = true;
$script.src = src; $script.src = src;
$script.onload = $script.onreadystatechange = function() { $script.onload = $script.onreadystatechange = function () {
if ( !ready && (!this.readyState || this.readyState == "complete") ) { if (!ready && (!this.readyState || this.readyState == "complete")) {
ready = true; ready = true;
setTimeout(function(){ setTimeout(function () {
resolve(true); resolve(true);
}, 1); }, 1);
} }
}; };
this.document.head.appendChild($script); this.document.head.appendChild($script);
}.bind(this)
}.bind(this)); );
} }
/** /**
@ -853,14 +870,13 @@ class Contents {
addClass(className) { addClass(className) {
var content; var content;
if(!this.document) return; if (!this.document) return;
content = this.content || this.document.body; content = this.content || this.document.body;
if (content) { if (content) {
content.classList.add(className); content.classList.add(className);
} }
} }
/** /**
@ -870,43 +886,45 @@ class Contents {
removeClass(className) { removeClass(className) {
var content; var content;
if(!this.document) return; if (!this.document) return;
content = this.content || this.document.body; content = this.content || this.document.body;
if (content) { if (content) {
content.classList.remove(className); content.classList.remove(className);
} }
} }
/** /**
* Add DOM event listeners * Add DOM event listeners
* @private * @private
*/ */
addEventListeners(){ addEventListeners() {
if(!this.document) { if (!this.document) {
return; return;
} }
this._triggerEvent = this.triggerEvent.bind(this); this._triggerEvent = this.triggerEvent.bind(this);
DOM_EVENTS.forEach(function(eventName){ DOM_EVENTS.forEach(function (eventName) {
this.document.addEventListener(eventName, this._triggerEvent, { passive: true }); this.document.addEventListener(eventName, this._triggerEvent, {
passive: true,
});
}, this); }, this);
} }
/** /**
* Remove DOM event listeners * Remove DOM event listeners
* @private * @private
*/ */
removeEventListeners(){ removeEventListeners() {
if(!this.document) { if (!this.document) {
return; return;
} }
DOM_EVENTS.forEach(function(eventName){ DOM_EVENTS.forEach(function (eventName) {
this.document.removeEventListener(eventName, this._triggerEvent, { passive: true }); this.document.removeEventListener(eventName, this._triggerEvent, {
passive: true,
});
}, this); }, this);
this._triggerEvent = undefined; this._triggerEvent = undefined;
} }
@ -915,7 +933,7 @@ class Contents {
* Emit passed browser events * Emit passed browser events
* @private * @private
*/ */
triggerEvent(e){ triggerEvent(e) {
this.emit(e.type, e); this.emit(e.type, e);
} }
@ -923,23 +941,29 @@ class Contents {
* Add listener for text selection * Add listener for text selection
* @private * @private
*/ */
addSelectionListeners(){ addSelectionListeners() {
if(!this.document) { if (!this.document) {
return; return;
} }
this._onSelectionChange = this.onSelectionChange.bind(this); this._onSelectionChange = this.onSelectionChange.bind(this);
this.document.addEventListener("selectionchange", this._onSelectionChange, { passive: true }); this.document.addEventListener("selectionchange", this._onSelectionChange, {
passive: true,
});
} }
/** /**
* Remove listener for text selection * Remove listener for text selection
* @private * @private
*/ */
removeSelectionListeners(){ removeSelectionListeners() {
if(!this.document) { if (!this.document) {
return; return;
} }
this.document.removeEventListener("selectionchange", this._onSelectionChange, { passive: true }); this.document.removeEventListener(
"selectionchange",
this._onSelectionChange,
{ passive: true }
);
this._onSelectionChange = undefined; this._onSelectionChange = undefined;
} }
@ -947,26 +971,29 @@ class Contents {
* Handle getting text on selection * Handle getting text on selection
* @private * @private
*/ */
onSelectionChange(e){ onSelectionChange(e) {
if (this.selectionEndTimeout) { if (this.selectionEndTimeout) {
clearTimeout(this.selectionEndTimeout); clearTimeout(this.selectionEndTimeout);
} }
this.selectionEndTimeout = setTimeout(function() { this.selectionEndTimeout = setTimeout(
function () {
var selection = this.window.getSelection(); var selection = this.window.getSelection();
this.triggerSelectedEvent(selection); this.triggerSelectedEvent(selection);
}.bind(this), 250); }.bind(this),
250
);
} }
/** /**
* Emit event on text selection * Emit event on text selection
* @private * @private
*/ */
triggerSelectedEvent(selection){ triggerSelectedEvent(selection) {
var range, cfirange; var range, cfirange;
if (selection && selection.rangeCount > 0) { if (selection && selection.rangeCount > 0) {
range = selection.getRangeAt(0); range = selection.getRangeAt(0);
if(!range.collapsed) { if (!range.collapsed) {
// cfirange = this.section.cfiFromRange(range); // cfirange = this.section.cfiFromRange(range);
cfirange = new EpubCFI(range, this.cfiBase).toString(); cfirange = new EpubCFI(range, this.cfiBase).toString();
this.emit(EVENTS.CONTENTS.SELECTED, cfirange); this.emit(EVENTS.CONTENTS.SELECTED, cfirange);
@ -981,7 +1008,7 @@ class Contents {
* @param {string} [ignoreClass] * @param {string} [ignoreClass]
* @returns {Range} range * @returns {Range} range
*/ */
range(_cfi, ignoreClass){ range(_cfi, ignoreClass) {
var cfi = new EpubCFI(_cfi); var cfi = new EpubCFI(_cfi);
return cfi.toRange(this.document, ignoreClass); return cfi.toRange(this.document, ignoreClass);
} }
@ -992,7 +1019,7 @@ class Contents {
* @param {string} [ignoreClass] * @param {string} [ignoreClass]
* @returns {EpubCFI} cfi * @returns {EpubCFI} cfi
*/ */
cfiFromRange(range, ignoreClass){ cfiFromRange(range, ignoreClass) {
return new EpubCFI(range, this.cfiBase, ignoreClass).toString(); return new EpubCFI(range, this.cfiBase, ignoreClass).toString();
} }
@ -1002,12 +1029,12 @@ class Contents {
* @param {string} [ignoreClass] * @param {string} [ignoreClass]
* @returns {EpubCFI} cfi * @returns {EpubCFI} cfi
*/ */
cfiFromNode(node, ignoreClass){ cfiFromNode(node, ignoreClass) {
return new EpubCFI(node, this.cfiBase, ignoreClass).toString(); return new EpubCFI(node, this.cfiBase, ignoreClass).toString();
} }
// TODO: find where this is used - remove? // TODO: find where this is used - remove?
map(layout){ map(layout) {
var map = new Mapping(layout); var map = new Mapping(layout);
return map.section(); return map.section();
} }
@ -1017,7 +1044,7 @@ class Contents {
* @param {number} [width] * @param {number} [width]
* @param {number} [height] * @param {number} [height]
*/ */
size(width, height){ size(width, height) {
var viewport = { scale: 1.0, scalable: "no" }; var viewport = { scale: 1.0, scalable: "no" };
this.layoutStyle("scrolling"); this.layoutStyle("scrolling");
@ -1025,7 +1052,7 @@ class Contents {
if (width >= 0) { if (width >= 0) {
this.width(width); this.width(width);
viewport.width = width; viewport.width = width;
this.css("padding", "0 "+(width/12)+"px"); this.css("padding", "0 " + width / 12 + "px");
} }
if (height >= 0) { if (height >= 0) {
@ -1036,7 +1063,6 @@ class Contents {
this.css("margin", "0"); this.css("margin", "0");
this.css("box-sizing", "border-box"); this.css("box-sizing", "border-box");
this.viewport(viewport); this.viewport(viewport);
} }
@ -1047,14 +1073,15 @@ class Contents {
* @param {number} columnWidth * @param {number} columnWidth
* @param {number} gap * @param {number} gap
*/ */
columns(width, height, columnWidth, gap, dir){ columns(width, height, columnWidth, gap, dir) {
let COLUMN_AXIS = prefixed("column-axis"); let COLUMN_AXIS = prefixed("column-axis");
let COLUMN_GAP = prefixed("column-gap"); let COLUMN_GAP = prefixed("column-gap");
let COLUMN_WIDTH = prefixed("column-width"); let COLUMN_WIDTH = prefixed("column-width");
let COLUMN_FILL = prefixed("column-fill"); let COLUMN_FILL = prefixed("column-fill");
let writingMode = this.writingMode(); let writingMode = this.writingMode();
let axis = (writingMode.indexOf("vertical") === 0) ? "vertical" : "horizontal"; let axis =
writingMode.indexOf("vertical") === 0 ? "vertical" : "horizontal";
this.layoutStyle("paginated"); this.layoutStyle("paginated");
@ -1076,16 +1103,16 @@ class Contents {
this.css("margin", "0", true); this.css("margin", "0", true);
if (axis === "vertical") { if (axis === "vertical") {
this.css("padding-top", (gap / 2) + "px", true); this.css("padding-top", gap / 2 + "px", true);
this.css("padding-bottom", (gap / 2) + "px", true); this.css("padding-bottom", gap / 2 + "px", true);
this.css("padding-left", "20px"); this.css("padding-left", "20px");
this.css("padding-right", "20px"); this.css("padding-right", "20px");
this.css(COLUMN_AXIS, "vertical"); this.css(COLUMN_AXIS, "vertical");
} else { } else {
this.css("padding-top", "20px"); this.css("padding-top", "20px");
this.css("padding-bottom", "20px"); this.css("padding-bottom", "20px");
this.css("padding-left", (gap / 2) + "px", true); this.css("padding-left", gap / 2 + "px", true);
this.css("padding-right", (gap / 2) + "px", true); this.css("padding-right", gap / 2 + "px", true);
this.css(COLUMN_AXIS, "horizontal"); this.css(COLUMN_AXIS, "horizontal");
} }
@ -1094,8 +1121,8 @@ class Contents {
this.css(COLUMN_FILL, "auto"); this.css(COLUMN_FILL, "auto");
this.css(COLUMN_GAP, gap+"px"); this.css(COLUMN_GAP, gap + "px");
this.css(COLUMN_WIDTH, columnWidth+"px"); this.css(COLUMN_WIDTH, columnWidth + "px");
// Fix glyph clipping in WebKit // Fix glyph clipping in WebKit
// https://github.com/futurepress/epub.js/issues/983 // https://github.com/futurepress/epub.js/issues/983
@ -1108,14 +1135,15 @@ class Contents {
* @param {number} offsetX * @param {number} offsetX
* @param {number} offsetY * @param {number} offsetY
*/ */
scaler(scale, offsetX, offsetY){ scaler(scale, offsetX, offsetY) {
var scaleStr = "scale(" + scale + ")"; var scaleStr = "scale(" + scale + ")";
var translateStr = ""; var translateStr = "";
// this.css("position", "absolute")); // this.css("position", "absolute"));
this.css("transform-origin", "top left"); this.css("transform-origin", "top left");
if (offsetX >= 0 || offsetY >= 0) { if (offsetX >= 0 || offsetY >= 0) {
translateStr = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )"; translateStr =
" translate(" + (offsetX || 0) + "px, " + (offsetY || 0) + "px )";
} }
this.css("transform", scaleStr + translateStr); this.css("transform", scaleStr + translateStr);
@ -1126,7 +1154,7 @@ class Contents {
* @param {number} width * @param {number} width
* @param {number} height * @param {number} height
*/ */
fit(width, height, section){ fit(width, height, section) {
var viewport = this.viewport(); var viewport = this.viewport();
var viewportWidth = parseInt(viewport.width); var viewportWidth = parseInt(viewport.width);
var viewportHeight = parseInt(viewport.height); var viewportHeight = parseInt(viewport.height);
@ -1153,12 +1181,15 @@ class Contents {
// this.scaler(scale, offsetX > 0 ? offsetX : 0, offsetY); // this.scaler(scale, offsetX > 0 ? offsetX : 0, offsetY);
// background images are not scaled by transform // background images are not scaled by transform
this.css("background-size", viewportWidth * scale + "px " + viewportHeight * scale + "px"); this.css(
"background-size",
viewportWidth * scale + "px " + viewportHeight * scale + "px"
);
this.css("background-color", "transparent"); this.css("background-color", "transparent");
if (section && section.properties.includes("page-spread-left")) { if (section && section.properties.includes("page-spread-left")) {
// set margin since scale is weird // set margin since scale is weird
var marginLeft = width - (viewportWidth * scale); var marginLeft = width - viewportWidth * scale;
this.css("margin-left", marginLeft + "px"); this.css("margin-left", marginLeft + "px");
} }
} }
@ -1200,7 +1231,9 @@ class Contents {
this.documentElement.style[WRITING_MODE] = mode; this.documentElement.style[WRITING_MODE] = mode;
} }
return this.window.getComputedStyle(this.documentElement)[WRITING_MODE] || ''; return (
this.window.getComputedStyle(this.documentElement)[WRITING_MODE] || ""
);
} }
/** /**
@ -1209,7 +1242,6 @@ class Contents {
* @private * @private
*/ */
layoutStyle(style) { layoutStyle(style) {
if (style) { if (style) {
this._layoutStyle = style; this._layoutStyle = style;
navigator.epubReadingSystem.layoutStyle = this._layoutStyle; navigator.epubReadingSystem.layoutStyle = this._layoutStyle;
@ -1246,7 +1278,7 @@ class Contents {
default: default:
return false; return false;
} }
} },
}; };
return navigator.epubReadingSystem; return navigator.epubReadingSystem;
} }
@ -1255,7 +1287,6 @@ class Contents {
// this.document.removeEventListener('transitionend', this._resizeCheck); // this.document.removeEventListener('transitionend', this._resizeCheck);
this.removeListeners(); this.removeListeners();
} }
} }

View file

@ -1,4 +1,4 @@
import {qs, qsa } from "./utils/core"; import { qs, qsa } from "./utils/core";
/** /**
* Open DisplayOptions Format Parser * Open DisplayOptions Format Parser
@ -23,12 +23,12 @@ class DisplayOptions {
* @return {DisplayOptions} self * @return {DisplayOptions} self
*/ */
parse(displayOptionsDocument) { parse(displayOptionsDocument) {
if(!displayOptionsDocument) { if (!displayOptionsDocument) {
return this; return this;
} }
const displayOptionsNode = qs(displayOptionsDocument, "display_options"); const displayOptionsNode = qs(displayOptionsDocument, "display_options");
if(!displayOptionsNode) { if (!displayOptionsNode) {
return this; return this;
} }

View file

@ -1,13 +1,9 @@
import Book from "./book"; import Book from "./book";
import Rendition from "./rendition";
import CFI from "./epubcfi";
import Contents from "./contents"; import Contents from "./contents";
import * as utils from "./utils/core"; import CFI from "./epubcfi";
import Rendition from "./rendition";
import { EPUBJS_VERSION } from "./utils/constants"; import { EPUBJS_VERSION } from "./utils/constants";
import * as utils from "./utils/core";
import IframeView from "./managers/views/iframe";
import DefaultViewManager from "./managers/default";
import ContinuousViewManager from "./managers/continuous";
/** /**
* Creates a new Book * Creates a new Book
@ -22,7 +18,7 @@ function ePub(url, options) {
ePub.VERSION = EPUBJS_VERSION; ePub.VERSION = EPUBJS_VERSION;
if (typeof(global) !== "undefined") { if (typeof global !== "undefined") {
global.EPUBJS_VERSION = EPUBJS_VERSION; global.EPUBJS_VERSION = EPUBJS_VERSION;
} }

View file

@ -1,8 +1,13 @@
import {extend, type, findChildren, RangeObject, isNumber} from "./utils/core"; import {
RangeObject,
extend,
findChildren,
isNumber,
type,
} from "./utils/core";
const ELEMENT_NODE = 1; const ELEMENT_NODE = 1;
const TEXT_NODE = 3; const TEXT_NODE = 3;
const COMMENT_NODE = 8;
const DOCUMENT_NODE = 9; const DOCUMENT_NODE = 9;
/** /**
@ -23,7 +28,7 @@ const DOCUMENT_NODE = 9;
@param {string} [ignoreClass] class to ignore when parsing DOM @param {string} [ignoreClass] class to ignore when parsing DOM
*/ */
class EpubCFI { class EpubCFI {
constructor(cfiFrom, base, ignoreClass){ constructor(cfiFrom, base, ignoreClass) {
var type; var type;
this.str = ""; this.str = "";
@ -42,16 +47,15 @@ class EpubCFI {
return new EpubCFI(cfiFrom, base, ignoreClass); return new EpubCFI(cfiFrom, base, ignoreClass);
} }
if(typeof base === "string") { if (typeof base === "string") {
this.base = this.parseComponent(base); this.base = this.parseComponent(base);
} else if(typeof base === "object" && base.steps) { } else if (typeof base === "object" && base.steps) {
this.base = base; this.base = base;
} }
type = this.checkType(cfiFrom); type = this.checkType(cfiFrom);
if (type === "string") {
if(type === "string") {
this.str = cfiFrom; this.str = cfiFrom;
return extend(this, this.parse(cfiFrom)); return extend(this, this.parse(cfiFrom));
} else if (type === "range") { } else if (type === "range") {
@ -65,7 +69,6 @@ class EpubCFI {
} else { } else {
throw new TypeError("not a valid argument for EpubCFI"); throw new TypeError("not a valid argument for EpubCFI");
} }
} }
/** /**
@ -73,15 +76,23 @@ class EpubCFI {
* @private * @private
*/ */
checkType(cfi) { checkType(cfi) {
if (this.isCfiString(cfi)) { if (this.isCfiString(cfi)) {
return "string"; return "string";
// Is a range object // Is a range object
} else if (cfi && typeof cfi === "object" && (type(cfi) === "Range" || typeof(cfi.startContainer) != "undefined")){ } else if (
cfi &&
typeof cfi === "object" &&
(type(cfi) === "Range" || typeof cfi.startContainer != "undefined")
) {
return "range"; return "range";
} else if (cfi && typeof cfi === "object" && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === "function" } else if (
cfi &&
typeof cfi === "object" &&
typeof cfi.nodeType != "undefined"
) {
// || typeof cfi === "function"
return "node"; return "node";
} else if (cfi && typeof cfi === "object" && cfi instanceof EpubCFI){ } else if (cfi && typeof cfi === "object" && cfi instanceof EpubCFI) {
return "EpubCFI"; return "EpubCFI";
} else { } else {
return false; return false;
@ -100,24 +111,24 @@ class EpubCFI {
base: {}, base: {},
path: {}, path: {},
start: null, start: null,
end: null end: null,
}; };
var baseComponent, pathComponent, range; var baseComponent, pathComponent, range;
if(typeof cfiStr !== "string") { if (typeof cfiStr !== "string") {
return {spinePos: -1}; return { spinePos: -1 };
} }
if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") { if (cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length - 1] === ")") {
// Remove initial epubcfi( and ending ) // Remove initial epubcfi( and ending )
cfiStr = cfiStr.slice(8, cfiStr.length-1); cfiStr = cfiStr.slice(8, cfiStr.length - 1);
} }
baseComponent = this.getChapterComponent(cfiStr); baseComponent = this.getChapterComponent(cfiStr);
// Make sure this is a valid cfi or return // Make sure this is a valid cfi or return
if(!baseComponent) { if (!baseComponent) {
return {spinePos: -1}; return { spinePos: -1 };
} }
cfi.base = this.parseComponent(baseComponent); cfi.base = this.parseComponent(baseComponent);
@ -127,7 +138,7 @@ class EpubCFI {
range = this.getRange(cfiStr); range = this.getRange(cfiStr);
if(range) { if (range) {
cfi.range = true; cfi.range = true;
cfi.start = this.parseComponent(range[0]); cfi.start = this.parseComponent(range[0]);
cfi.end = this.parseComponent(range[1]); cfi.end = this.parseComponent(range[1]);
@ -142,19 +153,19 @@ class EpubCFI {
return cfi; return cfi;
} }
parseComponent(componentStr){ parseComponent(componentStr) {
var component = { var component = {
steps: [], steps: [],
terminal: { terminal: {
offset: null, offset: null,
assertion: null assertion: null,
} },
}; };
var parts = componentStr.split(":"); var parts = componentStr.split(":");
var steps = parts[0].split("/"); var steps = parts[0].split("/");
var terminal; var terminal;
if(parts.length > 1) { if (parts.length > 1) {
terminal = parts[1]; terminal = parts[1];
component.terminal = this.parseTerminal(terminal); component.terminal = this.parseTerminal(terminal);
} }
@ -163,48 +174,51 @@ class EpubCFI {
steps.shift(); // Ignore the first slash steps.shift(); // Ignore the first slash
} }
component.steps = steps.map(function(step){ component.steps = steps.map(
function (step) {
return this.parseStep(step); return this.parseStep(step);
}.bind(this)); }.bind(this)
);
return component; return component;
} }
parseStep(stepStr){ parseStep(stepStr) {
var type, num, index, has_brackets, id; var type, num, index, has_brackets, id;
has_brackets = stepStr.match(/\[(.*)\]/); has_brackets = stepStr.match(/\[(.*)\]/);
if(has_brackets && has_brackets[1]){ if (has_brackets && has_brackets[1]) {
id = has_brackets[1]; id = has_brackets[1];
} }
//-- Check if step is a text node or element //-- Check if step is a text node or element
num = parseInt(stepStr); num = parseInt(stepStr);
if(isNaN(num)) { if (isNaN(num)) {
return; return;
} }
if(num % 2 === 0) { // Even = is an element if (num % 2 === 0) {
// Even = is an element
type = "element"; type = "element";
index = num / 2 - 1; index = num / 2 - 1;
} else { } else {
type = "text"; type = "text";
index = (num - 1 ) / 2; index = (num - 1) / 2;
} }
return { return {
"type" : type, type: type,
"index" : index, index: index,
"id" : id || null id: id || null,
}; };
} }
parseTerminal(termialStr){ parseTerminal(termialStr) {
var characterOffset, textLocationAssertion; var characterOffset, textLocationAssertion;
var assertion = termialStr.match(/\[(.*)\]/); var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){ if (assertion && assertion[1]) {
characterOffset = parseInt(termialStr.split("[")[0]); characterOffset = parseInt(termialStr.split("[")[0]);
textLocationAssertion = assertion[1]; textLocationAssertion = assertion[1];
} else { } else {
@ -216,39 +230,31 @@ class EpubCFI {
} }
return { return {
"offset": characterOffset, offset: characterOffset,
"assertion": textLocationAssertion assertion: textLocationAssertion,
}; };
} }
getChapterComponent(cfiStr) { getChapterComponent(cfiStr) {
var indirection = cfiStr.split("!"); var indirection = cfiStr.split("!");
return indirection[0]; return indirection[0];
} }
getPathComponent(cfiStr) { getPathComponent(cfiStr) {
var indirection = cfiStr.split("!"); var indirection = cfiStr.split("!");
if(indirection[1]) { if (indirection[1]) {
let ranges = indirection[1].split(","); let ranges = indirection[1].split(",");
return ranges[0]; return ranges[0];
} }
} }
getRange(cfiStr) { getRange(cfiStr) {
var ranges = cfiStr.split(","); var ranges = cfiStr.split(",");
if(ranges.length === 3){ if (ranges.length === 3) {
return [ return [ranges[1], ranges[2]];
ranges[1],
ranges[2]
];
} }
return false; return false;
@ -260,29 +266,29 @@ class EpubCFI {
} }
joinSteps(steps) { joinSteps(steps) {
if(!steps) { if (!steps) {
return ""; return "";
} }
return steps.map(function(part){ return steps
.map(function (part) {
var segment = ""; var segment = "";
if(part.type === "element") { if (part.type === "element") {
segment += (part.index + 1) * 2; segment += (part.index + 1) * 2;
} }
if(part.type === "text") { if (part.type === "text") {
segment += 1 + (2 * part.index); // TODO: double check that this is odd segment += 1 + 2 * part.index; // TODO: double check that this is odd
} }
if(part.id) { if (part.id) {
segment += "[" + part.id + "]"; segment += "[" + part.id + "]";
} }
return segment; return segment;
})
}).join("/"); .join("/");
} }
segmentString(segment) { segmentString(segment) {
@ -290,11 +296,11 @@ class EpubCFI {
segmentString += this.joinSteps(segment.steps); segmentString += this.joinSteps(segment.steps);
if(segment.terminal && segment.terminal.offset != null){ if (segment.terminal && segment.terminal.offset != null) {
segmentString += ":" + segment.terminal.offset; segmentString += ":" + segment.terminal.offset;
} }
if(segment.terminal && segment.terminal.assertion != null){ if (segment.terminal && segment.terminal.assertion != null) {
segmentString += "[" + segment.terminal.assertion + "]"; segmentString += "[" + segment.terminal.assertion + "]";
} }
@ -314,12 +320,12 @@ class EpubCFI {
cfiString += this.segmentString(this.path); cfiString += this.segmentString(this.path);
// Add Range, if present // Add Range, if present
if(this.range && this.start) { if (this.range && this.start) {
cfiString += ","; cfiString += ",";
cfiString += this.segmentString(this.start); cfiString += this.segmentString(this.start);
} }
if(this.range && this.end) { if (this.range && this.end) {
cfiString += ","; cfiString += ",";
cfiString += this.segmentString(this.end); cfiString += this.segmentString(this.end);
} }
@ -329,7 +335,6 @@ class EpubCFI {
return cfiString; return cfiString;
} }
/** /**
* Compare which of two CFIs is earlier in the text * Compare which of two CFIs is earlier in the text
* @returns {number} First is earlier = -1, Second is earlier = 1, They are equal = 0 * @returns {number} First is earlier = -1, Second is earlier = 1, They are equal = 0
@ -338,22 +343,17 @@ class EpubCFI {
var stepsA, stepsB; var stepsA, stepsB;
var terminalA, terminalB; var terminalA, terminalB;
var rangeAStartSteps, rangeAEndSteps; if (typeof cfiOne === "string") {
var rangeBEndSteps, rangeBEndSteps;
var rangeAStartTerminal, rangeAEndTerminal;
var rangeBStartTerminal, rangeBEndTerminal;
if(typeof cfiOne === "string") {
cfiOne = new EpubCFI(cfiOne); cfiOne = new EpubCFI(cfiOne);
} }
if(typeof cfiTwo === "string") { if (typeof cfiTwo === "string") {
cfiTwo = new EpubCFI(cfiTwo); cfiTwo = new EpubCFI(cfiTwo);
} }
// Compare Spine Positions // Compare Spine Positions
if(cfiOne.spinePos > cfiTwo.spinePos) { if (cfiOne.spinePos > cfiTwo.spinePos) {
return 1; return 1;
} }
if(cfiOne.spinePos < cfiTwo.spinePos) { if (cfiOne.spinePos < cfiTwo.spinePos) {
return -1; return -1;
} }
@ -375,31 +375,31 @@ class EpubCFI {
// Compare Each Step in the First item // Compare Each Step in the First item
for (var i = 0; i < stepsA.length; i++) { for (var i = 0; i < stepsA.length; i++) {
if(!stepsA[i]) { if (!stepsA[i]) {
return -1; return -1;
} }
if(!stepsB[i]) { if (!stepsB[i]) {
return 1; return 1;
} }
if(stepsA[i].index > stepsB[i].index) { if (stepsA[i].index > stepsB[i].index) {
return 1; return 1;
} }
if(stepsA[i].index < stepsB[i].index) { if (stepsA[i].index < stepsB[i].index) {
return -1; return -1;
} }
// Otherwise continue checking // Otherwise continue checking
} }
// All steps in First equal to Second and First is Less Specific // All steps in First equal to Second and First is Less Specific
if(stepsA.length < stepsB.length) { if (stepsA.length < stepsB.length) {
return -1; return -1;
} }
// Compare the character offset of the text node // Compare the character offset of the text node
if(terminalA.offset > terminalB.offset) { if (terminalA.offset > terminalB.offset) {
return 1; return 1;
} }
if(terminalA.offset < terminalB.offset) { if (terminalA.offset < terminalB.offset) {
return -1; return -1;
} }
@ -408,13 +408,13 @@ class EpubCFI {
} }
step(node) { step(node) {
var nodeType = (node.nodeType === TEXT_NODE) ? "text" : "element"; var nodeType = node.nodeType === TEXT_NODE ? "text" : "element";
return { return {
"id" : node.id, id: node.id,
"tagName" : node.tagName, tagName: node.tagName,
"type" : nodeType, type: nodeType,
"index" : this.position(node) index: this.position(node),
}; };
} }
@ -428,13 +428,13 @@ class EpubCFI {
} }
// Otherwise add the filter node in // Otherwise add the filter node in
nodeType = (filteredNode.nodeType === TEXT_NODE) ? "text" : "element"; nodeType = filteredNode.nodeType === TEXT_NODE ? "text" : "element";
return { return {
"id" : filteredNode.id, id: filteredNode.id,
"tagName" : filteredNode.tagName, tagName: filteredNode.tagName,
"type" : nodeType, type: nodeType,
"index" : this.filteredPosition(filteredNode, ignoreClass) index: this.filteredPosition(filteredNode, ignoreClass),
}; };
} }
@ -443,15 +443,17 @@ class EpubCFI {
steps: [], steps: [],
terminal: { terminal: {
offset: null, offset: null,
assertion: null assertion: null,
} },
}; };
var currentNode = node; var currentNode = node;
var step; var step;
while(currentNode && currentNode.parentNode && while (
currentNode.parentNode.nodeType != DOCUMENT_NODE) { currentNode &&
currentNode.parentNode &&
currentNode.parentNode.nodeType != DOCUMENT_NODE
) {
if (ignoreClass) { if (ignoreClass) {
step = this.filteredStep(currentNode, ignoreClass); step = this.filteredStep(currentNode, ignoreClass);
} else { } else {
@ -463,24 +465,20 @@ class EpubCFI {
} }
currentNode = currentNode.parentNode; currentNode = currentNode.parentNode;
} }
if (offset != null && offset >= 0) { if (offset != null && offset >= 0) {
segment.terminal.offset = offset; segment.terminal.offset = offset;
// Make sure we are getting to a textNode if there is an offset // Make sure we are getting to a textNode if there is an offset
if(segment.steps[segment.steps.length-1].type != "text") { if (segment.steps[segment.steps.length - 1].type != "text") {
segment.steps.push({ segment.steps.push({
"type" : "text", type: "text",
"index" : 0 index: 0,
}); });
} }
} }
return segment; return segment;
} }
@ -489,9 +487,11 @@ class EpubCFI {
return false; return false;
} }
if(stepA.index === stepB.index && if (
stepA.index === stepB.index &&
stepA.id === stepB.id && stepA.id === stepB.id &&
stepA.type === stepB.type) { stepA.type === stepB.type
) {
return true; return true;
} }
@ -511,7 +511,7 @@ class EpubCFI {
base: {}, base: {},
path: {}, path: {},
start: null, start: null,
end: null end: null,
}; };
var start = range.startContainer; var start = range.startContainer;
@ -524,10 +524,10 @@ class EpubCFI {
if (ignoreClass) { if (ignoreClass) {
// Tell pathTo if / what to ignore // Tell pathTo if / what to ignore
needsIgnoring = (start.ownerDocument.querySelector("." + ignoreClass) != null); needsIgnoring =
start.ownerDocument.querySelector("." + ignoreClass) != null;
} }
if (typeof base === "string") { if (typeof base === "string") {
cfi.base = this.parseComponent(base); cfi.base = this.parseComponent(base);
cfi.spinePos = cfi.base.steps[1].index; cfi.spinePos = cfi.base.steps[1].index;
@ -557,7 +557,7 @@ class EpubCFI {
// Create a new empty path // Create a new empty path
cfi.path = { cfi.path = {
steps: [], steps: [],
terminal: null terminal: null,
}; };
// Push steps that are shared between start and end to the common path // Push steps that are shared between start and end to the common path
@ -566,9 +566,9 @@ class EpubCFI {
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) { if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) {
if(i === len-1) { if (i === len - 1) {
// Last step is equal, check terminals // Last step is equal, check terminals
if(cfi.start.terminal === cfi.end.terminal) { if (cfi.start.terminal === cfi.end.terminal) {
// CFI's are equal // CFI's are equal
cfi.path.steps.push(cfi.start.steps[i]); cfi.path.steps.push(cfi.start.steps[i]);
// Not a range // Not a range
@ -577,7 +577,6 @@ class EpubCFI {
} else { } else {
cfi.path.steps.push(cfi.start.steps[i]); cfi.path.steps.push(cfi.start.steps[i]);
} }
} else { } else {
break; break;
} }
@ -605,7 +604,7 @@ class EpubCFI {
base: {}, base: {},
path: {}, path: {},
start: null, start: null,
end: null end: null,
}; };
if (typeof base === "string") { if (typeof base === "string") {
@ -652,7 +651,6 @@ class EpubCFI {
// Parent will be ignored on next step // Parent will be ignored on next step
return anchor; return anchor;
} }
} else if (needsIgnoring && !isText) { } else if (needsIgnoring && !isText) {
// Otherwise just skip the element node // Otherwise just skip the element node
return false; return false;
@ -660,7 +658,6 @@ class EpubCFI {
// No need to filter // No need to filter
return anchor; return anchor;
} }
} }
patchOffset(anchor, offset, ignoreClass) { patchOffset(anchor, offset, ignoreClass) {
@ -677,9 +674,9 @@ class EpubCFI {
} }
while (curr.previousSibling) { while (curr.previousSibling) {
if(curr.previousSibling.nodeType === ELEMENT_NODE) { if (curr.previousSibling.nodeType === ELEMENT_NODE) {
// Originally a text node, so join // Originally a text node, so join
if(curr.previousSibling.classList.contains(ignoreClass)){ if (curr.previousSibling.classList.contains(ignoreClass)) {
totalOffset += curr.previousSibling.textContent.length; totalOffset += curr.previousSibling.textContent.length;
} else { } else {
break; // Normal node, dont join break; // Normal node, dont join
@ -693,38 +690,36 @@ class EpubCFI {
} }
return totalOffset; return totalOffset;
} }
normalizedMap(children, nodeType, ignoreClass) { normalizedMap(children, nodeType, ignoreClass) {
var output = {}; var output = {};
var prevIndex = -1; var prevIndex = -1;
var i, len = children.length; var i,
len = children.length;
var currNodeType; var currNodeType;
var prevNodeType; var prevNodeType;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
currNodeType = children[i].nodeType; currNodeType = children[i].nodeType;
// Check if needs ignoring // Check if needs ignoring
if (currNodeType === ELEMENT_NODE && if (
children[i].classList.contains(ignoreClass)) { currNodeType === ELEMENT_NODE &&
children[i].classList.contains(ignoreClass)
) {
currNodeType = TEXT_NODE; currNodeType = TEXT_NODE;
} }
if (i > 0 && if (i > 0 && currNodeType === TEXT_NODE && prevNodeType === TEXT_NODE) {
currNodeType === TEXT_NODE &&
prevNodeType === TEXT_NODE) {
// join text nodes // join text nodes
output[i] = prevIndex; output[i] = prevIndex;
} else if (nodeType === currNodeType){ } else if (nodeType === currNodeType) {
prevIndex = prevIndex + 1; prevIndex = prevIndex + 1;
output[i] = prevIndex; output[i] = prevIndex;
} }
prevNodeType = currNodeType; prevNodeType = currNodeType;
} }
return output; return output;
@ -755,14 +750,13 @@ class EpubCFI {
} else { } else {
children = anchor.parentNode.childNodes; children = anchor.parentNode.childNodes;
// Inside an ignored node // Inside an ignored node
if(anchor.parentNode.classList.contains(ignoreClass)) { if (anchor.parentNode.classList.contains(ignoreClass)) {
anchor = anchor.parentNode; anchor = anchor.parentNode;
children = anchor.parentNode.childNodes; children = anchor.parentNode.childNodes;
} }
map = this.normalizedMap(children, TEXT_NODE, ignoreClass); map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
} }
index = Array.prototype.indexOf.call(children, anchor); index = Array.prototype.indexOf.call(children, anchor);
return map[index]; return map[index];
@ -771,12 +765,12 @@ class EpubCFI {
stepsToXpath(steps) { stepsToXpath(steps) {
var xpath = [".", "*"]; var xpath = [".", "*"];
steps.forEach(function(step){ steps.forEach(function (step) {
var position = step.index + 1; var position = step.index + 1;
if(step.id){ if (step.id) {
xpath.push("*[position()=" + position + " and @id='" + step.id + "']"); xpath.push("*[position()=" + position + " and @id='" + step.id + "']");
} else if(step.type === "text") { } else if (step.type === "text") {
xpath.push("text()[" + position + "]"); xpath.push("text()[" + position + "]");
} else { } else {
xpath.push("*[" + position + "]"); xpath.push("*[" + position + "]");
@ -786,7 +780,6 @@ class EpubCFI {
return xpath.join("/"); return xpath.join("/");
} }
/* /*
To get the last step if needed: To get the last step if needed:
@ -805,12 +798,12 @@ class EpubCFI {
stepsToQuerySelector(steps) { stepsToQuerySelector(steps) {
var query = ["html"]; var query = ["html"];
steps.forEach(function(step){ steps.forEach(function (step) {
var position = step.index + 1; var position = step.index + 1;
if(step.id){ if (step.id) {
query.push("#" + step.id); query.push("#" + step.id);
} else if(step.type === "text") { } else if (step.type === "text") {
// unsupported in querySelector // unsupported in querySelector
// query.push("text()[" + position + "]"); // query.push("text()[" + position + "]");
} else { } else {
@ -819,12 +812,12 @@ class EpubCFI {
}); });
return query.join(">"); return query.join(">");
} }
textNodes(container, ignoreClass) { textNodes(container, ignoreClass) {
return Array.prototype.slice.call(container.childNodes). return Array.prototype.slice
filter(function (node) { .call(container.childNodes)
.filter(function (node) {
if (node.nodeType === TEXT_NODE) { if (node.nodeType === TEXT_NODE) {
return true; return true;
} else if (ignoreClass && node.classList.contains(ignoreClass)) { } else if (ignoreClass && node.classList.contains(ignoreClass)) {
@ -845,26 +838,24 @@ class EpubCFI {
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
step = steps[i]; step = steps[i];
if(step.type === "element") { if (step.type === "element") {
//better to get a container using id as some times step.index may not be correct //better to get a container using id as some times step.index may not be correct
//For ex.https://github.com/futurepress/epub.js/issues/561 //For ex.https://github.com/futurepress/epub.js/issues/561
if(step.id) { if (step.id) {
container = doc.getElementById(step.id); container = doc.getElementById(step.id);
} } else {
else {
children = container.children || findChildren(container); children = container.children || findChildren(container);
container = children[step.index]; container = children[step.index];
} }
} else if(step.type === "text") { } else if (step.type === "text") {
container = this.textNodes(container, ignoreClass)[step.index]; container = this.textNodes(container, ignoreClass)[step.index];
} }
if(!container) { if (!container) {
//Break the for loop as due to incorrect index we can get error if //Break the for loop as due to incorrect index we can get error if
//container is undefined so that other functionailties works fine //container is undefined so that other functionailties works fine
//like navigation //like navigation
break; break;
} }
} }
return container; return container;
@ -875,10 +866,16 @@ class EpubCFI {
var container; var container;
var xpath; var xpath;
if(!ignoreClass && typeof doc.evaluate != "undefined") { if (!ignoreClass && typeof doc.evaluate != "undefined") {
xpath = this.stepsToXpath(steps); xpath = this.stepsToXpath(steps);
container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; container = doc.evaluate(
} else if(ignoreClass) { xpath,
doc,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
} else if (ignoreClass) {
container = this.walkToNode(steps, doc, ignoreClass); container = this.walkToNode(steps, doc, ignoreClass);
} else { } else {
container = this.walkToNode(steps, doc); container = this.walkToNode(steps, doc);
@ -888,20 +885,20 @@ class EpubCFI {
} }
fixMiss(steps, offset, _doc, ignoreClass) { fixMiss(steps, offset, _doc, ignoreClass) {
var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass); var container = this.findNode(steps.slice(0, -1), _doc, ignoreClass);
var children = container.childNodes; var children = container.childNodes;
var map = this.normalizedMap(children, TEXT_NODE, ignoreClass); var map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
var child; var child;
var len; var len;
var lastStepIndex = steps[steps.length-1].index; var lastStepIndex = steps[steps.length - 1].index;
for (let childIndex in map) { for (let childIndex in map) {
if (!map.hasOwnProperty(childIndex)) return; if (!map.hasOwnProperty(childIndex)) return;
if(map[childIndex] === lastStepIndex) { if (map[childIndex] === lastStepIndex) {
child = children[childIndex]; child = children[childIndex];
len = child.textContent.length; len = child.textContent.length;
if(offset > len) { if (offset > len) {
offset = offset - len; offset = offset - len;
} else { } else {
if (child.nodeType === ELEMENT_NODE) { if (child.nodeType === ELEMENT_NODE) {
@ -916,9 +913,8 @@ class EpubCFI {
return { return {
container: container, container: container,
offset: offset offset: offset,
}; };
} }
/** /**
@ -933,10 +929,12 @@ class EpubCFI {
var start, end, startContainer, endContainer; var start, end, startContainer, endContainer;
var cfi = this; var cfi = this;
var startSteps, endSteps; var startSteps, endSteps;
var needsIgnoring = ignoreClass ? (doc.querySelector("." + ignoreClass) != null) : false; var needsIgnoring = ignoreClass
? doc.querySelector("." + ignoreClass) != null
: false;
var missed; var missed;
if (typeof(doc.createRange) !== "undefined") { if (typeof doc.createRange !== "undefined") {
range = doc.createRange(); range = doc.createRange();
} else { } else {
range = new RangeObject(); range = new RangeObject();
@ -945,27 +943,42 @@ class EpubCFI {
if (cfi.range) { if (cfi.range) {
start = cfi.start; start = cfi.start;
startSteps = cfi.path.steps.concat(start.steps); startSteps = cfi.path.steps.concat(start.steps);
startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); startContainer = this.findNode(
startSteps,
doc,
needsIgnoring ? ignoreClass : null
);
end = cfi.end; end = cfi.end;
endSteps = cfi.path.steps.concat(end.steps); endSteps = cfi.path.steps.concat(end.steps);
endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); endContainer = this.findNode(
endSteps,
doc,
needsIgnoring ? ignoreClass : null
);
} else { } else {
start = cfi.path; start = cfi.path;
startSteps = cfi.path.steps; startSteps = cfi.path.steps;
startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); startContainer = this.findNode(
cfi.path.steps,
doc,
needsIgnoring ? ignoreClass : null
);
} }
if(startContainer) { if (startContainer) {
try { try {
if (start.terminal.offset != null) {
if(start.terminal.offset != null) {
range.setStart(startContainer, start.terminal.offset); range.setStart(startContainer, start.terminal.offset);
} else { } else {
range.setStart(startContainer, 0); range.setStart(startContainer, 0);
} }
} catch (e) { } catch (e) {
missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); missed = this.fixMiss(
startSteps,
start.terminal.offset,
doc,
needsIgnoring ? ignoreClass : null
);
range.setStart(missed.container, missed.offset); range.setStart(missed.container, missed.offset);
} }
} else { } else {
@ -976,20 +989,22 @@ class EpubCFI {
if (endContainer) { if (endContainer) {
try { try {
if (end.terminal.offset != null) {
if(end.terminal.offset != null) {
range.setEnd(endContainer, end.terminal.offset); range.setEnd(endContainer, end.terminal.offset);
} else { } else {
range.setEnd(endContainer, 0); range.setEnd(endContainer, 0);
} }
} catch (e) { } catch (e) {
missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); missed = this.fixMiss(
endSteps,
cfi.end.terminal.offset,
doc,
needsIgnoring ? ignoreClass : null
);
range.setEnd(missed.container, missed.offset); range.setEnd(missed.container, missed.offset);
} }
} }
// doc.defaultView.getSelection().addRange(range); // doc.defaultView.getSelection().addRange(range);
return range; return range;
} }
@ -1000,9 +1015,11 @@ class EpubCFI {
* @returns {boolean} * @returns {boolean}
*/ */
isCfiString(str) { isCfiString(str) {
if(typeof str === "string" && if (
typeof str === "string" &&
str.indexOf("epubcfi(") === 0 && str.indexOf("epubcfi(") === 0 &&
str[str.length-1] === ")") { str[str.length - 1] === ")"
) {
return true; return true;
} }
@ -1012,11 +1029,11 @@ class EpubCFI {
generateChapterComponent(_spineNodeIndex, _pos, id) { generateChapterComponent(_spineNodeIndex, _pos, id) {
var pos = parseInt(_pos), var pos = parseInt(_pos),
spineNodeIndex = (_spineNodeIndex + 1) * 2, spineNodeIndex = (_spineNodeIndex + 1) * 2,
cfi = "/"+spineNodeIndex+"/"; cfi = "/" + spineNodeIndex + "/";
cfi += (pos + 1) * 2; cfi += (pos + 1) * 2;
if(id) { if (id) {
cfi += "[" + id + "]"; cfi += "[" + id + "]";
} }
@ -1041,7 +1058,6 @@ class EpubCFI {
this.path.steps = this.path.steps.concat(this.end.steps); this.path.steps = this.path.steps.concat(this.end.steps);
this.path.terminal = this.end.terminal; this.path.terminal = this.end.terminal;
} }
} }
} }

View file

@ -1,15 +1,9 @@
import Book from "./book"; import Book from "./book";
import EpubCFI from "./epubcfi";
import Rendition from "./rendition";
import Contents from "./contents"; import Contents from "./contents";
import Layout from "./layout";
import ePub from "./epub"; import ePub from "./epub";
import EpubCFI from "./epubcfi";
import Layout from "./layout";
import Rendition from "./rendition";
export default ePub; export default ePub;
export { export { Book, Contents, EpubCFI, Layout, Rendition };
Book,
EpubCFI,
Rendition,
Contents,
Layout
};

View file

@ -1,6 +1,6 @@
import { extend } from "./utils/core";
import { EVENTS } from "./utils/constants";
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import { EVENTS } from "./utils/constants";
import { extend } from "./utils/core";
/** /**
* Figures out the CSS values to apply for a layout * Figures out the CSS values to apply for a layout
@ -15,19 +15,20 @@ class Layout {
constructor(settings) { constructor(settings) {
this.settings = settings; this.settings = settings;
this.name = settings.layout || "reflowable"; this.name = settings.layout || "reflowable";
this._spread = (settings.spread === "none") ? false : true; this._spread = settings.spread === "none" ? false : true;
this._minSpreadWidth = settings.minSpreadWidth || 800; this._minSpreadWidth = settings.minSpreadWidth || 800;
this._evenSpreads = settings.evenSpreads || false; this._evenSpreads = settings.evenSpreads || false;
if (settings.flow === "scrolled" || if (
settings.flow === "scrolled" ||
settings.flow === "scrolled-continuous" || settings.flow === "scrolled-continuous" ||
settings.flow === "scrolled-doc") { settings.flow === "scrolled-doc"
) {
this._flow = "scrolled"; this._flow = "scrolled";
} else { } else {
this._flow = "paginated"; this._flow = "paginated";
} }
this.width = 0; this.width = 0;
this.height = 0; this.height = 0;
this.spreadWidth = 0; this.spreadWidth = 0;
@ -47,9 +48,8 @@ class Layout {
delta: 0, delta: 0,
columnWidth: 0, columnWidth: 0,
gap: 0, gap: 0,
divisor: 1 divisor: 1,
}; };
} }
/** /**
@ -58,16 +58,18 @@ class Layout {
* @return {string} simplified flow * @return {string} simplified flow
*/ */
flow(flow) { flow(flow) {
if (typeof(flow) != "undefined") { if (typeof flow != "undefined") {
if (flow === "scrolled" || if (
flow === "scrolled" ||
flow === "scrolled-continuous" || flow === "scrolled-continuous" ||
flow === "scrolled-doc") { flow === "scrolled-doc"
) {
this._flow = "scrolled"; this._flow = "scrolled";
} else { } else {
this._flow = "paginated"; this._flow = "paginated";
} }
// this.props.flow = this._flow; // this.props.flow = this._flow;
this.update({flow: this._flow}); this.update({ flow: this._flow });
} }
return this._flow; return this._flow;
} }
@ -80,11 +82,10 @@ class Layout {
* @return {boolean} spread true | false * @return {boolean} spread true | false
*/ */
spread(spread, min) { spread(spread, min) {
if (spread) { if (spread) {
this._spread = (spread === "none") ? false : true; this._spread = spread === "none" ? false : true;
// this.props.spread = this._spread; // this.props.spread = this._spread;
this.update({spread: this._spread}); this.update({ spread: this._spread });
} }
if (min >= 0) { if (min >= 0) {
@ -100,8 +101,7 @@ class Layout {
* @param {number} _height height of the rendering * @param {number} _height height of the rendering
* @param {number} _gap width of the gap between columns * @param {number} _gap width of the gap between columns
*/ */
calculate(_width, _height, _gap){ calculate(_width, _height, _gap) {
var divisor = 1; var divisor = 1;
var gap = _gap || 0; var gap = _gap || 0;
@ -123,20 +123,24 @@ class Layout {
divisor = 1; divisor = 1;
} }
if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { if (
gap = ((section % 2 === 0) ? section : section - 1); this.name === "reflowable" &&
this._flow === "paginated" &&
!(_gap >= 0)
) {
gap = section % 2 === 0 ? section : section - 1;
} }
if (this.name === "pre-paginated" ) { if (this.name === "pre-paginated") {
gap = 0; gap = 0;
} }
//-- Double Page //-- Double Page
if(divisor > 1) { if (divisor > 1) {
// width = width - gap; // width = width - gap;
// columnWidth = (width - gap) / divisor; // columnWidth = (width - gap) / divisor;
// gap = gap / divisor; // gap = gap / divisor;
columnWidth = (width / divisor) - gap; columnWidth = width / divisor - gap;
pageWidth = columnWidth + gap; pageWidth = columnWidth + gap;
} else { } else {
columnWidth = width; columnWidth = width;
@ -147,7 +151,7 @@ class Layout {
width = columnWidth; width = columnWidth;
} }
spreadWidth = (columnWidth * divisor) + gap; spreadWidth = columnWidth * divisor + gap;
delta = width; delta = width;
@ -179,9 +183,8 @@ class Layout {
delta, delta,
columnWidth, columnWidth,
gap, gap,
divisor divisor,
}); });
} }
/** /**
@ -189,13 +192,19 @@ class Layout {
* @param {Contents} contents * @param {Contents} contents
* @return {Promise} * @return {Promise}
*/ */
format(contents, section, axis){ format(contents, section, axis) {
var formating; var formating;
if (this.name === "pre-paginated") { if (this.name === "pre-paginated") {
formating = contents.fit(this.columnWidth, this.height, section); formating = contents.fit(this.columnWidth, this.height, section);
} else if (this._flow === "paginated") { } else if (this._flow === "paginated") {
formating = contents.columns(this.width, this.height, this.columnWidth, this.gap, this.settings.direction); formating = contents.columns(
this.width,
this.height,
this.columnWidth,
this.gap,
this.settings.direction
);
} else if (axis && axis === "horizontal") { } else if (axis && axis === "horizontal") {
formating = contents.size(null, this.height); formating = contents.size(null, this.height);
} else { } else {
@ -212,7 +221,6 @@ class Layout {
* @return {{spreads: Number, pages: Number}} * @return {{spreads: Number, pages: Number}}
*/ */
count(totalLength, pageLength) { count(totalLength, pageLength) {
let spreads, pages; let spreads, pages;
if (this.name === "pre-paginated") { if (this.name === "pre-paginated") {
@ -220,19 +228,19 @@ class Layout {
pages = 1; pages = 1;
} else if (this._flow === "paginated") { } else if (this._flow === "paginated") {
pageLength = pageLength || this.delta; pageLength = pageLength || this.delta;
spreads = Math.ceil( totalLength / pageLength); spreads = Math.ceil(totalLength / pageLength);
pages = spreads * this.divisor; pages = spreads * this.divisor;
} else { // scrolled } else {
// scrolled
pageLength = pageLength || this.height; pageLength = pageLength || this.height;
spreads = Math.ceil( totalLength / pageLength); spreads = Math.ceil(totalLength / pageLength);
pages = spreads; pages = spreads;
} }
return { return {
spreads, spreads,
pages pages,
}; };
} }
/** /**
@ -248,7 +256,7 @@ class Layout {
} }
}); });
if(Object.keys(props).length > 0) { if (Object.keys(props).length > 0) {
let newProps = extend(this.props, props); let newProps = extend(this.props, props);
this.emit(EVENTS.LAYOUT.UPDATED, newProps, props); this.emit(EVENTS.LAYOUT.UPDATED, newProps, props);
} }

View file

@ -1,8 +1,8 @@
import {qs, sprint, locationOf, defer} from "./utils/core"; import EventEmitter from "event-emitter";
import Queue from "./utils/queue";
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import { EVENTS } from "./utils/constants"; import { EVENTS } from "./utils/constants";
import EventEmitter from "event-emitter"; import { defer, locationOf, qs, sprint } from "./utils/core";
import Queue from "./utils/queue";
/** /**
* Find Locations for a Book * Find Locations for a Book
@ -22,15 +22,11 @@ class Locations {
this._locations = []; this._locations = [];
this._locationsWords = []; this._locationsWords = [];
this.total = 0; this.total = 0;
this.break = 150; this.break = 150;
this._current = 0; this._current = 0;
this._wordCounter = 0; this._wordCounter = 0;
this.currentLocation = "";
this.currentLocation = ''; this._currentCfi = "";
this._currentCfi ='';
this.processingTimeout = undefined; this.processingTimeout = undefined;
} }
@ -40,20 +36,22 @@ class Locations {
* @return {Promise<Array<string>>} locations * @return {Promise<Array<string>>} locations
*/ */
generate(chars) { generate(chars) {
if (chars) { if (chars) {
this.break = chars; this.break = chars;
} }
this.q.pause(); this.q.pause();
this.spine.each(function(section) { this.spine.each(
function (section) {
if (section.linear) { if (section.linear) {
this.q.enqueue(this.process.bind(this), section); this.q.enqueue(this.process.bind(this), section);
} }
}.bind(this)); }.bind(this)
);
return this.q.run().then(function() { return this.q.run().then(
function () {
this.total = this._locations.length - 1; this.total = this._locations.length - 1;
if (this._currentCfi) { if (this._currentCfi) {
@ -62,33 +60,35 @@ class Locations {
return this._locations; return this._locations;
// console.log(this.percentage(this.book.rendition.location.start), this.percentage(this.book.rendition.location.end)); // console.log(this.percentage(this.book.rendition.location.start), this.percentage(this.book.rendition.location.end));
}.bind(this)); }.bind(this)
);
} }
createRange () { createRange() {
return { return {
startContainer: undefined, startContainer: undefined,
startOffset: undefined, startOffset: undefined,
endContainer: undefined, endContainer: undefined,
endOffset: undefined endOffset: undefined,
}; };
} }
process(section) { process(section) {
return section.load(this.request).then(
return section.load(this.request) function (contents) {
.then(function(contents) {
var completed = new defer(); var completed = new defer();
var locations = this.parse(contents, section.cfiBase); var locations = this.parse(contents, section.cfiBase);
this._locations = this._locations.concat(locations); this._locations = this._locations.concat(locations);
section.unload(); section.unload();
this.processingTimeout = setTimeout(() => completed.resolve(locations), this.pause); this.processingTimeout = setTimeout(
() => completed.resolve(locations),
this.pause
);
return completed.promise; return completed.promise;
}.bind(this)); }.bind(this)
);
} }
parse(contents, cfiBase, chars) { parse(contents, cfiBase, chars) {
@ -99,7 +99,7 @@ class Locations {
var counter = 0; var counter = 0;
var prev; var prev;
var _break = chars || this.break; var _break = chars || this.break;
var parser = function(node) { var parser = function (node) {
var len = node.length; var len = node.length;
var dist; var dist;
var pos = 0; var pos = 0;
@ -119,12 +119,11 @@ class Locations {
// Node is smaller than a break, // Node is smaller than a break,
// skip over it // skip over it
if(dist > len){ if (dist > len) {
counter += len; counter += len;
pos = len; pos = len;
} }
while (pos < len) { while (pos < len) {
dist = _break - counter; dist = _break - counter;
@ -139,7 +138,7 @@ class Locations {
// pos += dist; // pos += dist;
// Gone over // Gone over
if(pos + dist >= len){ if (pos + dist >= len) {
// Continue counter for next node // Continue counter for next node
counter += len - pos; counter += len - pos;
// break // break
@ -175,7 +174,6 @@ class Locations {
return locations; return locations;
} }
/** /**
* Load all of sections in the book to generate locations * Load all of sections in the book to generate locations
* @param {string} startCfi start position * @param {string} startCfi start position
@ -189,26 +187,41 @@ class Locations {
this._locationsWords = []; this._locationsWords = [];
this._wordCounter = 0; this._wordCounter = 0;
this.spine.each(function(section) { this.spine.each(
function (section) {
if (section.linear) { if (section.linear) {
if (start) { if (start) {
if (section.index >= start.spinePos) { if (section.index >= start.spinePos) {
this.q.enqueue(this.processWords.bind(this), section, wordCount, start, count); this.q.enqueue(
this.processWords.bind(this),
section,
wordCount,
start,
count
);
} }
} else { } else {
this.q.enqueue(this.processWords.bind(this), section, wordCount, start, count); this.q.enqueue(
this.processWords.bind(this),
section,
wordCount,
start,
count
);
} }
} }
}.bind(this)); }.bind(this)
);
return this.q.run().then(function() { return this.q.run().then(
function () {
if (this._currentCfi) { if (this._currentCfi) {
this.currentLocation = this._currentCfi; this.currentLocation = this._currentCfi;
} }
return this._locationsWords; return this._locationsWords;
}.bind(this)); }.bind(this)
);
} }
processWords(section, wordCount, startCfi, count) { processWords(section, wordCount, startCfi, count) {
@ -216,24 +229,32 @@ class Locations {
return Promise.resolve(); return Promise.resolve();
} }
return section.load(this.request) return section.load(this.request).then(
.then(function(contents) { function (contents) {
var completed = new defer(); var completed = new defer();
var locations = this.parseWords(contents, section, wordCount, startCfi); var locations = this.parseWords(contents, section, wordCount, startCfi);
var remainingCount = count - this._locationsWords.length; var remainingCount = count - this._locationsWords.length;
this._locationsWords = this._locationsWords.concat(locations.length >= count ? locations.slice(0, remainingCount) : locations); this._locationsWords = this._locationsWords.concat(
locations.length >= count
? locations.slice(0, remainingCount)
: locations
);
section.unload(); section.unload();
this.processingTimeout = setTimeout(() => completed.resolve(locations), this.pause); this.processingTimeout = setTimeout(
() => completed.resolve(locations),
this.pause
);
return completed.promise; return completed.promise;
}.bind(this)); }.bind(this)
);
} }
//http://stackoverflow.com/questions/18679576/counting-words-in-string //http://stackoverflow.com/questions/18679576/counting-words-in-string
countWords(s) { countWords(s) {
s = s.replace(/(^\s*)|(\s*$)/gi, "");//exclude start and end white-space s = s.replace(/(^\s*)|(\s*$)/gi, ""); //exclude start and end white-space
s = s.replace(/[ ]{2,}/gi, " ");//2 or more space to 1 s = s.replace(/[ ]{2,}/gi, " "); //2 or more space to 1
s = s.replace(/\n /, "\n"); // exclude newline with a start spacing s = s.replace(/\n /, "\n"); // exclude newline with a start spacing
return s.split(" ").length; return s.split(" ").length;
} }
@ -243,14 +264,18 @@ class Locations {
var locations = []; var locations = [];
var doc = contents.ownerDocument; var doc = contents.ownerDocument;
var body = qs(doc, "body"); var body = qs(doc, "body");
var prev;
var _break = wordCount; var _break = wordCount;
var foundStartNode = startCfi ? startCfi.spinePos !== section.index : true; var foundStartNode = startCfi ? startCfi.spinePos !== section.index : true;
var startNode; var startNode;
if (startCfi && section.index === startCfi.spinePos) { if (startCfi && section.index === startCfi.spinePos) {
startNode = startCfi.findNode(startCfi.range ? startCfi.path.steps.concat(startCfi.start.steps) : startCfi.path.steps, contents.ownerDocument); startNode = startCfi.findNode(
startCfi.range
? startCfi.path.steps.concat(startCfi.start.steps)
: startCfi.path.steps,
contents.ownerDocument
);
} }
var parser = function(node) { var parser = function (node) {
if (!foundStartNode) { if (!foundStartNode) {
if (node === startNode) { if (node === startNode) {
foundStartNode = true; foundStartNode = true;
@ -280,7 +305,6 @@ class Locations {
pos = len; pos = len;
} }
while (pos < len) { while (pos < len) {
dist = _break - this._wordCounter; dist = _break - this._wordCounter;
@ -300,7 +324,6 @@ class Locations {
this._wordCounter = 0; this._wordCounter = 0;
} }
} }
prev = node;
}; };
sprint(body, parser.bind(this)); sprint(body, parser.bind(this));
@ -313,13 +336,13 @@ class Locations {
* @param {EpubCFI} cfi * @param {EpubCFI} cfi
* @return {number} * @return {number}
*/ */
locationFromCfi(cfi){ locationFromCfi(cfi) {
let loc; let loc;
if (EpubCFI.prototype.isCfiString(cfi)) { if (EpubCFI.prototype.isCfiString(cfi)) {
cfi = new EpubCFI(cfi); cfi = new EpubCFI(cfi);
} }
// Check if the location has not been set yet // Check if the location has not been set yet
if(this._locations.length === 0) { if (this._locations.length === 0) {
return -1; return -1;
} }
@ -338,7 +361,7 @@ class Locations {
* @return {number} * @return {number}
*/ */
percentageFromCfi(cfi) { percentageFromCfi(cfi) {
if(this._locations.length === 0) { if (this._locations.length === 0) {
return null; return null;
} }
// Find closest cfi // Find closest cfi
@ -357,7 +380,7 @@ class Locations {
return 0; return 0;
} }
return (loc / this.total); return loc / this.total;
} }
/** /**
@ -365,14 +388,14 @@ class Locations {
* @param {number} loc * @param {number} loc
* @return {EpubCFI} cfi * @return {EpubCFI} cfi
*/ */
cfiFromLocation(loc){ cfiFromLocation(loc) {
var cfi = -1; var cfi = -1;
// check that pg is an int // check that pg is an int
if(typeof loc != "number"){ if (typeof loc != "number") {
loc = parseInt(loc); loc = parseInt(loc);
} }
if(loc >= 0 && loc < this._locations.length) { if (loc >= 0 && loc < this._locations.length) {
cfi = this._locations[loc]; cfi = this._locations[loc];
} }
@ -384,7 +407,7 @@ class Locations {
* @param {number} percentage * @param {number} percentage
* @return {EpubCFI} cfi * @return {EpubCFI} cfi
*/ */
cfiFromPercentage(percentage){ cfiFromPercentage(percentage) {
let loc; let loc;
if (percentage > 1) { if (percentage > 1) {
console.warn("Normalize cfiFromPercentage value to between 0 - 1"); console.warn("Normalize cfiFromPercentage value to between 0 - 1");
@ -405,7 +428,7 @@ class Locations {
* Load locations from JSON * Load locations from JSON
* @param {json} locations * @param {json} locations
*/ */
load(locations){ load(locations) {
if (typeof locations === "string") { if (typeof locations === "string") {
this._locations = JSON.parse(locations); this._locations = JSON.parse(locations);
} else { } else {
@ -419,18 +442,18 @@ class Locations {
* Save locations to JSON * Save locations to JSON
* @return {json} * @return {json}
*/ */
save(){ save() {
return JSON.stringify(this._locations); return JSON.stringify(this._locations);
} }
getCurrent(){ getCurrent() {
return this._current; return this._current;
} }
setCurrent(curr){ setCurrent(curr) {
var loc; var loc;
if(typeof curr == "string"){ if (typeof curr == "string") {
this._currentCfi = curr; this._currentCfi = curr;
} else if (typeof curr == "number") { } else if (typeof curr == "number") {
this._current = curr; this._current = curr;
@ -438,11 +461,11 @@ class Locations {
return; return;
} }
if(this._locations.length === 0) { if (this._locations.length === 0) {
return; return;
} }
if(typeof curr == "string"){ if (typeof curr == "string") {
loc = this.locationFromCfi(curr); loc = this.locationFromCfi(curr);
this._current = loc; this._current = loc;
} else { } else {
@ -450,7 +473,7 @@ class Locations {
} }
this.emit(EVENTS.LOCATIONS.CHANGED, { this.emit(EVENTS.LOCATIONS.CHANGED, {
percentage: this.percentageFromLocation(loc) percentage: this.percentageFromLocation(loc),
}); });
} }
@ -471,11 +494,11 @@ class Locations {
/** /**
* Locations length * Locations length
*/ */
length () { length() {
return this._locations.length; return this._locations.length;
} }
destroy () { destroy() {
this.spine = undefined; this.spine = undefined;
this.request = undefined; this.request = undefined;
this.pause = undefined; this.pause = undefined;
@ -484,7 +507,7 @@ class Locations {
this.q = undefined; this.q = undefined;
this.epubcfi = undefined; this.epubcfi = undefined;
this._locations = undefined this._locations = undefined;
this.total = undefined; this.total = undefined;
this.break = undefined; this.break = undefined;

View file

@ -1,8 +1,8 @@
import {extend, defer, requestAnimationFrame} from "../../utils/core"; import debounce from "lodash/debounce";
import { EVENTS } from "../../utils/constants";
import { defer, extend, requestAnimationFrame } from "../../utils/core";
import DefaultViewManager from "../default"; import DefaultViewManager from "../default";
import Snap from "../helpers/snap"; import Snap from "../helpers/snap";
import { EVENTS } from "../../utils/constants";
import debounce from "lodash/debounce";
class ContinuousViewManager extends DefaultViewManager { class ContinuousViewManager extends DefaultViewManager {
constructor(options) { constructor(options) {
@ -23,7 +23,7 @@ class ContinuousViewManager extends DefaultViewManager {
snap: false, snap: false,
afterScrolledTimeout: 10, afterScrolledTimeout: 10,
allowScriptedContent: false, allowScriptedContent: false,
allowPopups: false allowPopups: false,
}); });
extend(this.settings, options.settings || {}); extend(this.settings, options.settings || {});
@ -42,26 +42,31 @@ class ContinuousViewManager extends DefaultViewManager {
height: 0, height: 0,
forceEvenPages: false, forceEvenPages: false,
allowScriptedContent: this.settings.allowScriptedContent, allowScriptedContent: this.settings.allowScriptedContent,
allowPopups: this.settings.allowPopups allowPopups: this.settings.allowPopups,
}; };
this.scrollTop = 0; this.scrollTop = 0;
this.scrollLeft = 0; this.scrollLeft = 0;
} }
display(section, target){ display(section, target) {
return DefaultViewManager.prototype.display.call(this, section, target) return DefaultViewManager.prototype.display
.then(function () { .call(this, section, target)
.then(
function () {
return this.fill(); return this.fill();
}.bind(this)); }.bind(this)
);
} }
fill(_full){ fill(_full) {
var full = _full || new defer(); var full = _full || new defer();
this.q.enqueue(() => { this.q
.enqueue(() => {
return this.check(); return this.check();
}).then((result) => { })
.then((result) => {
if (result) { if (result) {
this.fill(full); this.fill(full);
} else { } else {
@ -72,21 +77,14 @@ class ContinuousViewManager extends DefaultViewManager {
return full.promise; return full.promise;
} }
moveTo(offset){ moveTo(offset) {
// var bounds = this.stage.bounds();
// var dist = Math.floor(offset.top / bounds.height) * bounds.height;
var distX = 0, var distX = 0,
distY = 0; distY = 0;
var offsetX = 0, if (!this.isPaginated) {
offsetY = 0;
if(!this.isPaginated) {
distY = offset.top; distY = offset.top;
offsetY = offset.top+this.settings.offsetDelta;
} else { } else {
distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta; distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;
offsetX = distX+this.settings.offsetDelta;
} }
if (distX > 0 || distY > 0) { if (distX > 0 || distY > 0) {
@ -94,20 +92,16 @@ class ContinuousViewManager extends DefaultViewManager {
} }
} }
afterResized(view){ afterResized(view) {
this.emit(EVENTS.MANAGERS.RESIZE, view.section); this.emit(EVENTS.MANAGERS.RESIZE, view.section);
} }
// Remove Previous Listeners if present // Remove Previous Listeners if present
removeShownListeners(view){ removeShownListeners(view) {
view.onDisplayed = function () {};
// view.off("shown", this.afterDisplayed);
// view.off("shown", this.afterDisplayedAbove);
view.onDisplayed = function(){};
} }
add(section){ add(section) {
var view = this.createView(section); var view = this.createView(section);
this.views.append(view); this.views.append(view);
@ -124,14 +118,13 @@ class ContinuousViewManager extends DefaultViewManager {
this.updateWritingMode(mode); this.updateWritingMode(mode);
}); });
// view.on(EVENTS.VIEWS.SHOWN, this.afterDisplayed.bind(this));
view.onDisplayed = this.afterDisplayed.bind(this); view.onDisplayed = this.afterDisplayed.bind(this);
view.onResize = this.afterResized.bind(this); view.onResize = this.afterResized.bind(this);
return view.display(this.request); return view.display(this.request);
} }
append(section){ append(section) {
var view = this.createView(section); var view = this.createView(section);
view.on(EVENTS.VIEWS.RESIZED, (bounds) => { view.on(EVENTS.VIEWS.RESIZED, (bounds) => {
@ -153,7 +146,7 @@ class ContinuousViewManager extends DefaultViewManager {
return view; return view;
} }
prepend(section){ prepend(section) {
var view = this.createView(section); var view = this.createView(section);
view.on(EVENTS.VIEWS.RESIZED, (bounds) => { view.on(EVENTS.VIEWS.RESIZED, (bounds) => {
@ -176,20 +169,21 @@ class ContinuousViewManager extends DefaultViewManager {
return view; return view;
} }
counter(bounds){ counter(bounds) {
if(this.settings.axis === "vertical") { if (this.settings.axis === "vertical") {
this.scrollBy(0, bounds.heightDelta, true); this.scrollBy(0, bounds.heightDelta, true);
} else { } else {
this.scrollBy(bounds.widthDelta, 0, true); this.scrollBy(bounds.widthDelta, 0, true);
} }
} }
update(_offset){ update(_offset) {
var container = this.bounds(); var container = this.bounds();
var views = this.views.all(); var views = this.views.all();
var viewsLength = views.length; var viewsLength = views.length;
var visible = []; var visible = [];
var offset = typeof _offset != "undefined" ? _offset : (this.settings.offset || 0); var offset =
typeof _offset != "undefined" ? _offset : this.settings.offset || 0;
var isVisible; var isVisible;
var view; var view;
@ -200,16 +194,16 @@ class ContinuousViewManager extends DefaultViewManager {
isVisible = this.isVisible(view, offset, offset, container); isVisible = this.isVisible(view, offset, offset, container);
if(isVisible === true) { if (isVisible === true) {
// console.log("visible " + view.index, view.displayed);
if (!view.displayed) { if (!view.displayed) {
let displayed = view.display(this.request) let displayed = view.display(this.request).then(
.then(function (view) { function (view) {
view.show(); view.show();
}, (err) => { },
(err) => {
view.hide(); view.hide();
}); }
);
promises.push(displayed); promises.push(displayed);
} else { } else {
view.show(); view.show();
@ -217,33 +211,32 @@ class ContinuousViewManager extends DefaultViewManager {
visible.push(view); visible.push(view);
} else { } else {
this.q.enqueue(view.destroy.bind(view)); this.q.enqueue(view.destroy.bind(view));
// console.log("hidden " + view.index, view.displayed);
clearTimeout(this.trimTimeout); clearTimeout(this.trimTimeout);
this.trimTimeout = setTimeout(function(){ this.trimTimeout = setTimeout(
function () {
this.q.enqueue(this.trim.bind(this)); this.q.enqueue(this.trim.bind(this));
}.bind(this), 250); }.bind(this),
250
);
}
} }
} if (promises.length) {
return Promise.all(promises).catch((err) => {
if(promises.length){
return Promise.all(promises)
.catch((err) => {
updating.reject(err); updating.reject(err);
}); });
} else { } else {
updating.resolve(); updating.resolve();
return updating.promise; return updating.promise;
} }
} }
check(_offsetLeft, _offsetTop){ check(_offsetLeft, _offsetTop) {
var checking = new defer(); var checking = new defer();
var newViews = []; var newViews = [];
var horizontal = (this.settings.axis === "horizontal"); var horizontal = this.settings.axis === "horizontal";
var delta = this.settings.offset || 0; var delta = this.settings.offset || 0;
if (_offsetLeft && horizontal) { if (_offsetLeft && horizontal) {
@ -254,12 +247,18 @@ class ContinuousViewManager extends DefaultViewManager {
delta = _offsetTop; delta = _offsetTop;
} }
var bounds = this._bounds; // bounds saved this until resize // bounds saved this until resize
var bounds = this._bounds;
let offset = horizontal ? this.scrollLeft : this.scrollTop; let offset = horizontal ? this.scrollLeft : this.scrollTop;
let visibleLength = horizontal ? Math.floor(bounds.width) : bounds.height; let visibleLength = horizontal ? Math.floor(bounds.width) : bounds.height;
let contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight; let contentLength = horizontal
let writingMode = (this.writingMode && this.writingMode.indexOf("vertical") === 0) ? "vertical" : "horizontal"; ? this.container.scrollWidth
: this.container.scrollHeight;
let writingMode =
this.writingMode && this.writingMode.indexOf("vertical") === 0
? "vertical"
: "horizontal";
let rtlScrollType = this.settings.rtlScrollType; let rtlScrollType = this.settings.rtlScrollType;
let rtl = this.settings.direction === "rtl"; let rtl = this.settings.direction === "rtl";
@ -274,8 +273,10 @@ class ContinuousViewManager extends DefaultViewManager {
} }
} else { } else {
// Scroll offset starts at 0 and goes negative // Scroll offset starts at 0 and goes negative
if ((horizontal && rtl && rtlScrollType === "negative") || if (
(!horizontal && rtl && rtlScrollType === "default")) { (horizontal && rtl && rtlScrollType === "negative") ||
(!horizontal && rtl && rtlScrollType === "default")
) {
offset = offset * -1; offset = offset * -1;
} }
} }
@ -284,7 +285,7 @@ class ContinuousViewManager extends DefaultViewManager {
let first = this.views.first(); let first = this.views.first();
let prev = first && first.section.prev(); let prev = first && first.section.prev();
if(prev) { if (prev) {
newViews.push(this.prepend(prev)); newViews.push(this.prepend(prev));
} }
}; };
@ -293,10 +294,9 @@ class ContinuousViewManager extends DefaultViewManager {
let last = this.views.last(); let last = this.views.last();
let next = last && last.section.next(); let next = last && last.section.next();
if(next) { if (next) {
newViews.push(this.append(next)); newViews.push(this.append(next));
} }
}; };
let end = offset + visibleLength + delta; let end = offset + visibleLength + delta;
@ -310,45 +310,47 @@ class ContinuousViewManager extends DefaultViewManager {
prepend(); prepend();
} }
let promises = newViews.map((view) => { let promises = newViews.map((view) => {
return view.display(this.request); return view.display(this.request);
}); });
if(newViews.length){ if (newViews.length) {
return Promise.all(promises) return Promise.all(promises)
.then(() => { .then(() => {
return this.check(); return this.check();
}) })
.then(() => { .then(
() => {
// Check to see if anything new is on screen after rendering // Check to see if anything new is on screen after rendering
return this.update(delta); return this.update(delta);
}, (err) => { },
(err) => {
return err; return err;
}); }
);
} else { } else {
this.q.enqueue(function(){ this.q.enqueue(
function () {
this.update(); this.update();
}.bind(this)); }.bind(this)
);
checking.resolve(false); checking.resolve(false);
return checking.promise; return checking.promise;
} }
} }
trim(){ trim() {
var task = new defer(); var task = new defer();
var displayed = this.views.displayed(); var displayed = this.views.displayed();
var first = displayed[0]; var first = displayed[0];
var last = displayed[displayed.length-1]; var last = displayed[displayed.length - 1];
var firstIndex = this.views.indexOf(first); var firstIndex = this.views.indexOf(first);
var lastIndex = this.views.indexOf(last); var lastIndex = this.views.indexOf(last);
var above = this.views.slice(0, firstIndex); var above = this.views.slice(0, firstIndex);
var below = this.views.slice(lastIndex+1); var below = this.views.slice(lastIndex + 1);
// Erase all but last above // Erase all but last above
for (var i = 0; i < above.length-1; i++) { for (var i = 0; i < above.length - 1; i++) {
this.erase(above[i], above); this.erase(above[i], above);
} }
@ -361,12 +363,11 @@ class ContinuousViewManager extends DefaultViewManager {
return task.promise; return task.promise;
} }
erase(view, above){ //Trim erase(view, above) {
var prevTop; var prevTop;
var prevLeft; var prevLeft;
if(!this.settings.fullsize) { if (!this.settings.fullsize) {
prevTop = this.container.scrollTop; prevTop = this.container.scrollTop;
prevLeft = this.container.scrollLeft; prevLeft = this.container.scrollLeft;
} else { } else {
@ -378,11 +379,11 @@ class ContinuousViewManager extends DefaultViewManager {
this.views.remove(view); this.views.remove(view);
if(above) { if (above) {
if (this.settings.axis === "vertical") { if (this.settings.axis === "vertical") {
this.scrollTo(0, prevTop - bounds.height, true); this.scrollTo(0, prevTop - bounds.height, true);
} else { } else {
if(this.settings.direction === 'rtl') { if (this.settings.direction === "rtl") {
if (!this.settings.fullsize) { if (!this.settings.fullsize) {
this.scrollTo(prevLeft, 0, true); this.scrollTo(prevLeft, 0, true);
} else { } else {
@ -393,35 +394,42 @@ class ContinuousViewManager extends DefaultViewManager {
} }
} }
} }
} }
addEventListeners(stage){ addEventListeners(stage) {
window.addEventListener(
window.addEventListener("unload", function(e){ "unload",
function (e) {
this.ignore = true; this.ignore = true;
// this.scrollTo(0,0);
this.destroy(); this.destroy();
}.bind(this)); }.bind(this)
);
this.addScrollListeners(); this.addScrollListeners();
if (this.isPaginated && this.settings.snap) { if (this.isPaginated && this.settings.snap) {
this.snapper = new Snap(this, this.settings.snap && (typeof this.settings.snap === "object") && this.settings.snap); this.snapper = new Snap(
this,
this.settings.snap &&
typeof this.settings.snap === "object" &&
this.settings.snap
);
} }
} }
addScrollListeners() { addScrollListeners() {
var scroller; var scroller;
this.tick = requestAnimationFrame; this.tick = requestAnimationFrame;
let dir =
let dir = this.settings.direction === "rtl" && this.settings.rtlScrollType === "default" ? -1 : 1; this.settings.direction === "rtl" &&
this.settings.rtlScrollType === "default"
? -1
: 1;
this.scrollDeltaVert = 0; this.scrollDeltaVert = 0;
this.scrollDeltaHorz = 0; this.scrollDeltaHorz = 0;
if(!this.settings.fullsize) { if (!this.settings.fullsize) {
scroller = this.container; scroller = this.container;
this.scrollTop = this.container.scrollTop; this.scrollTop = this.container.scrollTop;
this.scrollLeft = this.container.scrollLeft; this.scrollLeft = this.container.scrollLeft;
@ -434,16 +442,13 @@ class ContinuousViewManager extends DefaultViewManager {
this._onScroll = this.onScroll.bind(this); this._onScroll = this.onScroll.bind(this);
scroller.addEventListener("scroll", this._onScroll); scroller.addEventListener("scroll", this._onScroll);
this._scrolled = debounce(this.scrolled.bind(this), 30); this._scrolled = debounce(this.scrolled.bind(this), 30);
// this.tick.call(window, this.onScroll.bind(this));
this.didScroll = false; this.didScroll = false;
} }
removeEventListeners(){ removeEventListeners() {
var scroller; var scroller;
if(!this.settings.fullsize) { if (!this.settings.fullsize) {
scroller = this.container; scroller = this.container;
} else { } else {
scroller = window; scroller = window;
@ -453,12 +458,16 @@ class ContinuousViewManager extends DefaultViewManager {
this._onScroll = undefined; this._onScroll = undefined;
} }
onScroll(){ onScroll() {
let scrollTop; let scrollTop;
let scrollLeft; let scrollLeft;
let dir = this.settings.direction === "rtl" && this.settings.rtlScrollType === "default" ? -1 : 1; let dir =
this.settings.direction === "rtl" &&
this.settings.rtlScrollType === "default"
? -1
: 1;
if(!this.settings.fullsize) { if (!this.settings.fullsize) {
scrollTop = this.container.scrollTop; scrollTop = this.container.scrollTop;
scrollLeft = this.container.scrollLeft; scrollLeft = this.container.scrollLeft;
} else { } else {
@ -469,104 +478,108 @@ class ContinuousViewManager extends DefaultViewManager {
this.scrollTop = scrollTop; this.scrollTop = scrollTop;
this.scrollLeft = scrollLeft; this.scrollLeft = scrollLeft;
if(!this.ignore) { if (!this.ignore) {
this._scrolled(); this._scrolled();
} else { } else {
this.ignore = false; this.ignore = false;
} }
this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop); this.scrollDeltaVert += Math.abs(scrollTop - this.prevScrollTop);
this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft); this.scrollDeltaHorz += Math.abs(scrollLeft - this.prevScrollLeft);
this.prevScrollTop = scrollTop; this.prevScrollTop = scrollTop;
this.prevScrollLeft = scrollLeft; this.prevScrollLeft = scrollLeft;
clearTimeout(this.scrollTimeout); clearTimeout(this.scrollTimeout);
this.scrollTimeout = setTimeout(function(){ this.scrollTimeout = setTimeout(
function () {
this.scrollDeltaVert = 0; this.scrollDeltaVert = 0;
this.scrollDeltaHorz = 0; this.scrollDeltaHorz = 0;
}.bind(this), 150); }.bind(this),
150
);
clearTimeout(this.afterScrolled); clearTimeout(this.afterScrolled);
this.didScroll = false; this.didScroll = false;
} }
scrolled() { scrolled() {
this.q.enqueue(
this.q.enqueue(function() { function () {
return this.check(); return this.check();
}.bind(this)); }.bind(this)
);
this.emit(EVENTS.MANAGERS.SCROLL, { this.emit(EVENTS.MANAGERS.SCROLL, {
top: this.scrollTop, top: this.scrollTop,
left: this.scrollLeft left: this.scrollLeft,
}); });
clearTimeout(this.afterScrolled); clearTimeout(this.afterScrolled);
this.afterScrolled = setTimeout(function () { this.afterScrolled = setTimeout(
function () {
// Don't report scroll if we are about the snap // Don't report scroll if we are about the snap
if (this.snapper && this.snapper.supportsTouch && this.snapper.needsSnap()) { if (
this.snapper &&
this.snapper.supportsTouch &&
this.snapper.needsSnap()
) {
return; return;
} }
this.emit(EVENTS.MANAGERS.SCROLLED, { this.emit(EVENTS.MANAGERS.SCROLLED, {
top: this.scrollTop, top: this.scrollTop,
left: this.scrollLeft left: this.scrollLeft,
}); });
}.bind(this),
}.bind(this), this.settings.afterScrolledTimeout); this.settings.afterScrolledTimeout
);
} }
next(){ next() {
let delta =
this.layout.props.name === "pre-paginated" && this.layout.props.spread
? this.layout.props.delta * 2
: this.layout.props.delta;
let delta = this.layout.props.name === "pre-paginated" && if (!this.views.length) return;
this.layout.props.spread ? this.layout.props.delta * 2 : this.layout.props.delta;
if(!this.views.length) return;
if(this.isPaginated && this.settings.axis === "horizontal") {
if (this.isPaginated && this.settings.axis === "horizontal") {
this.scrollBy(delta, 0, true); this.scrollBy(delta, 0, true);
} else { } else {
this.scrollBy(0, this.layout.height, true); this.scrollBy(0, this.layout.height, true);
} }
this.q.enqueue(function() { this.q.enqueue(
function () {
return this.check(); return this.check();
}.bind(this)); }.bind(this)
);
} }
prev(){ prev() {
let delta =
this.layout.props.name === "pre-paginated" && this.layout.props.spread
? this.layout.props.delta * 2
: this.layout.props.delta;
let delta = this.layout.props.name === "pre-paginated" && if (!this.views.length) return;
this.layout.props.spread ? this.layout.props.delta * 2 : this.layout.props.delta;
if(!this.views.length) return;
if(this.isPaginated && this.settings.axis === "horizontal") {
if (this.isPaginated && this.settings.axis === "horizontal") {
this.scrollBy(-delta, 0, true); this.scrollBy(-delta, 0, true);
} else { } else {
this.scrollBy(0, -this.layout.height, true); this.scrollBy(0, -this.layout.height, true);
} }
this.q.enqueue(function() { this.q.enqueue(
function () {
return this.check(); return this.check();
}.bind(this)); }.bind(this)
);
} }
updateFlow(flow){ updateFlow(flow) {
if (this.rendered && this.snapper) { if (this.rendered && this.snapper) {
this.snapper.destroy(); this.snapper.destroy();
this.snapper = undefined; this.snapper = undefined;
@ -575,18 +588,22 @@ class ContinuousViewManager extends DefaultViewManager {
super.updateFlow(flow, "scroll"); super.updateFlow(flow, "scroll");
if (this.rendered && this.isPaginated && this.settings.snap) { if (this.rendered && this.isPaginated && this.settings.snap) {
this.snapper = new Snap(this, this.settings.snap && (typeof this.settings.snap === "object") && this.settings.snap); this.snapper = new Snap(
this,
this.settings.snap &&
typeof this.settings.snap === "object" &&
this.settings.snap
);
} }
} }
destroy(){ destroy() {
super.destroy(); super.destroy();
if (this.snapper) { if (this.snapper) {
this.snapper.destroy(); this.snapper.destroy();
} }
} }
} }
export default ContinuousViewManager; export default ContinuousViewManager;

File diff suppressed because it is too large Load diff

View file

@ -1,36 +1,38 @@
import {extend, defer, requestAnimationFrame, prefixed} from "../../utils/core";
import { EVENTS, DOM_EVENTS } from "../../utils/constants";
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import { EVENTS } from "../../utils/constants";
import { defer, extend } from "../../utils/core";
// easing equations from https://github.com/danro/easing-js/blob/master/easing.js // easing equations from https://github.com/danro/easing-js/blob/master/easing.js
const PI_D2 = (Math.PI / 2); const PI_D2 = Math.PI / 2;
const EASING_EQUATIONS = { const EASING_EQUATIONS = {
easeOutSine: function (pos) { easeOutSine: function (pos) {
return Math.sin(pos * PI_D2); return Math.sin(pos * PI_D2);
}, },
easeInOutSine: function (pos) { easeInOutSine: function (pos) {
return (-0.5 * (Math.cos(Math.PI * pos) - 1)); return -0.5 * (Math.cos(Math.PI * pos) - 1);
}, },
easeInOutQuint: function (pos) { easeInOutQuint: function (pos) {
if ((pos /= 0.5) < 1) { if ((pos /= 0.5) < 1) {
return 0.5 * Math.pow(pos, 5); return 0.5 * Math.pow(pos, 5);
} }
return 0.5 * (Math.pow((pos - 2), 5) + 2); return 0.5 * (Math.pow(pos - 2, 5) + 2);
}, },
easeInCubic: function(pos) { easeInCubic: function (pos) {
return Math.pow(pos, 3); return Math.pow(pos, 3);
} },
}; };
class Snap { class Snap {
constructor(manager, options) { constructor(manager, options) {
this.settings = extend(
this.settings = extend({ {
duration: 80, duration: 80,
minVelocity: 0.2, minVelocity: 0.2,
minDistance: 10, minDistance: 10,
easing: EASING_EQUATIONS['easeInCubic'] easing: EASING_EQUATIONS["easeInCubic"],
}, options || {}); },
options || {}
);
this.supportsTouch = this.supportsTouch(); this.supportsTouch = this.supportsTouch();
@ -55,8 +57,6 @@ class Snap {
this.element.style["WebkitOverflowScrolling"] = "touch"; this.element.style["WebkitOverflowScrolling"] = "touch";
} }
// this.overflow = this.manager.overflow;
// set lookahead offset to page width // set lookahead offset to page width
this.manager.settings.offset = this.layout.width; this.manager.settings.offset = this.layout.width;
this.manager.settings.afterScrolledTimeout = this.settings.duration * 2; this.manager.settings.afterScrolledTimeout = this.settings.duration * 2;
@ -72,7 +72,6 @@ class Snap {
this.resizeCanceler = false; this.resizeCanceler = false;
this.snapping = false; this.snapping = false;
this.scrollLeft; this.scrollLeft;
this.scrollTop; this.scrollTop;
@ -87,7 +86,10 @@ class Snap {
} }
supportsTouch() { supportsTouch() {
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { if (
"ontouchstart" in window ||
(window.DocumentTouch && document instanceof DocumentTouch)
) {
return true; return true;
} }
@ -104,44 +106,56 @@ class Snap {
addListeners() { addListeners() {
this._onResize = this.onResize.bind(this); this._onResize = this.onResize.bind(this);
window.addEventListener('resize', this._onResize); window.addEventListener("resize", this._onResize);
this._onScroll = this.onScroll.bind(this); this._onScroll = this.onScroll.bind(this);
this.scroller.addEventListener('scroll', this._onScroll); this.scroller.addEventListener("scroll", this._onScroll);
this._onTouchStart = this.onTouchStart.bind(this); this._onTouchStart = this.onTouchStart.bind(this);
this.scroller.addEventListener('touchstart', this._onTouchStart, { passive: true }); this.scroller.addEventListener("touchstart", this._onTouchStart, {
this.on('touchstart', this._onTouchStart); passive: true,
});
this.on("touchstart", this._onTouchStart);
this._onTouchMove = this.onTouchMove.bind(this); this._onTouchMove = this.onTouchMove.bind(this);
this.scroller.addEventListener('touchmove', this._onTouchMove, { passive: true }); this.scroller.addEventListener("touchmove", this._onTouchMove, {
this.on('touchmove', this._onTouchMove); passive: true,
});
this.on("touchmove", this._onTouchMove);
this._onTouchEnd = this.onTouchEnd.bind(this); this._onTouchEnd = this.onTouchEnd.bind(this);
this.scroller.addEventListener('touchend', this._onTouchEnd, { passive: true }); this.scroller.addEventListener("touchend", this._onTouchEnd, {
this.on('touchend', this._onTouchEnd); passive: true,
});
this.on("touchend", this._onTouchEnd);
this._afterDisplayed = this.afterDisplayed.bind(this); this._afterDisplayed = this.afterDisplayed.bind(this);
this.manager.on(EVENTS.MANAGERS.ADDED, this._afterDisplayed); this.manager.on(EVENTS.MANAGERS.ADDED, this._afterDisplayed);
} }
removeListeners() { removeListeners() {
window.removeEventListener('resize', this._onResize); window.removeEventListener("resize", this._onResize);
this._onResize = undefined; this._onResize = undefined;
this.scroller.removeEventListener('scroll', this._onScroll); this.scroller.removeEventListener("scroll", this._onScroll);
this._onScroll = undefined; this._onScroll = undefined;
this.scroller.removeEventListener('touchstart', this._onTouchStart, { passive: true }); this.scroller.removeEventListener("touchstart", this._onTouchStart, {
this.off('touchstart', this._onTouchStart); passive: true,
});
this.off("touchstart", this._onTouchStart);
this._onTouchStart = undefined; this._onTouchStart = undefined;
this.scroller.removeEventListener('touchmove', this._onTouchMove, { passive: true }); this.scroller.removeEventListener("touchmove", this._onTouchMove, {
this.off('touchmove', this._onTouchMove); passive: true,
});
this.off("touchmove", this._onTouchMove);
this._onTouchMove = undefined; this._onTouchMove = undefined;
this.scroller.removeEventListener('touchend', this._onTouchEnd, { passive: true }); this.scroller.removeEventListener("touchend", this._onTouchEnd, {
this.off('touchend', this._onTouchEnd); passive: true,
});
this.off("touchend", this._onTouchEnd);
this._onTouchEnd = undefined; this._onTouchEnd = undefined;
this.manager.off(EVENTS.MANAGERS.ADDED, this._afterDisplayed); this.manager.off(EVENTS.MANAGERS.ADDED, this._afterDisplayed);
@ -155,7 +169,7 @@ class Snap {
}); });
} }
triggerViewEvent(e, contents){ triggerViewEvent(e, contents) {
this.emit(e.type, e, contents); this.emit(e.type, e, contents);
} }
@ -194,7 +208,6 @@ class Snap {
this.touchCanceler = true; this.touchCanceler = true;
if (!this.fullsize && deltaY < 10) { if (!this.fullsize && deltaY < 10) {
this.element.scrollLeft -= screenX - this.endTouchX; this.element.scrollLeft -= screenX - this.endTouchX;
} }
@ -229,10 +242,10 @@ class Snap {
wasSwiped() { wasSwiped() {
let snapWidth = this.layout.pageWidth * this.layout.divisor; let snapWidth = this.layout.pageWidth * this.layout.divisor;
let distance = (this.endTouchX - this.startTouchX); let distance = this.endTouchX - this.startTouchX;
let absolute = Math.abs(distance); let absolute = Math.abs(distance);
let time = this.endTime - this.startTime; let time = this.endTime - this.startTime;
let velocity = (distance / time); let velocity = distance / time;
let minVelocity = this.settings.minVelocity; let minVelocity = this.settings.minVelocity;
if (absolute <= this.settings.minDistance || absolute >= snapWidth) { if (absolute <= this.settings.minDistance || absolute >= snapWidth) {
@ -251,16 +264,16 @@ class Snap {
needsSnap() { needsSnap() {
let left = this.scrollLeft; let left = this.scrollLeft;
let snapWidth = this.layout.pageWidth * this.layout.divisor; let snapWidth = this.layout.pageWidth * this.layout.divisor;
return (left % snapWidth) !== 0; return left % snapWidth !== 0;
} }
snap(howMany=0) { snap(howMany = 0) {
let left = this.scrollLeft; let left = this.scrollLeft;
let snapWidth = this.layout.pageWidth * this.layout.divisor; let snapWidth = this.layout.pageWidth * this.layout.divisor;
let snapTo = Math.round(left / snapWidth) * snapWidth; let snapTo = Math.round(left / snapWidth) * snapWidth;
if (howMany) { if (howMany) {
snapTo += (howMany * snapWidth); snapTo += howMany * snapWidth;
} }
return this.smoothScrollTo(snapTo); return this.smoothScrollTo(snapTo);
@ -272,16 +285,13 @@ class Snap {
const startTime = this.now(); const startTime = this.now();
const duration = this.settings.duration; const duration = this.settings.duration;
const easing = this.settings.easing;
this.snapping = true; this.snapping = true;
// add animation loop // add animation loop
function tick() { function tick() {
const now = this.now(); const now = this.now();
const time = Math.min(1, ((now - startTime) / duration)); const time = Math.min(1, (now - startTime) / duration);
const timeFunction = easing(time);
if (this.touchCanceler || this.resizeCanceler) { if (this.touchCanceler || this.resizeCanceler) {
this.resizeCanceler = false; this.resizeCanceler = false;
@ -292,7 +302,7 @@ class Snap {
if (time < 1) { if (time < 1) {
window.requestAnimationFrame(tick.bind(this)); window.requestAnimationFrame(tick.bind(this));
this.scrollTo(start + ((destination - start) * time), 0); this.scrollTo(start + (destination - start) * time, 0);
} else { } else {
this.scrollTo(destination, 0); this.scrollTo(destination, 0);
this.snapping = false; this.snapping = false;
@ -305,7 +315,7 @@ class Snap {
return deferred.promise; return deferred.promise;
} }
scrollTo(left=0, top=0) { scrollTo(left = 0, top = 0) {
if (this.fullsize) { if (this.fullsize) {
window.scroll(left, top); window.scroll(left, top);
} else { } else {
@ -315,7 +325,9 @@ class Snap {
} }
now() { now() {
return ('now' in window.performance) ? performance.now() : new Date().getTime(); return "now" in window.performance
? performance.now()
: new Date().getTime();
} }
destroy() { destroy() {

View file

@ -1,5 +1,11 @@
import {uuid, isNumber, isElement, windowBounds, extend} from "../../utils/core"; import throttle from "lodash/throttle";
import throttle from 'lodash/throttle' import {
extend,
isElement,
isNumber,
uuid,
windowBounds,
} from "../../utils/core";
class Stage { class Stage {
constructor(_options) { constructor(_options) {
@ -8,30 +14,29 @@ class Stage {
this.container = this.create(this.settings); this.container = this.create(this.settings);
if(this.settings.hidden) { if (this.settings.hidden) {
this.wrapper = this.wrap(this.container); this.wrapper = this.wrap(this.container);
} }
} }
/* /*
* Creates an element to render to. * Creates an element to render to.
* Resizes to passed width and height or to the elements size * Resizes to passed width and height or to the elements size
*/ */
create(options){ create(options) {
let height = options.height;// !== false ? options.height : "100%"; let height = options.height;
let width = options.width;// !== false ? options.width : "100%"; let width = options.width;
let overflow = options.overflow || false; let overflow = options.overflow || false;
let axis = options.axis || "vertical"; let axis = options.axis || "vertical";
let direction = options.direction; let direction = options.direction;
extend(this.settings, options); extend(this.settings, options);
if(options.height && isNumber(options.height)) { if (options.height && isNumber(options.height)) {
height = options.height + "px"; height = options.height + "px";
} }
if(options.width && isNumber(options.width)) { if (options.width && isNumber(options.width)) {
width = options.width + "px"; width = options.width + "px";
} }
@ -42,24 +47,22 @@ class Stage {
container.classList.add("epub-container"); container.classList.add("epub-container");
// Style Element // Style Element
// container.style.fontSize = "0";
container.style.wordSpacing = "0"; container.style.wordSpacing = "0";
container.style.lineHeight = "0"; container.style.lineHeight = "0";
container.style.verticalAlign = "top"; container.style.verticalAlign = "top";
container.style.position = "relative"; container.style.position = "relative";
if(axis === "horizontal") { if (axis === "horizontal") {
// container.style.whiteSpace = "nowrap";
container.style.display = "flex"; container.style.display = "flex";
container.style.flexDirection = "row"; container.style.flexDirection = "row";
container.style.flexWrap = "nowrap"; container.style.flexWrap = "nowrap";
} }
if(width){ if (width) {
container.style.width = width; container.style.width = width;
} }
if(height){ if (height) {
container.style.height = height; container.style.height = height;
} }
@ -99,33 +102,31 @@ class Stage {
return wrapper; return wrapper;
} }
getElement(_element) {
getElement(_element){
var element; var element;
if(isElement(_element)) { if (isElement(_element)) {
element = _element; element = _element;
} else if (typeof _element === "string") { } else if (typeof _element === "string") {
element = document.getElementById(_element); element = document.getElementById(_element);
} }
if(!element){ if (!element) {
throw new Error("Not an Element"); throw new Error("Not an Element");
} }
return element; return element;
} }
attachTo(what){ attachTo(what) {
var element = this.getElement(what); var element = this.getElement(what);
var base; var base;
if(!element){ if (!element) {
return; return;
} }
if(this.settings.hidden) { if (this.settings.hidden) {
base = this.wrapper; base = this.wrapper;
} else { } else {
base = this.container; base = this.container;
@ -136,39 +137,40 @@ class Stage {
this.element = element; this.element = element;
return element; return element;
} }
getContainer() { getContainer() {
return this.container; return this.container;
} }
onResize(func){ onResize(func) {
// Only listen to window for resize event if width and height are not fixed. // Only listen to window for resize event if width and height are not fixed.
// This applies if it is set to a percent or auto. // This applies if it is set to a percent or auto.
if(!isNumber(this.settings.width) || if (!isNumber(this.settings.width) || !isNumber(this.settings.height)) {
!isNumber(this.settings.height) ) {
this.resizeFunc = throttle(func, 50); this.resizeFunc = throttle(func, 50);
window.addEventListener("resize", this.resizeFunc, false); window.addEventListener("resize", this.resizeFunc, false);
} }
} }
onOrientationChange(func){ onOrientationChange(func) {
this.orientationChangeFunc = func; this.orientationChangeFunc = func;
window.addEventListener("orientationchange", this.orientationChangeFunc, false); window.addEventListener(
"orientationchange",
this.orientationChangeFunc,
false
);
} }
size(width, height){ size(width, height) {
var bounds; var bounds;
let _width = width || this.settings.width; let _width = width || this.settings.width;
let _height = height || this.settings.height; let _height = height || this.settings.height;
// If width or height are set to false, inherit them from containing element // If width or height are set to false, inherit them from containing element
if(width === null) { if (width === null) {
bounds = this.element.getBoundingClientRect(); bounds = this.element.getBoundingClientRect();
if(bounds.width) { if (bounds.width) {
width = Math.floor(bounds.width); width = Math.floor(bounds.width);
this.container.style.width = width + "px"; this.container.style.width = width + "px";
} }
@ -180,14 +182,13 @@ class Stage {
} }
} }
if(height === null) { if (height === null) {
bounds = bounds || this.element.getBoundingClientRect(); bounds = bounds || this.element.getBoundingClientRect();
if(bounds.height) { if (bounds.height) {
height = bounds.height; height = bounds.height;
this.container.style.height = height + "px"; this.container.style.height = height + "px";
} }
} else { } else {
if (isNumber(height)) { if (isNumber(height)) {
this.container.style.height = height + "px"; this.container.style.height = height + "px";
@ -196,11 +197,11 @@ class Stage {
} }
} }
if(!isNumber(width)) { if (!isNumber(width)) {
width = this.container.clientWidth; width = this.container.clientWidth;
} }
if(!isNumber(height)) { if (!isNumber(height)) {
height = this.container.clientHeight; height = this.container.clientHeight;
} }
@ -210,7 +211,7 @@ class Stage {
left: parseFloat(this.containerStyles["padding-left"]) || 0, left: parseFloat(this.containerStyles["padding-left"]) || 0,
right: parseFloat(this.containerStyles["padding-right"]) || 0, right: parseFloat(this.containerStyles["padding-right"]) || 0,
top: parseFloat(this.containerStyles["padding-top"]) || 0, top: parseFloat(this.containerStyles["padding-top"]) || 0,
bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0 bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0,
}; };
// Bounds not set, get them from window // Bounds not set, get them from window
@ -220,47 +221,37 @@ class Stage {
left: parseFloat(bodyStyles["padding-left"]) || 0, left: parseFloat(bodyStyles["padding-left"]) || 0,
right: parseFloat(bodyStyles["padding-right"]) || 0, right: parseFloat(bodyStyles["padding-right"]) || 0,
top: parseFloat(bodyStyles["padding-top"]) || 0, top: parseFloat(bodyStyles["padding-top"]) || 0,
bottom: parseFloat(bodyStyles["padding-bottom"]) || 0 bottom: parseFloat(bodyStyles["padding-bottom"]) || 0,
}; };
if (!_width) { if (!_width) {
width = _windowBounds.width - width = _windowBounds.width - bodyPadding.left - bodyPadding.right;
bodyPadding.left -
bodyPadding.right;
} }
if ((this.settings.fullsize && !_height) || !_height) { if ((this.settings.fullsize && !_height) || !_height) {
height = _windowBounds.height - height = _windowBounds.height - bodyPadding.top - bodyPadding.bottom;
bodyPadding.top -
bodyPadding.bottom;
} }
return { return {
width: width - width: width - this.containerPadding.left - this.containerPadding.right,
this.containerPadding.left - height: height - this.containerPadding.top - this.containerPadding.bottom,
this.containerPadding.right,
height: height -
this.containerPadding.top -
this.containerPadding.bottom
}; };
} }
bounds(){ bounds() {
let box; let box;
if (this.container.style.overflow !== "visible") { if (this.container.style.overflow !== "visible") {
box = this.container && this.container.getBoundingClientRect(); box = this.container && this.container.getBoundingClientRect();
} }
if(!box || !box.width || !box.height) { if (!box || !box.width || !box.height) {
return windowBounds(); return windowBounds();
} else { } else {
return box; return box;
} }
} }
getSheet(){ getSheet() {
var style = document.createElement("style"); var style = document.createElement("style");
// WebKit hack --> https://davidwalsh.name/add-rules-stylesheets // WebKit hack --> https://davidwalsh.name/add-rules-stylesheets
@ -271,17 +262,17 @@ class Stage {
return style.sheet; return style.sheet;
} }
addStyleRules(selector, rulesArray){ addStyleRules(selector, rulesArray) {
var scope = "#" + this.id + " "; var scope = "#" + this.id + " ";
var rules = ""; var rules = "";
if(!this.sheet){ if (!this.sheet) {
this.sheet = this.getSheet(); this.sheet = this.getSheet();
} }
rulesArray.forEach(function(set) { rulesArray.forEach(function (set) {
for (var prop in set) { for (var prop in set) {
if(set.hasOwnProperty(prop)) { if (set.hasOwnProperty(prop)) {
rules += prop + ":" + set[prop] + ";"; rules += prop + ":" + set[prop] + ";";
} }
} }
@ -291,7 +282,7 @@ class Stage {
} }
axis(axis) { axis(axis) {
if(axis === "horizontal") { if (axis === "horizontal") {
this.container.style.display = "flex"; this.container.style.display = "flex";
this.container.style.flexDirection = "row"; this.container.style.flexDirection = "row";
this.container.style.flexWrap = "nowrap"; this.container.style.flexWrap = "nowrap";
@ -301,16 +292,6 @@ class Stage {
this.settings.axis = axis; this.settings.axis = axis;
} }
// orientation(orientation) {
// if (orientation === "landscape") {
//
// } else {
//
// }
//
// this.orientation = orientation;
// }
direction(dir) { direction(dir) {
if (this.container) { if (this.container) {
this.container.dir = dir; this.container.dir = dir;
@ -339,23 +320,16 @@ class Stage {
} }
destroy() { destroy() {
var base;
if (this.element) { if (this.element) {
if (this.element.contains(this.container)) {
if(this.settings.hidden) {
base = this.wrapper;
} else {
base = this.container;
}
if(this.element.contains(this.container)) {
this.element.removeChild(this.container); this.element.removeChild(this.container);
} }
window.removeEventListener("resize", this.resizeFunc); window.removeEventListener("resize", this.resizeFunc);
window.removeEventListener("orientationChange", this.orientationChangeFunc); window.removeEventListener(
"orientationChange",
this.orientationChangeFunc
);
} }
} }
} }

View file

@ -15,7 +15,7 @@ class Views {
} }
last() { last() {
return this._views[this._views.length-1]; return this._views[this._views.length - 1];
} }
indexOf(view) { indexOf(view) {
@ -30,18 +30,18 @@ class Views {
return this._views[i]; return this._views[i];
} }
append(view){ append(view) {
this._views.push(view); this._views.push(view);
if(this.container){ if (this.container) {
this.container.appendChild(view.element); this.container.appendChild(view.element);
} }
this.length++; this.length++;
return view; return view;
} }
prepend(view){ prepend(view) {
this._views.unshift(view); this._views.unshift(view);
if(this.container){ if (this.container) {
this.container.insertBefore(view.element, this.container.firstChild); this.container.insertBefore(view.element, this.container.firstChild);
} }
this.length++; this.length++;
@ -51,9 +51,12 @@ class Views {
insert(view, index) { insert(view, index) {
this._views.splice(index, 0, view); this._views.splice(index, 0, view);
if(this.container){ if (this.container) {
if(index < this.container.children.length){ if (index < this.container.children.length) {
this.container.insertBefore(view.element, this.container.children[index]); this.container.insertBefore(
view.element,
this.container.children[index]
);
} else { } else {
this.container.appendChild(view.element); this.container.appendChild(view.element);
} }
@ -66,22 +69,21 @@ class Views {
remove(view) { remove(view) {
var index = this._views.indexOf(view); var index = this._views.indexOf(view);
if(index > -1) { if (index > -1) {
this._views.splice(index, 1); this._views.splice(index, 1);
} }
this.destroy(view); this.destroy(view);
this.length--; this.length--;
} }
destroy(view) { destroy(view) {
if(view.displayed){ if (view.displayed) {
view.destroy(); view.destroy();
} }
if(this.container){ if (this.container) {
this.container.removeChild(view.element); this.container.removeChild(view.element);
} }
view = null; view = null;
@ -93,12 +95,12 @@ class Views {
return this._views.forEach.apply(this._views, arguments); return this._views.forEach.apply(this._views, arguments);
} }
clear(){ clear() {
// Remove all views // Remove all views
var view; var view;
var len = this.length; var len = this.length;
if(!this.length) return; if (!this.length) return;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
view = this._views[i]; view = this._views[i];
@ -109,54 +111,52 @@ class Views {
this.length = 0; this.length = 0;
} }
find(section){ find(section) {
var view; var view;
var len = this.length; var len = this.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
view = this._views[i]; view = this._views[i];
if(view.displayed && view.section.index == section.index) { if (view.displayed && view.section.index == section.index) {
return view; return view;
} }
} }
} }
displayed(){ displayed() {
var displayed = []; var displayed = [];
var view; var view;
var len = this.length; var len = this.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
view = this._views[i]; view = this._views[i];
if(view.displayed){ if (view.displayed) {
displayed.push(view); displayed.push(view);
} }
} }
return displayed; return displayed;
} }
show(){ show() {
var view; var view;
var len = this.length; var len = this.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
view = this._views[i]; view = this._views[i];
if(view.displayed){ if (view.displayed) {
view.show(); view.show();
} }
} }
this.hidden = false; this.hidden = false;
} }
hide(){ hide() {
var view; var view;
var len = this.length; var len = this.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
view = this._views[i]; view = this._views[i];
if(view.displayed){ if (view.displayed) {
view.hide(); view.hide();
} }
} }

View file

@ -1,14 +1,24 @@
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import {extend, borders, uuid, isNumber, bounds, defer, createBlobUrl, revokeBlobUrl} from "../../utils/core"; import { Highlight, Pane, Underline } from "marks-pane";
import EpubCFI from "../../epubcfi";
import Contents from "../../contents"; import Contents from "../../contents";
import EpubCFI from "../../epubcfi";
import { EVENTS } from "../../utils/constants"; import { EVENTS } from "../../utils/constants";
import { Pane, Highlight, Underline } from "marks-pane"; import {
borders,
bounds,
createBlobUrl,
defer,
extend,
isNumber,
revokeBlobUrl,
uuid,
} from "../../utils/core";
class IframeView { class IframeView {
constructor(section, options) { constructor(section, options) {
this.settings = extend({ this.settings = extend(
ignoreClass : "", {
ignoreClass: "",
axis: undefined, //options.layout && options.layout.props.flow === "scrolled" ? "vertical" : "horizontal", axis: undefined, //options.layout && options.layout.props.flow === "scrolled" ? "vertical" : "horizontal",
direction: undefined, direction: undefined,
width: 0, width: 0,
@ -18,8 +28,10 @@ class IframeView {
method: undefined, method: undefined,
forceRight: false, forceRight: false,
allowScriptedContent: false, allowScriptedContent: false,
allowPopups: false allowPopups: false,
}, options || {}); },
options || {}
);
this.id = "epubjs-view-" + uuid(); this.id = "epubjs-view-" + uuid();
this.section = section; this.section = section;
@ -48,7 +60,6 @@ class IframeView {
this.highlights = {}; this.highlights = {};
this.underlines = {}; this.underlines = {};
this.marks = {}; this.marks = {};
} }
container(axis) { container(axis) {
@ -63,7 +74,7 @@ class IframeView {
element.style.position = "relative"; element.style.position = "relative";
element.style.display = "block"; element.style.display = "block";
if(axis && axis == "horizontal"){ if (axis && axis == "horizontal") {
element.style.flex = "none"; element.style.flex = "none";
} else { } else {
element.style.flex = "initial"; element.style.flex = "initial";
@ -73,12 +84,11 @@ class IframeView {
} }
create() { create() {
if (this.iframe) {
if(this.iframe) {
return this.iframe; return this.iframe;
} }
if(!this.element) { if (!this.element) {
this.element = this.createContainer(); this.element = this.createContainer();
} }
@ -100,34 +110,18 @@ class IframeView {
} }
this.iframe.setAttribute("enable-annotation", "true"); this.iframe.setAttribute("enable-annotation", "true");
this.resizing = true; this.resizing = true;
// this.iframe.style.display = "none";
this.element.style.visibility = "hidden"; this.element.style.visibility = "hidden";
this.iframe.style.visibility = "hidden"; this.iframe.style.visibility = "hidden";
this.iframe.style.width = "0"; this.iframe.style.width = "0";
this.iframe.style.height = "0"; this.iframe.style.height = "0";
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
this.element.setAttribute("ref", this.index); this.element.setAttribute("ref", this.index);
this.added = true; this.added = true;
this.elementBounds = bounds(this.element); this.elementBounds = bounds(this.element);
// if(width || height){ if ("srcdoc" in this.iframe) {
// this.resize(width, height);
// } else if(this.width && this.height){
// this.resize(this.width, this.height);
// } else {
// this.iframeBounds = bounds(this.iframe);
// }
if(("srcdoc" in this.iframe)) {
this.supportsSrcdoc = true; this.supportsSrcdoc = true;
} else { } else {
this.supportsSrcdoc = false; this.supportsSrcdoc = false;
@ -141,36 +135,40 @@ class IframeView {
} }
render(request, show) { render(request, show) {
// view.onLayout = this.layout.format.bind(this.layout);
this.create(); this.create();
// Fit to size of the container, apply padding // Fit to size of the container, apply padding
this.size(); this.size();
if(!this.sectionRender) { if (!this.sectionRender) {
this.sectionRender = this.section.render(request); this.sectionRender = this.section.render(request);
} }
// Render Chain // Render Chain
return this.sectionRender return this.sectionRender
.then(function(contents){ .then(
function (contents) {
return this.load(contents); return this.load(contents);
}.bind(this)) }.bind(this)
.then(function(){ )
.then(
function () {
// find and report the writingMode axis // find and report the writingMode axis
let writingMode = this.contents.writingMode(); let writingMode = this.contents.writingMode();
// Set the axis based on the flow and writing mode // Set the axis based on the flow and writing mode
let axis; let axis;
if (this.settings.flow === "scrolled") { if (this.settings.flow === "scrolled") {
axis = (writingMode.indexOf("vertical") === 0) ? "horizontal" : "vertical"; axis =
writingMode.indexOf("vertical") === 0 ? "horizontal" : "vertical";
} else { } else {
axis = (writingMode.indexOf("vertical") === 0) ? "vertical" : "horizontal"; axis =
writingMode.indexOf("vertical") === 0 ? "vertical" : "horizontal";
} }
if (writingMode.indexOf("vertical") === 0 && this.settings.flow === "paginated") { if (
writingMode.indexOf("vertical") === 0 &&
this.settings.flow === "paginated"
) {
this.layout.delta = this.layout.height; this.layout.delta = this.layout.height;
} }
@ -180,7 +178,6 @@ class IframeView {
this.setWritingMode(writingMode); this.setWritingMode(writingMode);
this.emit(EVENTS.VIEWS.WRITING_MODE, writingMode); this.emit(EVENTS.VIEWS.WRITING_MODE, writingMode);
// apply the layout function to the contents // apply the layout function to the contents
this.layout.format(this.contents, this.section, this.axis); this.layout.format(this.contents, this.section, this.axis);
@ -196,20 +193,22 @@ class IframeView {
} }
resolve(); resolve();
}); });
}.bind(this),
}.bind(this), function(e){ function (e) {
this.emit(EVENTS.VIEWS.LOAD_ERROR, e); this.emit(EVENTS.VIEWS.LOAD_ERROR, e);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
reject(e); reject(e);
}); });
}.bind(this)) }.bind(this)
.then(function() { )
.then(
function () {
this.emit(EVENTS.VIEWS.RENDERED, this.section); this.emit(EVENTS.VIEWS.RENDERED, this.section);
}.bind(this)); }.bind(this)
);
} }
reset () { reset() {
if (this.iframe) { if (this.iframe) {
this.iframe.style.width = "0"; this.iframe.style.width = "0";
this.iframe.style.height = "0"; this.iframe.style.height = "0";
@ -228,9 +227,9 @@ class IframeView {
var width = _width || this.settings.width; var width = _width || this.settings.width;
var height = _height || this.settings.height; var height = _height || this.settings.height;
if(this.layout.name === "pre-paginated") { if (this.layout.name === "pre-paginated") {
this.lock("both", width, height); this.lock("both", width, height);
} else if(this.settings.axis === "horizontal") { } else if (this.settings.axis === "horizontal") {
this.lock("height", width, height); this.lock("height", width, height);
} else { } else {
this.lock("width", width, height); this.lock("width", width, height);
@ -245,39 +244,28 @@ class IframeView {
var elBorders = borders(this.element); var elBorders = borders(this.element);
var iframeBorders; var iframeBorders;
if(this.iframe) { if (this.iframe) {
iframeBorders = borders(this.iframe); iframeBorders = borders(this.iframe);
} else { } else {
iframeBorders = {width: 0, height: 0}; iframeBorders = { width: 0, height: 0 };
} }
if(what == "width" && isNumber(width)){ if (what == "width" && isNumber(width)) {
this.lockedWidth = width - elBorders.width - iframeBorders.width; this.lockedWidth = width - elBorders.width - iframeBorders.width;
// this.resize(this.lockedWidth, width); // width keeps ratio correct
} }
if(what == "height" && isNumber(height)){ if (what == "height" && isNumber(height)) {
this.lockedHeight = height - elBorders.height - iframeBorders.height; this.lockedHeight = height - elBorders.height - iframeBorders.height;
// this.resize(width, this.lockedHeight);
} }
if(what === "both" && if (what === "both" && isNumber(width) && isNumber(height)) {
isNumber(width) &&
isNumber(height)){
this.lockedWidth = width - elBorders.width - iframeBorders.width; this.lockedWidth = width - elBorders.width - iframeBorders.width;
this.lockedHeight = height - elBorders.height - iframeBorders.height; this.lockedHeight = height - elBorders.height - iframeBorders.height;
// this.resize(this.lockedWidth, this.lockedHeight);
} }
if(this.displayed && this.iframe) { if (this.displayed && this.iframe) {
// this.contents.layout();
this.expand(); this.expand();
} }
} }
// Resize a single axis based on content dimensions // Resize a single axis based on content dimensions
@ -286,47 +274,49 @@ class IframeView {
var height = this.lockedHeight; var height = this.lockedHeight;
var columns; var columns;
var textWidth, textHeight; if (!this.iframe || this._expanding) return;
if(!this.iframe || this._expanding) return;
this._expanding = true; this._expanding = true;
if(this.layout.name === "pre-paginated") { if (this.layout.name === "pre-paginated") {
width = this.layout.columnWidth; width = this.layout.columnWidth;
height = this.layout.height; height = this.layout.height;
} }
// Expand Horizontally // Expand Horizontally
else if(this.settings.axis === "horizontal") { else if (this.settings.axis === "horizontal") {
// Get the width of the text // Get the width of the text
width = this.contents.textWidth(); width = this.contents.textWidth();
if (width % this.layout.pageWidth > 0) { if (width % this.layout.pageWidth > 0) {
width = Math.ceil(width / this.layout.pageWidth) * this.layout.pageWidth; width =
Math.ceil(width / this.layout.pageWidth) * this.layout.pageWidth;
} }
if (this.settings.forceEvenPages) { if (this.settings.forceEvenPages) {
columns = (width / this.layout.pageWidth); columns = width / this.layout.pageWidth;
if ( this.layout.divisor > 1 && if (
this.layout.divisor > 1 &&
this.layout.name === "reflowable" && this.layout.name === "reflowable" &&
(columns % 2 > 0)) { columns % 2 > 0
) {
// add a blank page // add a blank page
width += this.layout.pageWidth; width += this.layout.pageWidth;
} }
} }
} // Expand Vertically } // Expand Vertically
else if(this.settings.axis === "vertical") { else if (this.settings.axis === "vertical") {
height = this.contents.textHeight(); height = this.contents.textHeight();
if (this.settings.flow === "paginated" && if (
height % this.layout.height > 0) { this.settings.flow === "paginated" &&
height % this.layout.height > 0
) {
height = Math.ceil(height / this.layout.height) * this.layout.height; height = Math.ceil(height / this.layout.height) * this.layout.height;
} }
} }
// Only Resize if dimensions have changed or // Only Resize if dimensions have changed or
// if Frame is still hidden, so needs reframing // if Frame is still hidden, so needs reframing
if(this._needsReframe || width != this._width || height != this._height){ if (this._needsReframe || width != this._width || height != this._height) {
this.reframe(width, height); this.reframe(width, height);
} }
@ -336,20 +326,22 @@ class IframeView {
reframe(width, height) { reframe(width, height) {
var size; var size;
if(isNumber(width)){ if (isNumber(width)) {
this.element.style.width = width + "px"; this.element.style.width = width + "px";
this.iframe.style.width = width + "px"; this.iframe.style.width = width + "px";
this._width = width; this._width = width;
} }
if(isNumber(height)){ if (isNumber(height)) {
this.element.style.height = height + "px"; this.element.style.height = height + "px";
this.iframe.style.height = height + "px"; this.iframe.style.height = height + "px";
this._height = height; this._height = height;
} }
let widthDelta = this.prevBounds ? width - this.prevBounds.width : width; let widthDelta = this.prevBounds ? width - this.prevBounds.width : width;
let heightDelta = this.prevBounds ? height - this.prevBounds.height : height; let heightDelta = this.prevBounds
? height - this.prevBounds.height
: height;
size = { size = {
width: width, width: width,
@ -377,46 +369,41 @@ class IframeView {
this.prevBounds = size; this.prevBounds = size;
this.elementBounds = bounds(this.element); this.elementBounds = bounds(this.element);
} }
load(contents) { load(contents) {
var loading = new defer(); var loading = new defer();
var loaded = loading.promise; var loaded = loading.promise;
if(!this.iframe) { if (!this.iframe) {
loading.reject(new Error("No Iframe Available")); loading.reject(new Error("No Iframe Available"));
return loaded; return loaded;
} }
this.iframe.onload = function(event) { this.iframe.onload = function (event) {
this.onLoad(event, loading); this.onLoad(event, loading);
}.bind(this); }.bind(this);
if (this.settings.method === "blobUrl") { if (this.settings.method === "blobUrl") {
this.blobUrl = createBlobUrl(contents, "application/xhtml+xml"); this.blobUrl = createBlobUrl(contents, "application/xhtml+xml");
this.iframe.src = this.blobUrl; this.iframe.src = this.blobUrl;
this.element.appendChild(this.iframe); this.element.appendChild(this.iframe);
} else if(this.settings.method === "srcdoc"){ } else if (this.settings.method === "srcdoc") {
this.iframe.srcdoc = contents; this.iframe.srcdoc = contents;
this.element.appendChild(this.iframe); this.element.appendChild(this.iframe);
} else { } else {
this.element.appendChild(this.iframe); this.element.appendChild(this.iframe);
this.document = this.iframe.contentDocument; this.document = this.iframe.contentDocument;
if(!this.document) { if (!this.document) {
loading.reject(new Error("No Document Available")); loading.reject(new Error("No Document Available"));
return loaded; return loaded;
} }
this.iframe.contentDocument.open(); this.iframe.contentDocument.open();
// For Cordova windows platform // For Cordova windows platform
if(window.MSApp && MSApp.execUnsafeLocalFunction) { if (window.MSApp && MSApp.execUnsafeLocalFunction) {
var outerThis = this; var outerThis = this;
MSApp.execUnsafeLocalFunction(function () { MSApp.execUnsafeLocalFunction(function () {
outerThis.iframe.contentDocument.write(contents); outerThis.iframe.contentDocument.write(contents);
@ -425,18 +412,21 @@ class IframeView {
this.iframe.contentDocument.write(contents); this.iframe.contentDocument.write(contents);
} }
this.iframe.contentDocument.close(); this.iframe.contentDocument.close();
} }
return loaded; return loaded;
} }
onLoad(event, promise) { onLoad(event, promise) {
this.window = this.iframe.contentWindow; this.window = this.iframe.contentWindow;
this.document = this.iframe.contentDocument; this.document = this.iframe.contentDocument;
this.contents = new Contents(this.document, this.document.body, this.section.cfiBase, this.section.index); this.contents = new Contents(
this.document,
this.document.body,
this.section.cfiBase,
this.section.index
);
this.rendering = false; this.rendering = false;
@ -451,7 +441,7 @@ class IframeView {
} }
this.contents.on(EVENTS.CONTENTS.EXPAND, () => { this.contents.on(EVENTS.CONTENTS.EXPAND, () => {
if(this.displayed && this.iframe) { if (this.displayed && this.iframe) {
this.expand(); this.expand();
if (this.contents) { if (this.contents) {
this.layout.format(this.contents); this.layout.format(this.contents);
@ -460,7 +450,7 @@ class IframeView {
}); });
this.contents.on(EVENTS.CONTENTS.RESIZE, (e) => { this.contents.on(EVENTS.CONTENTS.RESIZE, (e) => {
if(this.displayed && this.iframe) { if (this.displayed && this.iframe) {
this.expand(); this.expand();
if (this.contents) { if (this.contents) {
this.layout.format(this.contents); this.layout.format(this.contents);
@ -481,21 +471,18 @@ class IframeView {
} }
setAxis(axis) { setAxis(axis) {
this.settings.axis = axis; this.settings.axis = axis;
if(axis == "horizontal"){ if (axis == "horizontal") {
this.element.style.flex = "none"; this.element.style.flex = "none";
} else { } else {
this.element.style.flex = "initial"; this.element.style.flex = "initial";
} }
this.size(); this.size();
} }
setWritingMode(mode) { setWritingMode(mode) {
// this.element.style.writingMode = writingMode;
this.writingMode = mode; this.writingMode = mode;
} }
@ -511,33 +498,29 @@ class IframeView {
var displayed = new defer(); var displayed = new defer();
if (!this.displayed) { if (!this.displayed) {
this.render(request).then(
this.render(request) function () {
.then(function () {
this.emit(EVENTS.VIEWS.DISPLAYED, this); this.emit(EVENTS.VIEWS.DISPLAYED, this);
this.onDisplayed(this); this.onDisplayed(this);
this.displayed = true; this.displayed = true;
displayed.resolve(this); displayed.resolve(this);
}.bind(this),
}.bind(this), function (err) { function (err) {
displayed.reject(err, this); displayed.reject(err, this);
}); }
);
} else { } else {
displayed.resolve(this); displayed.resolve(this);
} }
return displayed.promise; return displayed.promise;
} }
show() { show() {
this.element.style.visibility = "visible"; this.element.style.visibility = "visible";
if(this.iframe){ if (this.iframe) {
this.iframe.style.visibility = "visible"; this.iframe.style.visibility = "visible";
// Remind Safari to redraw the iframe // Remind Safari to redraw the iframe
@ -550,7 +533,6 @@ class IframeView {
} }
hide() { hide() {
// this.iframe.style.display = "none";
this.element.style.visibility = "hidden"; this.element.style.visibility = "hidden";
this.iframe.style.visibility = "hidden"; this.iframe.style.visibility = "hidden";
@ -561,8 +543,8 @@ class IframeView {
offset() { offset() {
return { return {
top: this.element.offsetTop, top: this.element.offsetTop,
left: this.element.offsetLeft left: this.element.offsetLeft,
} };
} }
width() { width() {
@ -578,12 +560,11 @@ class IframeView {
} }
locationOf(target) { locationOf(target) {
var parentPos = this.iframe.getBoundingClientRect();
var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
return { return {
"left": targetPos.left, left: targetPos.left,
"top": targetPos.top top: targetPos.top,
}; };
} }
@ -596,18 +577,21 @@ class IframeView {
} }
bounds(force) { bounds(force) {
if(force || !this.elementBounds) { if (force || !this.elementBounds) {
this.elementBounds = bounds(this.element); this.elementBounds = bounds(this.element);
} }
return this.elementBounds; return this.elementBounds;
} }
highlight(cfiRange, data={}, cb, className = "epubjs-hl", styles = {}) { highlight(cfiRange, data = {}, cb, className = "epubjs-hl", styles = {}) {
if (!this.contents) { if (!this.contents) {
return; return;
} }
const attributes = Object.assign({"fill": "yellow", "fill-opacity": "0.3", "mix-blend-mode": "multiply"}, styles); const attributes = Object.assign(
{ fill: "yellow", "fill-opacity": "0.3", "mix-blend-mode": "multiply" },
styles
);
let range = this.contents.range(cfiRange); let range = this.contents.range(cfiRange);
let emitter = () => { let emitter = () => {
@ -623,7 +607,11 @@ class IframeView {
let m = new Highlight(range, className, data, attributes); let m = new Highlight(range, className, data, attributes);
let h = this.pane.addMark(m); let h = this.pane.addMark(m);
this.highlights[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] }; this.highlights[cfiRange] = {
mark: h,
element: h.element,
listeners: [emitter, cb],
};
h.element.setAttribute("ref", className); h.element.setAttribute("ref", className);
h.element.addEventListener("click", emitter); h.element.addEventListener("click", emitter);
@ -636,11 +624,18 @@ class IframeView {
return h; return h;
} }
underline(cfiRange, data={}, cb, className = "epubjs-ul", styles = {}) { underline(cfiRange, data = {}, cb, className = "epubjs-ul", styles = {}) {
if (!this.contents) { if (!this.contents) {
return; return;
} }
const attributes = Object.assign({"stroke": "black", "stroke-opacity": "0.3", "mix-blend-mode": "multiply"}, styles); const attributes = Object.assign(
{
stroke: "black",
"stroke-opacity": "0.3",
"mix-blend-mode": "multiply",
},
styles
);
let range = this.contents.range(cfiRange); let range = this.contents.range(cfiRange);
let emitter = () => { let emitter = () => {
this.emit(EVENTS.VIEWS.MARK_CLICKED, cfiRange, data); this.emit(EVENTS.VIEWS.MARK_CLICKED, cfiRange, data);
@ -655,7 +650,11 @@ class IframeView {
let m = new Underline(range, className, data, attributes); let m = new Underline(range, className, data, attributes);
let h = this.pane.addMark(m); let h = this.pane.addMark(m);
this.underlines[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] }; this.underlines[cfiRange] = {
mark: h,
element: h.element,
listeners: [emitter, cb],
};
h.element.setAttribute("ref", className); h.element.setAttribute("ref", className);
h.element.addEventListener("click", emitter); h.element.addEventListener("click", emitter);
@ -668,7 +667,7 @@ class IframeView {
return h; return h;
} }
mark(cfiRange, data={}, cb) { mark(cfiRange, data = {}, cb) {
if (!this.contents) { if (!this.contents) {
return; return;
} }
@ -683,7 +682,7 @@ class IframeView {
return; return;
} }
let container = range.commonAncestorContainer; let container = range.commonAncestorContainer;
let parent = (container.nodeType === 1) ? container : container.parentNode; let parent = container.nodeType === 1 ? container : container.parentNode;
let emitter = (e) => { let emitter = (e) => {
this.emit(EVENTS.VIEWS.MARK_CLICKED, cfiRange, data); this.emit(EVENTS.VIEWS.MARK_CLICKED, cfiRange, data);
@ -692,7 +691,8 @@ class IframeView {
if (range.collapsed && container.nodeType === 1) { if (range.collapsed && container.nodeType === 1) {
range = new Range(); range = new Range();
range.selectNodeContents(container); range.selectNodeContents(container);
} else if (range.collapsed) { // Webkit doesn't like collapsed ranges } else if (range.collapsed) {
// Webkit doesn't like collapsed ranges
range = new Range(); range = new Range();
range.selectNodeContents(parent); range.selectNodeContents(parent);
} }
@ -721,7 +721,11 @@ class IframeView {
this.element.appendChild(mark); this.element.appendChild(mark);
this.marks[cfiRange] = { "element": mark, "range": range, "listeners": [emitter, cb] }; this.marks[cfiRange] = {
element: mark,
range: range,
listeners: [emitter, cb],
};
return parent; return parent;
} }
@ -729,8 +733,10 @@ class IframeView {
placeMark(element, range) { placeMark(element, range) {
let top, right, left; let top, right, left;
if(this.layout.name === "pre-paginated" || if (
this.settings.axis !== "horizontal") { this.layout.name === "pre-paginated" ||
this.settings.axis !== "horizontal"
) {
let pos = range.getBoundingClientRect(); let pos = range.getBoundingClientRect();
top = pos.top; top = pos.top;
right = pos.right; right = pos.right;
@ -743,8 +749,10 @@ class IframeView {
rect = rects[i]; rect = rects[i];
if (!left || rect.left < left) { if (!left || rect.left < left) {
left = rect.left; left = rect.left;
// right = rect.right; right =
right = Math.ceil(left / this.layout.props.pageWidth) * this.layout.props.pageWidth - (this.layout.gap / 2); Math.ceil(left / this.layout.props.pageWidth) *
this.layout.props.pageWidth -
this.layout.gap / 2;
top = rect.top; top = rect.top;
} }
} }
@ -764,7 +772,7 @@ class IframeView {
if (l) { if (l) {
item.element.removeEventListener("click", l); item.element.removeEventListener("click", l);
item.element.removeEventListener("touchstart", l); item.element.removeEventListener("touchstart", l);
}; }
}); });
delete this.highlights[cfiRange]; delete this.highlights[cfiRange];
} }
@ -779,7 +787,7 @@ class IframeView {
if (l) { if (l) {
item.element.removeEventListener("click", l); item.element.removeEventListener("click", l);
item.element.removeEventListener("touchstart", l); item.element.removeEventListener("touchstart", l);
}; }
}); });
delete this.underlines[cfiRange]; delete this.underlines[cfiRange];
} }
@ -794,14 +802,13 @@ class IframeView {
if (l) { if (l) {
item.element.removeEventListener("click", l); item.element.removeEventListener("click", l);
item.element.removeEventListener("touchstart", l); item.element.removeEventListener("touchstart", l);
}; }
}); });
delete this.marks[cfiRange]; delete this.marks[cfiRange];
} }
} }
destroy() { destroy() {
for (let cfiRange in this.highlights) { for (let cfiRange in this.highlights) {
this.unhighlight(cfiRange); this.unhighlight(cfiRange);
} }
@ -818,7 +825,7 @@ class IframeView {
revokeBlobUrl(this.blobUrl); revokeBlobUrl(this.blobUrl);
} }
if(this.displayed){ if (this.displayed) {
this.displayed = false; this.displayed = false;
this.removeListeners(); this.removeListeners();
@ -840,9 +847,6 @@ class IframeView {
this._width = null; this._width = null;
this._height = null; this._height = null;
} }
// this.element.style.height = "0px";
// this.element.style.width = "0px";
} }
} }

View file

@ -1,19 +1,31 @@
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import {extend, borders, uuid, isNumber, bounds, defer, qs, parse} from "../../utils/core";
import EpubCFI from "../../epubcfi";
import Contents from "../../contents"; import Contents from "../../contents";
import EpubCFI from "../../epubcfi";
import { EVENTS } from "../../utils/constants"; import { EVENTS } from "../../utils/constants";
import {
borders,
bounds,
defer,
extend,
isNumber,
parse,
qs,
uuid,
} from "../../utils/core";
class InlineView { class InlineView {
constructor(section, options) { constructor(section, options) {
this.settings = extend({ this.settings = extend(
ignoreClass : "", {
ignoreClass: "",
axis: "vertical", axis: "vertical",
width: 0, width: 0,
height: 0, height: 0,
layout: undefined, layout: undefined,
globalLayoutProperties: {}, globalLayoutProperties: {},
}, options || {}); },
options || {}
);
this.id = "epubjs-view:" + uuid(); this.id = "epubjs-view:" + uuid();
this.section = section; this.section = section;
@ -35,27 +47,14 @@ class InlineView {
this.epubcfi = new EpubCFI(); this.epubcfi = new EpubCFI();
this.layout = this.settings.layout; this.layout = this.settings.layout;
// Dom events to listen for
// this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
} }
container(axis) { container(axis) {
var element = document.createElement("div"); var element = document.createElement("div");
element.classList.add("epub-view"); element.classList.add("epub-view");
// if(this.settings.axis === "horizontal") {
// element.style.width = "auto";
// element.style.height = "0";
// } else {
// element.style.width = "0";
// element.style.height = "auto";
// }
element.style.overflow = "hidden"; element.style.overflow = "hidden";
if(axis && axis == "horizontal"){ if (axis && axis == "horizontal") {
element.style.display = "inline-block"; element.style.display = "inline-block";
} else { } else {
element.style.display = "block"; element.style.display = "block";
@ -65,12 +64,11 @@ class InlineView {
} }
create() { create() {
if (this.frame) {
if(this.frame) {
return this.frame; return this.frame;
} }
if(!this.element) { if (!this.element) {
this.element = this.createContainer(); this.element = this.createContainer();
} }
@ -82,11 +80,10 @@ class InlineView {
this.resizing = true; this.resizing = true;
// this.frame.style.display = "none";
this.element.style.visibility = "hidden"; this.element.style.visibility = "hidden";
this.frame.style.visibility = "hidden"; this.frame.style.visibility = "hidden";
if(this.settings.axis === "horizontal") { if (this.settings.axis === "horizontal") {
this.frame.style.width = "auto"; this.frame.style.width = "auto";
this.frame.style.height = "0"; this.frame.style.height = "0";
} else { } else {
@ -106,56 +103,37 @@ class InlineView {
} }
render(request, show) { render(request, show) {
// view.onLayout = this.layout.format.bind(this.layout);
this.create(); this.create();
// Fit to size of the container, apply padding // Fit to size of the container, apply padding
this.size(); this.size();
// Render Chain // Render Chain
return this.section.render(request) return this.section
.then(function(contents){ .render(request)
.then(
function (contents) {
return this.load(contents); return this.load(contents);
}.bind(this)) }.bind(this)
// .then(function(doc){ )
// return this.hooks.content.trigger(view, this); .then(function () {}.bind(this))
// }.bind(this)) .then(
.then(function(){ function () {
// this.settings.layout.format(view.contents);
// return this.hooks.layout.trigger(view, this);
}.bind(this))
// .then(function(){
// return this.display();
// }.bind(this))
// .then(function(){
// return this.hooks.render.trigger(view, this);
// }.bind(this))
.then(function(){
// apply the layout function to the contents // apply the layout function to the contents
this.settings.layout.format(this.contents); this.settings.layout.format(this.contents);
// Expand the iframe to the full size of the content
// this.expand();
// Listen for events that require an expansion of the iframe // Listen for events that require an expansion of the iframe
this.addListeners(); this.addListeners();
if(show !== false) { if (show !== false) {
//this.q.enqueue(function(view){
this.show(); this.show();
//}, view);
} }
// this.map = new Map(view, this.layout);
//this.hooks.show.trigger(view, this);
this.emit(EVENTS.VIEWS.RENDERED, this.section); this.emit(EVENTS.VIEWS.RENDERED, this.section);
}.bind(this)
}.bind(this)) )
.catch(function(e){ .catch(
function (e) {
this.emit(EVENTS.VIEWS.LOAD_ERROR, e); this.emit(EVENTS.VIEWS.LOAD_ERROR, e);
}.bind(this)); }.bind(this)
);
} }
// Determine locks base on settings // Determine locks base on settings
@ -163,15 +141,14 @@ class InlineView {
var width = _width || this.settings.width; var width = _width || this.settings.width;
var height = _height || this.settings.height; var height = _height || this.settings.height;
if(this.layout.name === "pre-paginated") { if (this.layout.name === "pre-paginated") {
// TODO: check if these are different than the size set in chapter // TODO: check if these are different than the size set in chapter
this.lock("both", width, height); this.lock("both", width, height);
} else if(this.settings.axis === "horizontal") { } else if (this.settings.axis === "horizontal") {
this.lock("height", width, height); this.lock("height", width, height);
} else { } else {
this.lock("width", width, height); this.lock("width", width, height);
} }
} }
// Lock an axis to element dimensions, taking borders into account // Lock an axis to element dimensions, taking borders into account
@ -179,32 +156,28 @@ class InlineView {
var elBorders = borders(this.element); var elBorders = borders(this.element);
var iframeBorders; var iframeBorders;
if(this.frame) { if (this.frame) {
iframeBorders = borders(this.frame); iframeBorders = borders(this.frame);
} else { } else {
iframeBorders = {width: 0, height: 0}; iframeBorders = { width: 0, height: 0 };
} }
if(what == "width" && isNumber(width)){ if (what == "width" && isNumber(width)) {
this.lockedWidth = width - elBorders.width - iframeBorders.width; this.lockedWidth = width - elBorders.width - iframeBorders.width;
this.resize(this.lockedWidth, false); // width keeps ratio correct this.resize(this.lockedWidth, false); // width keeps ratio correct
} }
if(what == "height" && isNumber(height)){ if (what == "height" && isNumber(height)) {
this.lockedHeight = height - elBorders.height - iframeBorders.height; this.lockedHeight = height - elBorders.height - iframeBorders.height;
this.resize(false, this.lockedHeight); this.resize(false, this.lockedHeight);
} }
if(what === "both" && if (what === "both" && isNumber(width) && isNumber(height)) {
isNumber(width) &&
isNumber(height)){
this.lockedWidth = width - elBorders.width - iframeBorders.width; this.lockedWidth = width - elBorders.width - iframeBorders.width;
this.lockedHeight = height - elBorders.height - iframeBorders.height; this.lockedHeight = height - elBorders.height - iframeBorders.height;
this.resize(this.lockedWidth, this.lockedHeight); this.resize(this.lockedWidth, this.lockedHeight);
} }
} }
// Resize a single axis based on content dimensions // Resize a single axis based on content dimensions
@ -214,21 +187,21 @@ class InlineView {
var textWidth, textHeight; var textWidth, textHeight;
if(!this.frame || this._expanding) return; if (!this.frame || this._expanding) return;
this._expanding = true; this._expanding = true;
// Expand Horizontally // Expand Horizontally
if(this.settings.axis === "horizontal") { if (this.settings.axis === "horizontal") {
width = this.contentWidth(textWidth); width = this.contentWidth(textWidth);
} // Expand Vertically } // Expand Vertically
else if(this.settings.axis === "vertical") { else if (this.settings.axis === "vertical") {
height = this.contentHeight(textHeight); height = this.contentHeight(textHeight);
} }
// Only Resize if dimensions have changed or // Only Resize if dimensions have changed or
// if Frame is still hidden, so needs reframing // if Frame is still hidden, so needs reframing
if(this._needsReframe || width != this._width || height != this._height){ if (this._needsReframe || width != this._width || height != this._height) {
this.resize(width, height); this.resize(width, height);
} }
@ -243,17 +216,15 @@ class InlineView {
return this.frame.scrollHeight; return this.frame.scrollHeight;
} }
resize(width, height) { resize(width, height) {
if (!this.frame) return;
if(!this.frame) return; if (isNumber(width)) {
if(isNumber(width)){
this.frame.style.width = width + "px"; this.frame.style.width = width + "px";
this._width = width; this._width = width;
} }
if(isNumber(height)){ if (isNumber(height)) {
this.frame.style.height = height + "px"; this.frame.style.height = height + "px";
this._height = height; this._height = height;
} }
@ -272,32 +243,13 @@ class InlineView {
this.onResize(this, size); this.onResize(this, size);
this.emit(EVENTS.VIEWS.RESIZED, size); this.emit(EVENTS.VIEWS.RESIZED, size);
} }
load(contents) { load(contents) {
var loading = new defer(); var loading = new defer();
var loaded = loading.promise; var loaded = loading.promise;
var doc = parse(contents, "text/html"); var doc = parse(contents, "text/html");
var body = qs(doc, "body"); var body = qs(doc, "body");
/*
var srcs = doc.querySelectorAll("[src]");
Array.prototype.slice.call(srcs)
.forEach(function(item) {
var src = item.getAttribute("src");
var assetUri = URI(src);
var origin = assetUri.origin();
var absoluteUri;
if (!origin) {
absoluteUri = assetUri.absoluteTo(this.section.url);
item.src = absoluteUri;
}
}.bind(this));
*/
this.frame.innerHTML = body.innerHTML; this.frame.innerHTML = body.innerHTML;
this.document = this.frame.ownerDocument; this.document = this.frame.ownerDocument;
@ -309,7 +261,6 @@ class InlineView {
loading.resolve(this.contents); loading.resolve(this.contents);
return loaded; return loaded;
} }
@ -317,12 +268,7 @@ class InlineView {
this.layout = layout; this.layout = layout;
} }
resizeListenters() {}
resizeListenters() {
// Test size again
// clearTimeout(this.expanding);
// this.expanding = setTimeout(this.expand.bind(this), 350);
}
addListeners() { addListeners() {
//TODO: Add content listeners for expanding //TODO: Add content listeners for expanding
@ -336,31 +282,27 @@ class InlineView {
var displayed = new defer(); var displayed = new defer();
if (!this.displayed) { if (!this.displayed) {
this.render(request).then(
this.render(request).then(function () { function () {
this.emit(EVENTS.VIEWS.DISPLAYED, this); this.emit(EVENTS.VIEWS.DISPLAYED, this);
this.onDisplayed(this); this.onDisplayed(this);
this.displayed = true; this.displayed = true;
displayed.resolve(this); displayed.resolve(this);
}.bind(this)
}.bind(this)); );
} else { } else {
displayed.resolve(this); displayed.resolve(this);
} }
return displayed.promise; return displayed.promise;
} }
show() { show() {
this.element.style.visibility = "visible"; this.element.style.visibility = "visible";
if(this.frame){ if (this.frame) {
this.frame.style.visibility = "visible"; this.frame.style.visibility = "visible";
} }
@ -368,7 +310,6 @@ class InlineView {
} }
hide() { hide() {
// this.frame.style.display = "none";
this.element.style.visibility = "hidden"; this.element.style.visibility = "hidden";
this.frame.style.visibility = "hidden"; this.frame.style.visibility = "hidden";
@ -385,8 +326,8 @@ class InlineView {
var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
return { return {
"left": window.scrollX + parentPos.left + targetPos.left, left: window.scrollX + parentPos.left + targetPos.left,
"top": window.scrollY + parentPos.top + targetPos.top top: window.scrollY + parentPos.top + targetPos.top,
}; };
} }
@ -399,15 +340,14 @@ class InlineView {
} }
bounds() { bounds() {
if(!this.elementBounds) { if (!this.elementBounds) {
this.elementBounds = bounds(this.element); this.elementBounds = bounds(this.element);
} }
return this.elementBounds; return this.elementBounds;
} }
destroy() { destroy() {
if (this.displayed) {
if(this.displayed){
this.displayed = false; this.displayed = false;
this.removeListeners(); this.removeListeners();
@ -422,8 +362,6 @@ class InlineView {
this._width = null; this._width = null;
this._height = null; this._height = null;
} }
// this.element.style.height = "0px";
// this.element.style.width = "0px";
} }
} }

View file

@ -10,9 +10,9 @@ import { nodeBounds } from "./utils/core";
* @param {boolean} [dev] toggle developer highlighting * @param {boolean} [dev] toggle developer highlighting
*/ */
class Mapping { class Mapping {
constructor(layout, direction, axis, dev=false) { constructor(layout, direction, axis, dev = false) {
this.layout = layout; this.layout = layout;
this.horizontal = (axis === "horizontal") ? true : false; this.horizontal = axis === "horizontal" ? true : false;
this.direction = direction || "ltr"; this.direction = direction || "ltr";
this._dev = dev; this._dev = dev;
} }
@ -44,7 +44,7 @@ class Mapping {
result = this.rangePairToCfiPair(cfiBase, { result = this.rangePairToCfiPair(cfiBase, {
start: this.findStart(root, start, end), start: this.findStart(root, start, end),
end: this.findEnd(root, start, end) end: this.findEnd(root, start, end),
}); });
if (this._dev === true) { if (this._dev === true) {
@ -74,38 +74,43 @@ class Mapping {
// IE11 has strange issue, if root is text node IE throws exception on // IE11 has strange issue, if root is text node IE throws exception on
// calling treeWalker.nextNode(), saying // calling treeWalker.nextNode(), saying
// Unexpected call to method or property access instead of returning null value // Unexpected call to method or property access instead of returning null value
if(root && root.nodeType === Node.TEXT_NODE) { if (root && root.nodeType === Node.TEXT_NODE) {
return; return;
} }
// safeFilter is required so that it can work in IE as filter is a function for IE // safeFilter is required so that it can work in IE as filter is a function for IE
// and for other browser filter is an object. // and for other browser filter is an object.
var filter = { var filter = {
acceptNode: function(node) { acceptNode: function (node) {
if (node.data.trim().length > 0) { if (node.data.trim().length > 0) {
return NodeFilter.FILTER_ACCEPT; return NodeFilter.FILTER_ACCEPT;
} else { } else {
return NodeFilter.FILTER_REJECT; return NodeFilter.FILTER_REJECT;
} }
} },
}; };
var safeFilter = filter.acceptNode; var safeFilter = filter.acceptNode;
safeFilter.acceptNode = filter.acceptNode; safeFilter.acceptNode = filter.acceptNode;
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, safeFilter, false); var treeWalker = document.createTreeWalker(
root,
NodeFilter.SHOW_TEXT,
safeFilter,
false
);
var node; var node;
var result; var result;
while ((node = treeWalker.nextNode())) { while ((node = treeWalker.nextNode())) {
result = func(node); result = func(node);
if(result) break; if (result) break;
} }
return result; return result;
} }
findRanges(view){ findRanges(view) {
var columns = []; var columns = [];
var scrollWidth = view.contents.scrollWidth(); var scrollWidth = view.contents.scrollWidth();
var spreads = Math.ceil( scrollWidth / this.layout.spreadWidth); var spreads = Math.ceil(scrollWidth / this.layout.spreadWidth);
var count = spreads * this.layout.divisor; var count = spreads * this.layout.divisor;
var columnWidth = this.layout.columnWidth; var columnWidth = this.layout.columnWidth;
var gap = this.layout.gap; var gap = this.layout.gap;
@ -113,10 +118,10 @@ class Mapping {
for (var i = 0; i < count.pages; i++) { for (var i = 0; i < count.pages; i++) {
start = (columnWidth + gap) * i; start = (columnWidth + gap) * i;
end = (columnWidth * (i+1)) + (gap * i); end = columnWidth * (i + 1) + gap * i;
columns.push({ columns.push({
start: this.findStart(view.document.body, start, end), start: this.findStart(view.document.body, start, end),
end: this.findEnd(view.document.body, start, end) end: this.findEnd(view.document.body, start, end),
}); });
} }
@ -131,30 +136,26 @@ class Mapping {
* @param {number} end position to end at * @param {number} end position to end at
* @return {Range} * @return {Range}
*/ */
findStart(root, start, end){ findStart(root, start, end) {
var stack = [root]; var stack = [root];
var $el; var $el;
var found; var found;
var $prev = root; var $prev = root;
while (stack.length) { while (stack.length) {
$el = stack.shift(); $el = stack.shift();
found = this.walk($el, (node) => { found = this.walk($el, (node) => {
var left, right, top, bottom; var left, right, top, bottom;
var elPos; var elPos;
var elRange;
elPos = nodeBounds(node); elPos = nodeBounds(node);
if (this.horizontal && this.direction === "ltr") { if (this.horizontal && this.direction === "ltr") {
left = this.horizontal ? elPos.left : elPos.top; left = this.horizontal ? elPos.left : elPos.top;
right = this.horizontal ? elPos.right : elPos.bottom; right = this.horizontal ? elPos.right : elPos.bottom;
if( left >= start && left <= end ) { if (left >= start && left <= end) {
return node; return node;
} else if (right > start) { } else if (right > start) {
return node; return node;
@ -162,13 +163,11 @@ class Mapping {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} else if (this.horizontal && this.direction === "rtl") { } else if (this.horizontal && this.direction === "rtl") {
left = elPos.left; left = elPos.left;
right = elPos.right; right = elPos.right;
if( right <= end && right >= start ) { if (right <= end && right >= start) {
return node; return node;
} else if (left < end) { } else if (left < end) {
return node; return node;
@ -176,13 +175,11 @@ class Mapping {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} else { } else {
top = elPos.top; top = elPos.top;
bottom = elPos.bottom; bottom = elPos.bottom;
if( top >= start && top <= end ) { if (top >= start && top <= end) {
return node; return node;
} else if (bottom > start) { } else if (bottom > start) {
return node; return node;
@ -190,16 +187,12 @@ class Mapping {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} }
}); });
if(found) { if (found) {
return this.findTextStartRange(found, start, end); return this.findTextStartRange(found, start, end);
} }
} }
// Return last element // Return last element
@ -214,75 +207,63 @@ class Mapping {
* @param {number} end position to end at * @param {number} end position to end at
* @return {Range} * @return {Range}
*/ */
findEnd(root, start, end){ findEnd(root, start, end) {
var stack = [root]; var stack = [root];
var $el; var $el;
var $prev = root; var $prev = root;
var found; var found;
while (stack.length) { while (stack.length) {
$el = stack.shift(); $el = stack.shift();
found = this.walk($el, (node) => { found = this.walk($el, (node) => {
var left, right, top, bottom; var left, right, top, bottom;
var elPos; var elPos;
var elRange;
elPos = nodeBounds(node); elPos = nodeBounds(node);
if (this.horizontal && this.direction === "ltr") { if (this.horizontal && this.direction === "ltr") {
left = Math.round(elPos.left); left = Math.round(elPos.left);
right = Math.round(elPos.right); right = Math.round(elPos.right);
if(left > end && $prev) { if (left > end && $prev) {
return $prev; return $prev;
} else if(right > end) { } else if (right > end) {
return node; return node;
} else { } else {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} else if (this.horizontal && this.direction === "rtl") { } else if (this.horizontal && this.direction === "rtl") {
left = Math.round(this.horizontal ? elPos.left : elPos.top); left = Math.round(this.horizontal ? elPos.left : elPos.top);
right = Math.round(this.horizontal ? elPos.right : elPos.bottom); right = Math.round(this.horizontal ? elPos.right : elPos.bottom);
if(right < start && $prev) { if (right < start && $prev) {
return $prev; return $prev;
} else if(left < start) { } else if (left < start) {
return node; return node;
} else { } else {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} else { } else {
top = Math.round(elPos.top); top = Math.round(elPos.top);
bottom = Math.round(elPos.bottom); bottom = Math.round(elPos.bottom);
if(top > end && $prev) { if (top > end && $prev) {
return $prev; return $prev;
} else if(bottom > end) { } else if (bottom > end) {
return node; return node;
} else { } else {
$prev = node; $prev = node;
stack.push(node); stack.push(node);
} }
} }
}); });
if (found) {
if(found){
return this.findTextEndRange(found, start, end); return this.findTextEndRange(found, start, end);
} }
} }
// end of chapter // end of chapter
@ -297,7 +278,7 @@ class Mapping {
* @param {number} end position to end at * @param {number} end position to end at
* @return {Range} * @return {Range}
*/ */
findTextStartRange(node, start, end){ findTextStartRange(node, start, end) {
var ranges = this.splitTextNodeIntoRanges(node); var ranges = this.splitTextNodeIntoRanges(node);
var range; var range;
var pos; var pos;
@ -309,30 +290,21 @@ class Mapping {
pos = range.getBoundingClientRect(); pos = range.getBoundingClientRect();
if (this.horizontal && this.direction === "ltr") { if (this.horizontal && this.direction === "ltr") {
left = pos.left; left = pos.left;
if( left >= start ) { if (left >= start) {
return range; return range;
} }
} else if (this.horizontal && this.direction === "rtl") { } else if (this.horizontal && this.direction === "rtl") {
right = pos.right; right = pos.right;
if( right <= end ) { if (right <= end) {
return range; return range;
} }
} else { } else {
top = pos.top; top = pos.top;
if( top >= start ) { if (top >= start) {
return range; return range;
} }
} }
// prev = range;
} }
return ranges[0]; return ranges[0];
@ -346,7 +318,7 @@ class Mapping {
* @param {number} end position to end at * @param {number} end position to end at
* @return {Range} * @return {Range}
*/ */
findTextEndRange(node, start, end){ findTextEndRange(node, start, end) {
var ranges = this.splitTextNodeIntoRanges(node); var ranges = this.splitTextNodeIntoRanges(node);
var prev; var prev;
var range; var range;
@ -359,48 +331,39 @@ class Mapping {
pos = range.getBoundingClientRect(); pos = range.getBoundingClientRect();
if (this.horizontal && this.direction === "ltr") { if (this.horizontal && this.direction === "ltr") {
left = pos.left; left = pos.left;
right = pos.right; right = pos.right;
if(left > end && prev) { if (left > end && prev) {
return prev; return prev;
} else if(right > end) { } else if (right > end) {
return range; return range;
} }
} else if (this.horizontal && this.direction === "rtl") { } else if (this.horizontal && this.direction === "rtl") {
left = pos.left;
left = pos.left
right = pos.right; right = pos.right;
if(right < start && prev) { if (right < start && prev) {
return prev; return prev;
} else if(left < start) { } else if (left < start) {
return range; return range;
} }
} else { } else {
top = pos.top; top = pos.top;
bottom = pos.bottom; bottom = pos.bottom;
if(top > end && prev) { if (top > end && prev) {
return prev; return prev;
} else if(bottom > end) { } else if (bottom > end) {
return range; return range;
} }
} }
prev = range; prev = range;
} }
// Ends before limit // Ends before limit
return ranges[ranges.length-1]; return ranges[ranges.length - 1];
} }
/** /**
@ -410,7 +373,7 @@ class Mapping {
* @param {string} [_splitter] what to split on * @param {string} [_splitter] what to split on
* @return {Range[]} * @return {Range[]}
*/ */
splitTextNodeIntoRanges(node, _splitter){ splitTextNodeIntoRanges(node, _splitter) {
var ranges = []; var ranges = [];
var textContent = node.textContent || ""; var textContent = node.textContent || "";
var text = textContent.trim(); var text = textContent.trim();
@ -420,7 +383,7 @@ class Mapping {
var pos = text.indexOf(splitter); var pos = text.indexOf(splitter);
if(pos === -1 || node.nodeType != Node.TEXT_NODE) { if (pos === -1 || node.nodeType != Node.TEXT_NODE) {
range = doc.createRange(); range = doc.createRange();
range.selectNodeContents(node); range.selectNodeContents(node);
return [range]; return [range];
@ -432,22 +395,20 @@ class Mapping {
ranges.push(range); ranges.push(range);
range = false; range = false;
while ( pos != -1 ) { while (pos != -1) {
pos = text.indexOf(splitter, pos + 1); pos = text.indexOf(splitter, pos + 1);
if(pos > 0) { if (pos > 0) {
if (range) {
if(range) {
range.setEnd(node, pos); range.setEnd(node, pos);
ranges.push(range); ranges.push(range);
} }
range = doc.createRange(); range = doc.createRange();
range.setStart(node, pos+1); range.setStart(node, pos + 1);
} }
} }
if(range) { if (range) {
range.setEnd(node, text.length); range.setEnd(node, text.length);
ranges.push(range); ranges.push(range);
} }
@ -455,7 +416,6 @@ class Mapping {
return ranges; return ranges;
} }
/** /**
* Turn a pair of ranges into a pair of CFIs * Turn a pair of ranges into a pair of CFIs
* @private * @private
@ -463,8 +423,7 @@ class Mapping {
* @param {object} rangePair { start: Range, end: Range } * @param {object} rangePair { start: Range, end: Range }
* @return {object} { start: "epubcfi(...)", end: "epubcfi(...)" } * @return {object} { start: "epubcfi(...)", end: "epubcfi(...)" }
*/ */
rangePairToCfiPair(cfiBase, rangePair){ rangePairToCfiPair(cfiBase, rangePair) {
var startRange = rangePair.start; var startRange = rangePair.start;
var endRange = rangePair.end; var endRange = rangePair.end;
@ -476,12 +435,11 @@ class Mapping {
return { return {
start: startCfi, start: startCfi,
end: endCfi end: endCfi,
}; };
} }
rangeListToCfiList(cfiBase, columns){ rangeListToCfiList(cfiBase, columns) {
var map = []; var map = [];
var cifPair; var cifPair;
@ -489,7 +447,6 @@ class Mapping {
cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); cifPair = this.rangePairToCfiPair(cfiBase, columns[i]);
map.push(cifPair); map.push(cifPair);
} }
return map; return map;
@ -502,7 +459,7 @@ class Mapping {
*/ */
axis(axis) { axis(axis) {
if (axis) { if (axis) {
this.horizontal = (axis === "horizontal") ? true : false; this.horizontal = axis === "horizontal" ? true : false;
} }
return this.horizontal; return this.horizontal;
} }

View file

@ -1,4 +1,4 @@
import {qs, qsa, querySelectorByType, filterChildren, getParentByTagName} from "./utils/core"; import { filterChildren, qs, qsa, querySelectorByType } from "./utils/core";
/** /**
* Navigation Parser * Navigation Parser
@ -35,10 +35,10 @@ class Navigation {
if (!isXml) { if (!isXml) {
this.toc = this.load(xml); this.toc = this.load(xml);
} else if(html) { } else if (html) {
this.toc = this.parseNav(xml); this.toc = this.parseNav(xml);
this.landmarks = this.parseLandmarks(xml); this.landmarks = this.parseLandmarks(xml);
} else if(ncx){ } else if (ncx) {
this.toc = this.parseNcx(xml); this.toc = this.parseNcx(xml);
} }
@ -72,7 +72,6 @@ class Navigation {
this.unpack(item.subitems); this.unpack(item.subitems);
} }
} }
} }
/** /**
@ -83,13 +82,13 @@ class Navigation {
get(target) { get(target) {
var index; var index;
if(!target) { if (!target) {
return this.toc; return this.toc;
} }
if(target.indexOf("#") === 0) { if (target.indexOf("#") === 0) {
index = this.tocById[target.substring(1)]; index = this.tocById[target.substring(1)];
} else if(target in this.tocByHref){ } else if (target in this.tocByHref) {
index = this.tocByHref[target]; index = this.tocByHref[target];
} }
@ -132,7 +131,7 @@ class Navigation {
landmark(type) { landmark(type) {
var index; var index;
if(!type) { if (!type) {
return this.landmarks; return this.landmarks;
} }
@ -147,7 +146,7 @@ class Navigation {
* @param {document} navHtml * @param {document} navHtml
* @return {array} navigation list * @return {array} navigation list
*/ */
parseNav(navHtml){ parseNav(navHtml) {
var navElement = querySelectorByType(navHtml, "nav", "toc"); var navElement = querySelectorByType(navHtml, "nav", "toc");
var list = []; var list = [];
@ -191,8 +190,8 @@ class Navigation {
*/ */
navItem(item, parent) { navItem(item, parent) {
let id = item.getAttribute("id") || undefined; let id = item.getAttribute("id") || undefined;
let content = filterChildren(item, "a", true) let content =
|| filterChildren(item, "span", true); filterChildren(item, "a", true) || filterChildren(item, "span", true);
if (!content) { if (!content) {
return; return;
@ -212,11 +211,11 @@ class Navigation {
} }
return { return {
"id": id, id: id,
"href": src, href: src,
"label": text, label: text,
"subitems" : subitems, subitems: subitems,
"parent" : parent parent: parent,
}; };
} }
@ -226,7 +225,7 @@ class Navigation {
* @param {document} navHtml * @param {document} navHtml
* @return {array} landmarks list * @return {array} landmarks list
*/ */
parseLandmarks(navHtml){ parseLandmarks(navHtml) {
var navElement = querySelectorByType(navHtml, "nav", "landmarks"); var navElement = querySelectorByType(navHtml, "nav", "landmarks");
var navItems = navElement ? qsa(navElement, "li") : []; var navItems = navElement ? qsa(navElement, "li") : [];
var length = navItems.length; var length = navItems.length;
@ -234,7 +233,7 @@ class Navigation {
var list = []; var list = [];
var item; var item;
if(!navItems || length === 0) return list; if (!navItems || length === 0) return list;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
item = this.landmarkItem(navItems[i]); item = this.landmarkItem(navItems[i]);
@ -253,21 +252,23 @@ class Navigation {
* @param {element} item * @param {element} item
* @return {object} landmarkItem * @return {object} landmarkItem
*/ */
landmarkItem(item){ landmarkItem(item) {
let content = filterChildren(item, "a", true); let content = filterChildren(item, "a", true);
if (!content) { if (!content) {
return; return;
} }
let type = content.getAttributeNS("http://www.idpf.org/2007/ops", "type") || undefined; let type =
content.getAttributeNS("http://www.idpf.org/2007/ops", "type") ||
undefined;
let href = content.getAttribute("href") || ""; let href = content.getAttribute("href") || "";
let text = content.textContent || ""; let text = content.textContent || "";
return { return {
"href": href, href: href,
"label": text, label: text,
"type" : type type: type,
}; };
} }
@ -277,7 +278,7 @@ class Navigation {
* @param {document} navHtml * @param {document} navHtml
* @return {array} navigation list * @return {array} navigation list
*/ */
parseNcx(tocXml){ parseNcx(tocXml) {
var navPoints = qsa(tocXml, "navPoint"); var navPoints = qsa(tocXml, "navPoint");
var length = navPoints.length; var length = navPoints.length;
var i; var i;
@ -285,12 +286,12 @@ class Navigation {
var list = []; var list = [];
var item, parent; var item, parent;
if(!navPoints || length === 0) return list; if (!navPoints || length === 0) return list;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
item = this.ncxItem(navPoints[i]); item = this.ncxItem(navPoints[i]);
toc[item.id] = item; toc[item.id] = item;
if(!item.parent) { if (!item.parent) {
list.push(item); list.push(item);
} else { } else {
parent = toc[item.parent]; parent = toc[item.parent];
@ -307,7 +308,7 @@ class Navigation {
* @param {element} item * @param {element} item
* @return {object} ncxItem * @return {object} ncxItem
*/ */
ncxItem(item){ ncxItem(item) {
var id = item.getAttribute("id") || false, var id = item.getAttribute("id") || false,
content = qs(item, "content"), content = qs(item, "content"),
src = content.getAttribute("src"), src = content.getAttribute("src"),
@ -317,17 +318,20 @@ class Navigation {
parentNode = item.parentNode, parentNode = item.parentNode,
parent; parent;
if(parentNode && (parentNode.nodeName === "navPoint" || parentNode.nodeName.split(':').slice(-1)[0] === "navPoint")) { if (
parentNode &&
(parentNode.nodeName === "navPoint" ||
parentNode.nodeName.split(":").slice(-1)[0] === "navPoint")
) {
parent = parentNode.getAttribute("id"); parent = parentNode.getAttribute("id");
} }
return { return {
"id": id, id: id,
"href": src, href: src,
"label": text, label: text,
"subitems" : subitems, subitems: subitems,
"parent" : parent parent: parent,
}; };
} }
@ -337,7 +341,7 @@ class Navigation {
* @return {Array} navItems * @return {Array} navItems
*/ */
load(json) { load(json) {
return json.map(item => { return json.map((item) => {
item.label = item.title; item.label = item.title;
item.subitems = item.children ? this.load(item.children) : []; item.subitems = item.children ? this.load(item.children) : [];
return item; return item;

View file

@ -1,4 +1,4 @@
import {qs, qsa, qsp, indexOfElementNode} from "./utils/core"; import { indexOfElementNode, qs, qsa, qsp } from "./utils/core";
/** /**
* Open Packaging Format Parser * Open Packaging Format Parser
@ -8,9 +8,9 @@ import {qs, qsa, qsp, indexOfElementNode} from "./utils/core";
class Packaging { class Packaging {
constructor(packageDocument) { constructor(packageDocument) {
this.manifest = {}; this.manifest = {};
this.navPath = ''; this.navPath = "";
this.ncxPath = ''; this.ncxPath = "";
this.coverPath = ''; this.coverPath = "";
this.spineNodeIndex = 0; this.spineNodeIndex = 0;
this.spine = []; this.spine = [];
this.metadata = {}; this.metadata = {};
@ -25,25 +25,25 @@ class Packaging {
* @param {document} packageDocument OPF XML * @param {document} packageDocument OPF XML
* @return {object} parsed package parts * @return {object} parsed package parts
*/ */
parse(packageDocument){ parse(packageDocument) {
var metadataNode, manifestNode, spineNode; var metadataNode, manifestNode, spineNode;
if(!packageDocument) { if (!packageDocument) {
throw new Error("Package File Not Found"); throw new Error("Package File Not Found");
} }
metadataNode = qs(packageDocument, "metadata"); metadataNode = qs(packageDocument, "metadata");
if(!metadataNode) { if (!metadataNode) {
throw new Error("No Metadata Found"); throw new Error("No Metadata Found");
} }
manifestNode = qs(packageDocument, "manifest"); manifestNode = qs(packageDocument, "manifest");
if(!manifestNode) { if (!manifestNode) {
throw new Error("No Manifest Found"); throw new Error("No Manifest Found");
} }
spineNode = qs(packageDocument, "spine"); spineNode = qs(packageDocument, "spine");
if(!spineNode) { if (!spineNode) {
throw new Error("No Spine Found"); throw new Error("No Spine Found");
} }
@ -59,16 +59,18 @@ class Packaging {
this.uniqueIdentifier = this.findUniqueIdentifier(packageDocument); this.uniqueIdentifier = this.findUniqueIdentifier(packageDocument);
this.metadata = this.parseMetadata(metadataNode); this.metadata = this.parseMetadata(metadataNode);
this.metadata.direction = spineNode.getAttribute("page-progression-direction"); this.metadata.direction = spineNode.getAttribute(
"page-progression-direction"
);
return { return {
"metadata" : this.metadata, metadata: this.metadata,
"spine" : this.spine, spine: this.spine,
"manifest" : this.manifest, manifest: this.manifest,
"navPath" : this.navPath, navPath: this.navPath,
"ncxPath" : this.ncxPath, ncxPath: this.ncxPath,
"coverPath": this.coverPath, coverPath: this.coverPath,
"spineNodeIndex" : this.spineNodeIndex spineNodeIndex: this.spineNodeIndex,
}; };
} }
@ -78,7 +80,7 @@ class Packaging {
* @param {node} xml * @param {node} xml
* @return {object} metadata * @return {object} metadata
*/ */
parseMetadata(xml){ parseMetadata(xml) {
var metadata = {}; var metadata = {};
metadata.title = this.getElementText(xml, "title"); metadata.title = this.getElementText(xml, "title");
@ -99,7 +101,10 @@ class Packaging {
metadata.orientation = this.getPropertyText(xml, "rendition:orientation"); metadata.orientation = this.getPropertyText(xml, "rendition:orientation");
metadata.flow = this.getPropertyText(xml, "rendition:flow"); metadata.flow = this.getPropertyText(xml, "rendition:flow");
metadata.viewport = this.getPropertyText(xml, "rendition:viewport"); metadata.viewport = this.getPropertyText(xml, "rendition:viewport");
metadata.media_active_class = this.getPropertyText(xml, "media:active-class"); metadata.media_active_class = this.getPropertyText(
xml,
"media:active-class"
);
metadata.spread = this.getPropertyText(xml, "rendition:spread"); metadata.spread = this.getPropertyText(xml, "rendition:spread");
// metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
@ -112,7 +117,7 @@ class Packaging {
* @param {node} manifestXml * @param {node} manifestXml
* @return {object} manifest * @return {object} manifest
*/ */
parseManifest(manifestXml){ parseManifest(manifestXml) {
var manifest = {}; var manifest = {};
//-- Turn items into an array //-- Turn items into an array
@ -121,7 +126,7 @@ class Packaging {
var items = Array.prototype.slice.call(selected); var items = Array.prototype.slice.call(selected);
//-- Create an object with the id as key //-- Create an object with the id as key
items.forEach(function(item){ items.forEach(function (item) {
var id = item.getAttribute("id"), var id = item.getAttribute("id"),
href = item.getAttribute("href") || "", href = item.getAttribute("href") || "",
type = item.getAttribute("media-type") || "", type = item.getAttribute("media-type") || "",
@ -129,17 +134,15 @@ class Packaging {
properties = item.getAttribute("properties") || ""; properties = item.getAttribute("properties") || "";
manifest[id] = { manifest[id] = {
"href" : href, href: href,
// "url" : href, // "url" : href,
"type" : type, type: type,
"overlay" : overlay, overlay: overlay,
"properties" : properties.length ? properties.split(" ") : [] properties: properties.length ? properties.split(" ") : [],
}; };
}); });
return manifest; return manifest;
} }
/** /**
@ -149,7 +152,7 @@ class Packaging {
* @param {Packaging.manifest} manifest * @param {Packaging.manifest} manifest
* @return {object} spine * @return {object} spine
*/ */
parseSpine(spineXml, manifest){ parseSpine(spineXml, manifest) {
var spine = []; var spine = [];
var selected = qsa(spineXml, "itemref"); var selected = qsa(spineXml, "itemref");
@ -158,7 +161,7 @@ class Packaging {
// var epubcfi = new EpubCFI(); // var epubcfi = new EpubCFI();
//-- Add to array to maintain ordering and cross reference with manifest //-- Add to array to maintain ordering and cross reference with manifest
items.forEach(function(item, index){ items.forEach(function (item, index) {
var idref = item.getAttribute("idref"); var idref = item.getAttribute("idref");
// var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id); // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);
var props = item.getAttribute("properties") || ""; var props = item.getAttribute("properties") || "";
@ -167,13 +170,13 @@ class Packaging {
// var manifestPropArray = manifestProps.length ? manifestProps.split(" ") : []; // var manifestPropArray = manifestProps.length ? manifestProps.split(" ") : [];
var itemref = { var itemref = {
"id" : item.getAttribute("id"), id: item.getAttribute("id"),
"idref" : idref, idref: idref,
"linear" : item.getAttribute("linear") || "yes", linear: item.getAttribute("linear") || "yes",
"properties" : propArray, properties: propArray,
// "href" : manifest[Id].href, // "href" : manifest[Id].href,
// "url" : manifest[Id].url, // "url" : manifest[Id].url,
"index" : index index: index,
// "cfiBase" : cfiBase // "cfiBase" : cfiBase
}; };
spine.push(itemref); spine.push(itemref);
@ -188,18 +191,24 @@ class Packaging {
* @param {node} packageXml * @param {node} packageXml
* @return {string} Unique Identifier text * @return {string} Unique Identifier text
*/ */
findUniqueIdentifier(packageXml){ findUniqueIdentifier(packageXml) {
var uniqueIdentifierId = packageXml.documentElement.getAttribute("unique-identifier"); var uniqueIdentifierId =
if (! uniqueIdentifierId) { packageXml.documentElement.getAttribute("unique-identifier");
if (!uniqueIdentifierId) {
return ""; return "";
} }
var identifier = packageXml.getElementById(uniqueIdentifierId); var identifier = packageXml.getElementById(uniqueIdentifierId);
if (! identifier) { if (!identifier) {
return ""; return "";
} }
if (identifier.localName === "identifier" && identifier.namespaceURI === "http://purl.org/dc/elements/1.1/") { if (
return identifier.childNodes.length > 0 ? identifier.childNodes[0].nodeValue.trim() : ""; identifier.localName === "identifier" &&
identifier.namespaceURI === "http://purl.org/dc/elements/1.1/"
) {
return identifier.childNodes.length > 0
? identifier.childNodes[0].nodeValue.trim()
: "";
} }
return ""; return "";
@ -211,11 +220,11 @@ class Packaging {
* @param {element} manifestNode * @param {element} manifestNode
* @return {string} * @return {string}
*/ */
findNavPath(manifestNode){ findNavPath(manifestNode) {
// Find item with property "nav" // Find item with property "nav"
// Should catch nav regardless of order // Should catch nav regardless of order
// var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']"); // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']");
var node = qsp(manifestNode, "item", {"properties":"nav"}); var node = qsp(manifestNode, "item", { properties: "nav" });
return node ? node.getAttribute("href") : false; return node ? node.getAttribute("href") : false;
} }
@ -227,9 +236,11 @@ class Packaging {
* @param {element} spineNode * @param {element} spineNode
* @return {string} * @return {string}
*/ */
findNcxPath(manifestNode, spineNode){ findNcxPath(manifestNode, spineNode) {
// var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
var node = qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"}); var node = qsp(manifestNode, "item", {
"media-type": "application/x-dtbncx+xml",
});
var tocId; var tocId;
// If we can't find the toc by media-type then try to look for id of the item in the spine attributes as // If we can't find the toc by media-type then try to look for id of the item in the spine attributes as
@ -237,7 +248,7 @@ class Packaging {
// "The item that describes the NCX must be referenced by the spine toc attribute." // "The item that describes the NCX must be referenced by the spine toc attribute."
if (!node) { if (!node) {
tocId = spineNode.getAttribute("toc"); tocId = spineNode.getAttribute("toc");
if(tocId) { if (tocId) {
// node = manifestNode.querySelector("item[id='" + tocId + "']"); // node = manifestNode.querySelector("item[id='" + tocId + "']");
node = manifestNode.querySelector(`#${tocId}`); node = manifestNode.querySelector(`#${tocId}`);
} }
@ -254,25 +265,19 @@ class Packaging {
* @param {node} packageXml * @param {node} packageXml
* @return {string} href * @return {string} href
*/ */
findCoverPath(packageXml){ findCoverPath(packageXml) {
var pkg = qs(packageXml, "package");
var epubVersion = pkg.getAttribute("version");
// Try parsing cover with epub 3. // Try parsing cover with epub 3.
// var node = packageXml.querySelector("item[properties='cover-image']"); var node = qsp(packageXml, "item", { properties: "cover-image" });
var node = qsp(packageXml, "item", {"properties":"cover-image"});
if (node) return node.getAttribute("href"); if (node) return node.getAttribute("href");
// Fallback to epub 2. // Fallback to epub 2.
var metaCover = qsp(packageXml, "meta", {"name":"cover"}); var metaCover = qsp(packageXml, "meta", { name: "cover" });
if (metaCover) { if (metaCover) {
var coverId = metaCover.getAttribute("content"); var coverId = metaCover.getAttribute("content");
// var cover = packageXml.querySelector("item[id='" + coverId + "']");
var cover = packageXml.getElementById(coverId); var cover = packageXml.getElementById(coverId);
return cover ? cover.getAttribute("href") : ""; return cover ? cover.getAttribute("href") : "";
} } else {
else {
return false; return false;
} }
} }
@ -284,20 +289,22 @@ class Packaging {
* @param {string} tag * @param {string} tag
* @return {string} text * @return {string} text
*/ */
getElementText(xml, tag){ getElementText(xml, tag) {
var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag); var found = xml.getElementsByTagNameNS(
"http://purl.org/dc/elements/1.1/",
tag
);
var el; var el;
if(!found || found.length === 0) return ""; if (!found || found.length === 0) return "";
el = found[0]; el = found[0];
if(el.childNodes.length){ if (el.childNodes.length) {
return el.childNodes[0].nodeValue; return el.childNodes[0].nodeValue;
} }
return ""; return "";
} }
/** /**
@ -307,10 +314,10 @@ class Packaging {
* @param {string} property * @param {string} property
* @return {string} text * @return {string} text
*/ */
getPropertyText(xml, property){ getPropertyText(xml, property) {
var el = qsp(xml, "meta", {"property":property}); var el = qsp(xml, "meta", { property: property });
if(el && el.childNodes.length){ if (el && el.childNodes.length) {
return el.childNodes[0].nodeValue; return el.childNodes[0].nodeValue;
} }
@ -326,7 +333,7 @@ class Packaging {
this.metadata = json.metadata; this.metadata = json.metadata;
let spine = json.readingOrder || json.spine; let spine = json.readingOrder || json.spine;
this.spine = spine.map((item, index) =>{ this.spine = spine.map((item, index) => {
item.index = index; item.index = index;
item.linear = item.linear || "yes"; item.linear = item.linear || "yes";
return item; return item;
@ -342,20 +349,20 @@ class Packaging {
this.spineNodeIndex = 0; this.spineNodeIndex = 0;
this.toc = json.toc.map((item, index) =>{ this.toc = json.toc.map((item, index) => {
item.label = item.title; item.label = item.title;
return item; return item;
}); });
return { return {
"metadata" : this.metadata, metadata: this.metadata,
"spine" : this.spine, spine: this.spine,
"manifest" : this.manifest, manifest: this.manifest,
"navPath" : this.navPath, navPath: this.navPath,
"ncxPath" : this.ncxPath, ncxPath: this.ncxPath,
"coverPath": this.coverPath, coverPath: this.coverPath,
"spineNodeIndex" : this.spineNodeIndex, spineNodeIndex: this.spineNodeIndex,
"toc" : this.toc toc: this.toc,
}; };
} }

View file

@ -1,10 +1,10 @@
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import { import {
indexOfSorted,
locationOf,
qs, qs,
qsa, qsa,
querySelectorByType, querySelectorByType,
indexOfSorted,
locationOf
} from "./utils/core"; } from "./utils/core";
/** /**
@ -28,7 +28,7 @@ class PageList {
this.pageList = this.parse(xml); this.pageList = this.parse(xml);
} }
if(this.pageList && this.pageList.length) { if (this.pageList && this.pageList.length) {
this.process(this.pageList); this.process(this.pageList);
} }
} }
@ -41,12 +41,11 @@ class PageList {
var html = qs(xml, "html"); var html = qs(xml, "html");
var ncx = qs(xml, "ncx"); var ncx = qs(xml, "ncx");
if(html) { if (html) {
return this.parseNav(xml); return this.parseNav(xml);
} else if(ncx){ } else if (ncx) {
return this.parseNcx(xml); return this.parseNcx(xml);
} }
} }
/** /**
@ -55,7 +54,7 @@ class PageList {
* @param {node} navHtml * @param {node} navHtml
* @return {PageList.item[]} list * @return {PageList.item[]} list
*/ */
parseNav(navHtml){ parseNav(navHtml) {
var navElement = querySelectorByType(navHtml, "nav", "page-list"); var navElement = querySelectorByType(navHtml, "nav", "page-list");
var navItems = navElement ? qsa(navElement, "li") : []; var navItems = navElement ? qsa(navElement, "li") : [];
var length = navItems.length; var length = navItems.length;
@ -63,7 +62,7 @@ class PageList {
var list = []; var list = [];
var item; var item;
if(!navItems || length === 0) return list; if (!navItems || length === 0) return list;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
item = this.item(navItems[i]); item = this.item(navItems[i]);
@ -109,8 +108,8 @@ class PageList {
var page = parseInt(pageText, 10); var page = parseInt(pageText, 10);
return { return {
"href": href, href: href,
"page": page, page: page,
}; };
} }
@ -120,7 +119,7 @@ class PageList {
* @param {node} item * @param {node} item
* @return {object} pageListItem * @return {object} pageListItem
*/ */
item(item){ item(item) {
var content = qs(item, "a"), var content = qs(item, "a"),
href = content.getAttribute("href") || "", href = content.getAttribute("href") || "",
text = content.textContent || "", text = content.textContent || "",
@ -130,20 +129,20 @@ class PageList {
packageUrl, packageUrl,
cfi; cfi;
if(isCfi != -1) { if (isCfi != -1) {
split = href.split("#"); split = href.split("#");
packageUrl = split[0]; packageUrl = split[0];
cfi = split.length > 1 ? split[1] : false; cfi = split.length > 1 ? split[1] : false;
return { return {
"cfi" : cfi, cfi: cfi,
"href" : href, href: href,
"packageUrl" : packageUrl, packageUrl: packageUrl,
"page" : page page: page,
}; };
} else { } else {
return { return {
"href" : href, href: href,
"page" : page page: page,
}; };
} }
} }
@ -153,15 +152,15 @@ class PageList {
* @private * @private
* @param {array} pageList * @param {array} pageList
*/ */
process(pageList){ process(pageList) {
pageList.forEach(function(item){ pageList.forEach(function (item) {
this.pages.push(item.page); this.pages.push(item.page);
if (item.cfi) { if (item.cfi) {
this.locations.push(item.cfi); this.locations.push(item.cfi);
} }
}, this); }, this);
this.firstPage = parseInt(this.pages[0]); this.firstPage = parseInt(this.pages[0]);
this.lastPage = parseInt(this.pages[this.pages.length-1]); this.lastPage = parseInt(this.pages[this.pages.length - 1]);
this.totalPages = this.lastPage - this.firstPage; this.totalPages = this.lastPage - this.firstPage;
} }
@ -170,11 +169,11 @@ class PageList {
* @param {string} cfi EpubCFI String * @param {string} cfi EpubCFI String
* @return {number} page * @return {number} page
*/ */
pageFromCfi(cfi){ pageFromCfi(cfi) {
var pg = -1; var pg = -1;
// Check if the pageList has not been set yet // Check if the pageList has not been set yet
if(this.locations.length === 0) { if (this.locations.length === 0) {
return -1; return -1;
} }
@ -183,7 +182,7 @@ class PageList {
// check if the cfi is in the location list // check if the cfi is in the location list
// var index = this.locations.indexOf(cfi); // var index = this.locations.indexOf(cfi);
var index = indexOfSorted(cfi, this.locations, this.epubcfi.compare); var index = indexOfSorted(cfi, this.locations, this.epubcfi.compare);
if(index != -1) { if (index != -1) {
pg = this.pages[index]; pg = this.pages[index];
} else { } else {
// Otherwise add it to the list of locations // Otherwise add it to the list of locations
@ -191,14 +190,13 @@ class PageList {
//index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare); //index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
index = locationOf(cfi, this.locations, this.epubcfi.compare); index = locationOf(cfi, this.locations, this.epubcfi.compare);
// Get the page at the location just before the new one, or return the first // 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]; pg = index - 1 >= 0 ? this.pages[index - 1] : this.pages[0];
if(pg !== undefined) { if (pg !== undefined) {
// Add the new page in so that the locations and page array match up // Add the new page in so that the locations and page array match up
//this.pages.splice(index, 0, pg); //this.pages.splice(index, 0, pg);
} else { } else {
pg = -1; pg = -1;
} }
} }
return pg; return pg;
} }
@ -208,17 +206,17 @@ class PageList {
* @param {string | number} pg * @param {string | number} pg
* @return {string} cfi * @return {string} cfi
*/ */
cfiFromPage(pg){ cfiFromPage(pg) {
var cfi = -1; var cfi = -1;
// check that pg is an int // check that pg is an int
if(typeof pg != "number"){ if (typeof pg != "number") {
pg = parseInt(pg); pg = parseInt(pg);
} }
// check if the cfi is in the page list // check if the cfi is in the page list
// Pages could be unsorted. // Pages could be unsorted.
var index = this.pages.indexOf(pg); var index = this.pages.indexOf(pg);
if(index != -1) { if (index != -1) {
cfi = this.locations[index]; cfi = this.locations[index];
} }
// TODO: handle pages not in the list // TODO: handle pages not in the list
@ -230,7 +228,7 @@ class PageList {
* @param {number} percent * @param {number} percent
* @return {number} page * @return {number} page
*/ */
pageFromPercentage(percent){ pageFromPercentage(percent) {
var pg = Math.round(this.totalPages * percent); var pg = Math.round(this.totalPages * percent);
return pg; return pg;
} }
@ -240,7 +238,7 @@ class PageList {
* @param {number} pg the page * @param {number} pg the page
* @return {number} percentage * @return {number} percentage
*/ */
percentageFromPage(pg){ percentageFromPage(pg) {
var percentage = (pg - this.firstPage) / this.totalPages; var percentage = (pg - this.firstPage) / this.totalPages;
return Math.round(percentage * 1000) / 1000; return Math.round(percentage * 1000) / 1000;
} }
@ -250,7 +248,7 @@ class PageList {
* @param {string} cfi EpubCFI String * @param {string} cfi EpubCFI String
* @return {number} percentage * @return {number} percentage
*/ */
percentageFromCfi(cfi){ percentageFromCfi(cfi) {
var pg = this.pageFromCfi(cfi); var pg = this.pageFromCfi(cfi);
var percentage = this.percentageFromPage(pg); var percentage = this.percentageFromPage(pg);
return percentage; return percentage;

View file

@ -1,21 +1,15 @@
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import { extend, defer, isFloat } from "./utils/core";
import Hook from "./utils/hook";
import EpubCFI from "./epubcfi";
import Queue from "./utils/queue";
import Layout from "./layout";
// import Mapping from "./mapping";
import Themes from "./themes";
import Contents from "./contents";
import Annotations from "./annotations"; import Annotations from "./annotations";
import { EVENTS, DOM_EVENTS } from "./utils/constants"; import EpubCFI from "./epubcfi";
import Layout from "./layout";
// Default Views
import IframeView from "./managers/views/iframe";
// Default View Managers
import DefaultViewManager from "./managers/default/index";
import ContinuousViewManager from "./managers/continuous/index"; import ContinuousViewManager from "./managers/continuous/index";
import DefaultViewManager from "./managers/default/index";
import IframeView from "./managers/views/iframe";
import Themes from "./themes";
import { DOM_EVENTS, EVENTS } from "./utils/constants";
import { defer, extend, isFloat } from "./utils/core";
import Hook from "./utils/hook";
import Queue from "./utils/queue";
/** /**
* Displays an Epub as a series of Views for each Section. * Displays an Epub as a series of Views for each Section.
@ -42,7 +36,6 @@ import ContinuousViewManager from "./managers/continuous/index";
*/ */
class Rendition { class Rendition {
constructor(book, options) { constructor(book, options) {
this.settings = extend(this.settings || {}, { this.settings = extend(this.settings || {}, {
width: null, width: null,
height: null, height: null,
@ -59,12 +52,12 @@ class Rendition {
snap: false, snap: false,
defaultDirection: "ltr", defaultDirection: "ltr",
allowScriptedContent: false, allowScriptedContent: false,
allowPopups: false allowPopups: false,
}); });
extend(this.settings, options); extend(this.settings, options);
if (typeof(this.settings.manager) === "object") { if (typeof this.settings.manager === "object") {
this.manager = this.settings.manager; this.manager = this.settings.manager;
} }
@ -209,20 +202,24 @@ class Rendition {
* Start the rendering * Start the rendering
* @return {Promise} rendering has started * @return {Promise} rendering has started
*/ */
start(){ start() {
if (!this.settings.layout && (this.book.package.metadata.layout === "pre-paginated" || this.book.displayOptions.fixedLayout === "true")) { if (
!this.settings.layout &&
(this.book.package.metadata.layout === "pre-paginated" ||
this.book.displayOptions.fixedLayout === "true")
) {
this.settings.layout = "pre-paginated"; this.settings.layout = "pre-paginated";
} }
switch(this.book.package.metadata.spread) { switch (this.book.package.metadata.spread) {
case 'none': case "none":
this.settings.spread = 'none'; this.settings.spread = "none";
break; break;
case 'both': case "both":
this.settings.spread = true; this.settings.spread = true;
break; break;
} }
if(!this.manager) { if (!this.manager) {
this.ViewManager = this.requireManager(this.settings.manager); this.ViewManager = this.requireManager(this.settings.manager);
this.View = this.requireView(this.settings.view); this.View = this.requireView(this.settings.view);
@ -230,14 +227,18 @@ class Rendition {
view: this.View, view: this.View,
queue: this.q, queue: this.q,
request: this.book.load.bind(this.book), request: this.book.load.bind(this.book),
settings: this.settings settings: this.settings,
}); });
} }
this.direction(this.book.package.metadata.direction || this.settings.defaultDirection); this.direction(
this.book.package.metadata.direction || this.settings.defaultDirection
);
// Parse metadata to get layout props // Parse metadata to get layout props
this.settings.globalLayoutProperties = this.determineLayoutProperties(this.book.package.metadata); this.settings.globalLayoutProperties = this.determineLayoutProperties(
this.book.package.metadata
);
this.flow(this.settings.globalLayoutProperties.flow); this.flow(this.settings.globalLayoutProperties.flow);
@ -251,7 +252,10 @@ class Rendition {
this.manager.on(EVENTS.MANAGERS.RESIZED, this.onResized.bind(this)); this.manager.on(EVENTS.MANAGERS.RESIZED, this.onResized.bind(this));
// Listen for rotation // Listen for rotation
this.manager.on(EVENTS.MANAGERS.ORIENTATION_CHANGE, this.onOrientationChange.bind(this)); this.manager.on(
EVENTS.MANAGERS.ORIENTATION_CHANGE,
this.onOrientationChange.bind(this)
);
// Listen for scroll changes // Listen for scroll changes
this.manager.on(EVENTS.MANAGERS.SCROLLED, this.reportLocation.bind(this)); this.manager.on(EVENTS.MANAGERS.SCROLLED, this.reportLocation.bind(this));
@ -273,14 +277,13 @@ class Rendition {
* @param {element} element to attach to * @param {element} element to attach to
* @return {Promise} * @return {Promise}
*/ */
attachTo(element){ attachTo(element) {
return this.q.enqueue(
return this.q.enqueue(function () { function () {
// Start rendering // Start rendering
this.manager.render(element, { this.manager.render(element, {
"width" : this.settings.width, width: this.settings.width,
"height" : this.settings.height height: this.settings.height,
}); });
/** /**
@ -289,9 +292,8 @@ class Rendition {
* @memberof Rendition * @memberof Rendition
*/ */
this.emit(EVENTS.RENDITION.ATTACHED); this.emit(EVENTS.RENDITION.ATTACHED);
}.bind(this)
}.bind(this)); );
} }
/** /**
@ -302,7 +304,7 @@ class Rendition {
* @param {string} target Url or EpubCFI * @param {string} target Url or EpubCFI
* @return {Promise} * @return {Promise}
*/ */
display(target){ display(target) {
if (this.displaying) { if (this.displaying) {
this.displaying.resolve(); this.displaying.resolve();
} }
@ -315,15 +317,13 @@ class Rendition {
* @param {string} target Url or EpubCFI * @param {string} target Url or EpubCFI
* @return {Promise} * @return {Promise}
*/ */
_display(target){ _display(target) {
if (!this.book) { if (!this.book) {
return; return;
} }
var isCfiString = this.epubcfi.isCfiString(target);
var displaying = new defer(); var displaying = new defer();
var displayed = displaying.promise; var displayed = displaying.promise;
var section; var section;
var moveTo;
this.displaying = displaying; this.displaying = displaying;
@ -334,13 +334,13 @@ class Rendition {
section = this.book.spine.get(target); section = this.book.spine.get(target);
if(!section){ if (!section) {
displaying.reject(new Error("No Section Found")); displaying.reject(new Error("No Section Found"));
return displayed; return displayed;
} }
this.manager.display(section, target) this.manager.display(section, target).then(
.then(() => { () => {
displaying.resolve(section); displaying.resolve(section);
this.displaying = undefined; this.displaying = undefined;
@ -352,7 +352,8 @@ class Rendition {
*/ */
this.emit(EVENTS.RENDITION.DISPLAYED, section); this.emit(EVENTS.RENDITION.DISPLAYED, section);
this.reportLocation(); this.reportLocation();
}, (err) => { },
(err) => {
/** /**
* Emit that has been an error displaying * Emit that has been an error displaying
* @event displayError * @event displayError
@ -360,67 +361,23 @@ class Rendition {
* @memberof Rendition * @memberof Rendition
*/ */
this.emit(EVENTS.RENDITION.DISPLAY_ERROR, err); this.emit(EVENTS.RENDITION.DISPLAY_ERROR, err);
}); }
);
return displayed; return displayed;
} }
/*
render(view, show) {
// view.onLayout = this.layout.format.bind(this.layout);
view.create();
// Fit to size of the container, apply padding
this.manager.resizeView(view);
// Render Chain
return view.section.render(this.book.request)
.then(function(contents){
return view.load(contents);
}.bind(this))
.then(function(doc){
return this.hooks.content.trigger(view, this);
}.bind(this))
.then(function(){
this.layout.format(view.contents);
return this.hooks.layout.trigger(view, this);
}.bind(this))
.then(function(){
return view.display();
}.bind(this))
.then(function(){
return this.hooks.render.trigger(view, this);
}.bind(this))
.then(function(){
if(show !== false) {
this.q.enqueue(function(view){
view.show();
}, view);
}
// this.map = new Map(view, this.layout);
this.hooks.show.trigger(view, this);
this.trigger("rendered", view.section);
}.bind(this))
.catch(function(e){
this.trigger("loaderror", e);
}.bind(this));
}
*/
/** /**
* Report what section has been displayed * Report what section has been displayed
* @private * @private
* @param {*} view * @param {*} view
*/ */
afterDisplayed(view){ afterDisplayed(view) {
view.on(EVENTS.VIEWS.MARK_CLICKED, (cfiRange, data) =>
this.triggerMarkEvent(cfiRange, data, view.contents)
);
view.on(EVENTS.VIEWS.MARK_CLICKED, (cfiRange, data) => this.triggerMarkEvent(cfiRange, data, view.contents)); this.hooks.render.trigger(view, this).then(() => {
this.hooks.render.trigger(view, this)
.then(() => {
if (view.contents) { if (view.contents) {
this.hooks.content.trigger(view.contents, this).then(() => { this.hooks.content.trigger(view.contents, this).then(() => {
/** /**
@ -436,7 +393,6 @@ class Rendition {
this.emit(EVENTS.RENDITION.RENDERED, view.section, view); this.emit(EVENTS.RENDITION.RENDERED, view.section, view);
} }
}); });
} }
/** /**
@ -444,7 +400,7 @@ class Rendition {
* @private * @private
* @param {*} view * @param {*} view
*/ */
afterRemoved(view){ afterRemoved(view) {
this.hooks.unloaded.trigger(view, this).then(() => { this.hooks.unloaded.trigger(view, this).then(() => {
/** /**
* Emit that a section has been removed * Emit that a section has been removed
@ -461,8 +417,7 @@ class Rendition {
* Report resize events and display the last seen location * Report resize events and display the last seen location
* @private * @private
*/ */
onResized(size, epubcfi){ onResized(size, epubcfi) {
/** /**
* Emit that the rendition has been resized * Emit that the rendition has been resized
* @event resized * @event resized
@ -471,22 +426,25 @@ class Rendition {
* @param {string} epubcfi (optional) * @param {string} epubcfi (optional)
* @memberof Rendition * @memberof Rendition
*/ */
this.emit(EVENTS.RENDITION.RESIZED, { this.emit(
EVENTS.RENDITION.RESIZED,
{
width: size.width, width: size.width,
height: size.height height: size.height,
}, epubcfi); },
epubcfi
);
if (this.location && this.location.start) { if (this.location && this.location.start) {
this.display(epubcfi || this.location.start.cfi); this.display(epubcfi || this.location.start.cfi);
} }
} }
/** /**
* Report orientation events and display the last seen location * Report orientation events and display the last seen location
* @private * @private
*/ */
onOrientationChange(orientation){ onOrientationChange(orientation) {
/** /**
* Emit that the rendition has been rotated * Emit that the rendition has been rotated
* @event orientationchange * @event orientationchange
@ -501,7 +459,7 @@ class Rendition {
* Usually you would be better off calling display() * Usually you would be better off calling display()
* @param {object} offset * @param {object} offset
*/ */
moveTo(offset){ moveTo(offset) {
this.manager.moveTo(offset); this.manager.moveTo(offset);
} }
@ -511,7 +469,7 @@ class Rendition {
* @param {number} [height] * @param {number} [height]
* @param {string} [epubcfi] (optional) * @param {string} [epubcfi] (optional)
*/ */
resize(width, height, epubcfi){ resize(width, height, epubcfi) {
if (width) { if (width) {
this.settings.width = width; this.settings.width = width;
} }
@ -524,7 +482,7 @@ class Rendition {
/** /**
* Clear all rendered views * Clear all rendered views
*/ */
clear(){ clear() {
this.manager.clear(); this.manager.clear();
} }
@ -532,8 +490,9 @@ class Rendition {
* Go to the next "page" in the rendition * Go to the next "page" in the rendition
* @return {Promise} * @return {Promise}
*/ */
next(){ next() {
return this.q.enqueue(this.manager.next.bind(this.manager)) return this.q
.enqueue(this.manager.next.bind(this.manager))
.then(this.reportLocation.bind(this)); .then(this.reportLocation.bind(this));
} }
@ -541,8 +500,9 @@ class Rendition {
* Go to the previous "page" in the rendition * Go to the previous "page" in the rendition
* @return {Promise} * @return {Promise}
*/ */
prev(){ prev() {
return this.q.enqueue(this.manager.prev.bind(this.manager)) return this.q
.enqueue(this.manager.prev.bind(this.manager))
.then(this.reportLocation.bind(this)); .then(this.reportLocation.bind(this));
} }
@ -553,29 +513,33 @@ class Rendition {
* @param {object} metadata * @param {object} metadata
* @return {object} properties * @return {object} properties
*/ */
determineLayoutProperties(metadata){ determineLayoutProperties(metadata) {
var properties; var properties;
var layout = this.settings.layout || metadata.layout || "reflowable"; var layout = this.settings.layout || metadata.layout || "reflowable";
var spread = this.settings.spread || metadata.spread || "auto"; var spread = this.settings.spread || metadata.spread || "auto";
var orientation = this.settings.orientation || metadata.orientation || "auto"; var orientation =
this.settings.orientation || metadata.orientation || "auto";
var flow = this.settings.flow || metadata.flow || "auto"; var flow = this.settings.flow || metadata.flow || "auto";
var viewport = metadata.viewport || ""; var viewport = metadata.viewport || "";
var minSpreadWidth = this.settings.minSpreadWidth || metadata.minSpreadWidth || 800; var minSpreadWidth =
this.settings.minSpreadWidth || metadata.minSpreadWidth || 800;
var direction = this.settings.direction || metadata.direction || "ltr"; var direction = this.settings.direction || metadata.direction || "ltr";
if ((this.settings.width === 0 || this.settings.width > 0) && if (
(this.settings.height === 0 || this.settings.height > 0)) { (this.settings.width === 0 || this.settings.width > 0) &&
(this.settings.height === 0 || this.settings.height > 0)
) {
// viewport = "width="+this.settings.width+", height="+this.settings.height+""; // viewport = "width="+this.settings.width+", height="+this.settings.height+"";
} }
properties = { properties = {
layout : layout, layout: layout,
spread : spread, spread: spread,
orientation : orientation, orientation: orientation,
flow : flow, flow: flow,
viewport : viewport, viewport: viewport,
minSpreadWidth : minSpreadWidth, minSpreadWidth: minSpreadWidth,
direction: direction direction: direction,
}; };
return properties; return properties;
@ -586,11 +550,13 @@ class Rendition {
* (scrolled-continuous vs scrolled-doc are handled by different view managers) * (scrolled-continuous vs scrolled-doc are handled by different view managers)
* @param {string} flow * @param {string} flow
*/ */
flow(flow){ flow(flow) {
var _flow = flow; var _flow = flow;
if (flow === "scrolled" || if (
flow === "scrolled" ||
flow === "scrolled-doc" || flow === "scrolled-doc" ||
flow === "scrolled-continuous") { flow === "scrolled-continuous"
) {
_flow = "scrolled"; _flow = "scrolled";
} }
@ -622,7 +588,7 @@ class Rendition {
* Adjust the layout of the rendition to reflowable or pre-paginated * Adjust the layout of the rendition to reflowable or pre-paginated
* @param {object} settings * @param {object} settings
*/ */
layout(settings){ layout(settings) {
if (settings) { if (settings) {
this._layout = new Layout(settings); this._layout = new Layout(settings);
this._layout.spread(settings.spread, this.settings.minSpreadWidth); this._layout.spread(settings.spread, this.settings.minSpreadWidth);
@ -631,7 +597,7 @@ class Rendition {
this._layout.on(EVENTS.LAYOUT.UPDATED, (props, changed) => { this._layout.on(EVENTS.LAYOUT.UPDATED, (props, changed) => {
this.emit(EVENTS.RENDITION.LAYOUT, props, changed); this.emit(EVENTS.RENDITION.LAYOUT, props, changed);
}) });
} }
if (this.manager && this._layout) { if (this.manager && this._layout) {
@ -646,8 +612,7 @@ class Rendition {
* @param {string} spread none | auto (TODO: implement landscape, portrait, both) * @param {string} spread none | auto (TODO: implement landscape, portrait, both)
* @param {int} [min] min width to use spreads at * @param {int} [min] min width to use spreads at
*/ */
spread(spread, min){ spread(spread, min) {
this.settings.spread = spread; this.settings.spread = spread;
if (min) { if (min) {
@ -667,8 +632,7 @@ class Rendition {
* Adjust the direction of the rendition * Adjust the direction of the rendition
* @param {string} dir * @param {string} dir
*/ */
direction(dir){ direction(dir) {
this.settings.direction = dir || "ltr"; this.settings.direction = dir || "ltr";
if (this.manager) { if (this.manager) {
@ -686,12 +650,19 @@ class Rendition {
* @fires relocated * @fires relocated
* @fires locationChanged * @fires locationChanged
*/ */
reportLocation(){ reportLocation() {
return this.q.enqueue(function reportedLocation(){ return this.q.enqueue(
requestAnimationFrame(function reportedLocationAfterRAF() { function reportedLocation() {
requestAnimationFrame(
function reportedLocationAfterRAF() {
var location = this.manager.currentLocation(); var location = this.manager.currentLocation();
if (location && location.then && typeof location.then === "function") { if (
location.then(function(result) { location &&
location.then &&
typeof location.then === "function"
) {
location.then(
function (result) {
let located = this.located(result); let located = this.located(result);
if (!located || !located.start || !located.end) { if (!located || !located.start || !located.end) {
@ -705,11 +676,12 @@ class Rendition {
href: this.location.start.href, href: this.location.start.href,
start: this.location.start.cfi, start: this.location.start.cfi,
end: this.location.end.cfi, end: this.location.end.cfi,
percentage: this.location.start.percentage percentage: this.location.start.percentage,
}); });
this.emit(EVENTS.RENDITION.RELOCATED, this.location); this.emit(EVENTS.RENDITION.RELOCATED, this.location);
}.bind(this)); }.bind(this)
);
} else if (location) { } else if (location) {
let located = this.located(location); let located = this.located(location);
@ -735,7 +707,7 @@ class Rendition {
href: this.location.start.href, href: this.location.start.href,
start: this.location.start.cfi, start: this.location.start.cfi,
end: this.location.end.cfi, end: this.location.end.cfi,
percentage: this.location.start.percentage percentage: this.location.start.percentage,
}); });
/** /**
@ -745,21 +717,25 @@ class Rendition {
*/ */
this.emit(EVENTS.RENDITION.RELOCATED, this.location); this.emit(EVENTS.RENDITION.RELOCATED, this.location);
} }
}.bind(this)); }.bind(this)
}.bind(this)); );
}.bind(this)
);
} }
/** /**
* Get the Current Location object * Get the Current Location object
* @return {displayedLocation | promise} location (may be a promise) * @return {displayedLocation | promise} location (may be a promise)
*/ */
currentLocation(){ currentLocation() {
var location = this.manager.currentLocation(); var location = this.manager.currentLocation();
if (location && location.then && typeof location.then === "function") { if (location && location.then && typeof location.then === "function") {
location.then(function(result) { location.then(
function (result) {
let located = this.located(result); let located = this.located(result);
return located; return located;
}.bind(this)); }.bind(this)
);
} else if (location) { } else if (location) {
let located = this.located(location); let located = this.located(location);
return located; return located;
@ -772,12 +748,12 @@ class Rendition {
* @returns {displayedLocation} * @returns {displayedLocation}
* @private * @private
*/ */
located(location){ located(location) {
if (!location.length) { if (!location.length) {
return {}; return {};
} }
let start = location[0]; let start = location[0];
let end = location[location.length-1]; let end = location[location.length - 1];
let located = { let located = {
start: { start: {
@ -786,30 +762,34 @@ class Rendition {
cfi: start.mapping.start, cfi: start.mapping.start,
displayed: { displayed: {
page: start.pages[0] || 1, page: start.pages[0] || 1,
total: start.totalPages total: start.totalPages,
} },
}, },
end: { end: {
index: end.index, index: end.index,
href: end.href, href: end.href,
cfi: end.mapping.end, cfi: end.mapping.end,
displayed: { displayed: {
page: end.pages[end.pages.length-1] || 1, page: end.pages[end.pages.length - 1] || 1,
total: end.totalPages total: end.totalPages,
} },
} },
}; };
let locationStart = this.book.locations.locationFromCfi(start.mapping.start); let locationStart = this.book.locations.locationFromCfi(
start.mapping.start
);
let locationEnd = this.book.locations.locationFromCfi(end.mapping.end); let locationEnd = this.book.locations.locationFromCfi(end.mapping.end);
if (locationStart != null) { if (locationStart != null) {
located.start.location = locationStart; located.start.location = locationStart;
located.start.percentage = this.book.locations.percentageFromLocation(locationStart); located.start.percentage =
this.book.locations.percentageFromLocation(locationStart);
} }
if (locationEnd != null) { if (locationEnd != null) {
located.end.location = locationEnd; located.end.location = locationEnd;
located.end.percentage = this.book.locations.percentageFromLocation(locationEnd); located.end.percentage =
this.book.locations.percentageFromLocation(locationEnd);
} }
let pageStart = this.book.pageList.pageFromCfi(start.mapping.start); let pageStart = this.book.pageList.pageFromCfi(start.mapping.start);
@ -822,13 +802,17 @@ class Rendition {
located.end.page = pageEnd; located.end.page = pageEnd;
} }
if (end.index === this.book.spine.last().index && if (
located.end.displayed.page >= located.end.displayed.total) { end.index === this.book.spine.last().index &&
located.end.displayed.page >= located.end.displayed.total
) {
located.atEnd = true; located.atEnd = true;
} }
if (start.index === this.book.spine.first().index && if (
located.start.displayed.page === 1) { start.index === this.book.spine.first().index &&
located.start.displayed.page === 1
) {
located.atStart = true; located.atStart = true;
} }
@ -838,7 +822,7 @@ class Rendition {
/** /**
* Remove and Clean Up the Rendition * Remove and Clean Up the Rendition
*/ */
destroy(){ destroy() {
// Clear the queue // Clear the queue
// this.q.clear(); // this.q.clear();
// this.q = undefined; // this.q = undefined;
@ -864,8 +848,6 @@ class Rendition {
// this.starting = undefined; // this.starting = undefined;
// this.started = undefined; // this.started = undefined;
} }
/** /**
@ -873,12 +855,14 @@ class Rendition {
* @private * @private
* @param {Contents} view contents * @param {Contents} view contents
*/ */
passEvents(contents){ passEvents(contents) {
DOM_EVENTS.forEach((e) => { DOM_EVENTS.forEach((e) => {
contents.on(e, (ev) => this.triggerViewEvent(ev, contents)); contents.on(e, (ev) => this.triggerViewEvent(ev, contents));
}); });
contents.on(EVENTS.CONTENTS.SELECTED, (e) => this.triggerSelectedEvent(e, contents)); contents.on(EVENTS.CONTENTS.SELECTED, (e) =>
this.triggerSelectedEvent(e, contents)
);
} }
/** /**
@ -886,7 +870,7 @@ class Rendition {
* @private * @private
* @param {event} e * @param {event} e
*/ */
triggerViewEvent(e, contents){ triggerViewEvent(e, contents) {
this.emit(e.type, e, contents); this.emit(e.type, e, contents);
} }
@ -895,7 +879,7 @@ class Rendition {
* @private * @private
* @param {string} cfirange * @param {string} cfirange
*/ */
triggerSelectedEvent(cfirange, contents){ triggerSelectedEvent(cfirange, contents) {
/** /**
* Emit that a text selection has occurred * Emit that a text selection has occurred
* @event selected * @event selected
@ -911,7 +895,7 @@ class Rendition {
* @private * @private
* @param {EpubCFI} cfirange * @param {EpubCFI} cfirange
*/ */
triggerMarkEvent(cfiRange, data, contents){ triggerMarkEvent(cfiRange, data, contents) {
/** /**
* Emit that a mark was clicked * Emit that a mark was clicked
* @event markClicked * @event markClicked
@ -929,10 +913,10 @@ class Rendition {
* @param {string} ignoreClass * @param {string} ignoreClass
* @return {range} * @return {range}
*/ */
getRange(cfi, ignoreClass){ getRange(cfi, ignoreClass) {
var _cfi = new EpubCFI(cfi); var _cfi = new EpubCFI(cfi);
var found = this.manager.visible().filter(function (view) { var found = this.manager.visible().filter(function (view) {
if(_cfi.spinePos === view.index) return true; if (_cfi.spinePos === view.index) return true;
}); });
// Should only every return 1 item // Should only every return 1 item
@ -947,37 +931,47 @@ class Rendition {
* @private * @private
*/ */
adjustImages(contents) { adjustImages(contents) {
if (this._layout.name === "pre-paginated") { if (this._layout.name === "pre-paginated") {
return new Promise(function(resolve){ return new Promise(function (resolve) {
resolve(); resolve();
}); });
} }
let computed = contents.window.getComputedStyle(contents.content, null); let computed = contents.window.getComputedStyle(contents.content, null);
let height = (contents.content.offsetHeight - (parseFloat(computed.paddingTop) + parseFloat(computed.paddingBottom))) * .95; let height =
let horizontalPadding = parseFloat(computed.paddingLeft) + parseFloat(computed.paddingRight); (contents.content.offsetHeight -
(parseFloat(computed.paddingTop) +
parseFloat(computed.paddingBottom))) *
0.95;
let horizontalPadding =
parseFloat(computed.paddingLeft) + parseFloat(computed.paddingRight);
contents.addStylesheetRules({ contents.addStylesheetRules({
"img" : { img: {
"max-width": (this._layout.columnWidth ? (this._layout.columnWidth - horizontalPadding) + "px" : "100%") + "!important", "max-width":
(this._layout.columnWidth
? this._layout.columnWidth - horizontalPadding + "px"
: "100%") + "!important",
"max-height": height + "px" + "!important", "max-height": height + "px" + "!important",
"object-fit": "contain", "object-fit": "contain",
"page-break-inside": "avoid", "page-break-inside": "avoid",
"break-inside": "avoid", "break-inside": "avoid",
"box-sizing": "border-box" "box-sizing": "border-box",
}, },
"svg" : { svg: {
"max-width": (this._layout.columnWidth ? (this._layout.columnWidth - horizontalPadding) + "px" : "100%") + "!important", "max-width":
(this._layout.columnWidth
? this._layout.columnWidth - horizontalPadding + "px"
: "100%") + "!important",
"max-height": height + "px" + "!important", "max-height": height + "px" + "!important",
"page-break-inside": "avoid", "page-break-inside": "avoid",
"break-inside": "avoid" "break-inside": "avoid",
} },
}); });
return new Promise(function(resolve, reject){ return new Promise(function (resolve, reject) {
// Wait to apply // Wait to apply
setTimeout(function() { setTimeout(function () {
resolve(); resolve();
}, 1); }, 1);
}); });
@ -987,7 +981,7 @@ class Rendition {
* Get the Contents object of each rendered view * Get the Contents object of each rendered view
* @returns {Contents[]} * @returns {Contents[]}
*/ */
getContents () { getContents() {
return this.manager ? this.manager.getContents() : []; return this.manager ? this.manager.getContents() : [];
} }
@ -995,7 +989,7 @@ class Rendition {
* Get the views member from the manager * Get the views member from the manager
* @returns {Views} * @returns {Views}
*/ */
views () { views() {
let views = this.manager ? this.manager.views : undefined; let views = this.manager ? this.manager.views : undefined;
return views || []; return views || [];
} }
@ -1060,7 +1054,6 @@ class Rendition {
} }
doc.getElementsByTagName("head")[0].appendChild(meta); doc.getElementsByTagName("head")[0].appendChild(meta);
} }
} }
//-- Enable binding events to Renderer //-- Enable binding events to Renderer

View file

@ -1,9 +1,9 @@
import {substitute} from "./utils/replacements"; import path from "path-webpack";
import {createBase64Url, createBlobUrl, blob2base64} from "./utils/core"; import { blob2base64, createBase64Url, createBlobUrl } from "./utils/core";
import Url from "./utils/url";
import mime from "./utils/mime"; import mime from "./utils/mime";
import Path from "./utils/path"; import Path from "./utils/path";
import path from "path-webpack"; import { substitute } from "./utils/replacements";
import Url from "./utils/url";
/** /**
* Handle Package Resources * Handle Package Resources
@ -18,9 +18,9 @@ class Resources {
constructor(manifest, options) { constructor(manifest, options) {
this.settings = { this.settings = {
replacements: (options && options.replacements) || "base64", replacements: (options && options.replacements) || "base64",
archive: (options && options.archive), archive: options && options.archive,
resolver: (options && options.resolver), resolver: options && options.resolver,
request: (options && options.request) request: options && options.request,
}; };
this.process(manifest); this.process(manifest);
@ -30,10 +30,9 @@ class Resources {
* Process resources * Process resources
* @param {Manifest} manifest * @param {Manifest} manifest
*/ */
process(manifest){ process(manifest) {
this.manifest = manifest; this.manifest = manifest;
this.resources = Object.keys(manifest). this.resources = Object.keys(manifest).map(function (key) {
map(function (key){
return manifest[key]; return manifest[key];
}); });
@ -54,29 +53,23 @@ class Resources {
* Split resources by type * Split resources by type
* @private * @private
*/ */
split(){ split() {
// HTML // HTML
this.html = this.resources. this.html = this.resources.filter(function (item) {
filter(function (item){ if (item.type === "application/xhtml+xml" || item.type === "text/html") {
if (item.type === "application/xhtml+xml" ||
item.type === "text/html") {
return true; return true;
} }
}); });
// Exclude HTML // Exclude HTML
this.assets = this.resources. this.assets = this.resources.filter(function (item) {
filter(function (item){ if (item.type !== "application/xhtml+xml" && item.type !== "text/html") {
if (item.type !== "application/xhtml+xml" &&
item.type !== "text/html") {
return true; return true;
} }
}); });
// Only CSS // Only CSS
this.css = this.resources. this.css = this.resources.filter(function (item) {
filter(function (item){
if (item.type === "text/css") { if (item.type === "text/css") {
return true; return true;
} }
@ -87,19 +80,18 @@ class Resources {
* Convert split resources into Urls * Convert split resources into Urls
* @private * @private
*/ */
splitUrls(){ splitUrls() {
// All Assets Urls // All Assets Urls
this.urls = this.assets. this.urls = this.assets.map(
map(function(item) { function (item) {
return item.href; return item.href;
}.bind(this)); }.bind(this)
);
// Css Urls // Css Urls
this.cssUrls = this.css.map(function(item) { this.cssUrls = this.css.map(function (item) {
return item.href; return item.href;
}); });
} }
/** /**
@ -107,15 +99,18 @@ class Resources {
* @param {string} url * @param {string} url
* @return {Promise<string>} Promise resolves with url string * @return {Promise<string>} Promise resolves with url string
*/ */
createUrl (url) { createUrl(url) {
var parsedUrl = new Url(url); var parsedUrl = new Url(url);
var mimeType = mime.lookup(parsedUrl.filename); var mimeType = mime.lookup(parsedUrl.filename);
if (this.settings.archive) { if (this.settings.archive) {
return this.settings.archive.createUrl(url, {"base64": (this.settings.replacements === "base64")}); return this.settings.archive.createUrl(url, {
base64: this.settings.replacements === "base64",
});
} else { } else {
if (this.settings.replacements === "base64") { if (this.settings.replacements === "base64") {
return this.settings.request(url, 'blob') return this.settings
.request(url, "blob")
.then((blob) => { .then((blob) => {
return blob2base64(blob); return blob2base64(blob);
}) })
@ -123,9 +118,9 @@ class Resources {
return createBase64Url(blob, mimeType); return createBase64Url(blob, mimeType);
}); });
} else { } else {
return this.settings.request(url, 'blob').then((blob) => { return this.settings.request(url, "blob").then((blob) => {
return createBlobUrl(blob, mimeType); return createBlobUrl(blob, mimeType);
}) });
} }
} }
} }
@ -134,27 +129,26 @@ class Resources {
* Create blob urls for all the assets * Create blob urls for all the assets
* @return {Promise} returns replacement urls * @return {Promise} returns replacement urls
*/ */
replacements(){ replacements() {
if (this.settings.replacements === "none") { if (this.settings.replacements === "none") {
return new Promise(function(resolve) { return new Promise(
function (resolve) {
resolve(this.urls); resolve(this.urls);
}.bind(this)); }.bind(this)
);
} }
var replacements = this.urls.map( (url) => { var replacements = this.urls.map((url) => {
var absolute = this.settings.resolver(url); var absolute = this.settings.resolver(url);
return this.createUrl(absolute). return this.createUrl(absolute).catch(() => {
catch((err) => {
console.error(err);
return null; return null;
}); });
}); });
return Promise.all(replacements) return Promise.all(replacements).then((replacementUrls) => {
.then( (replacementUrls) => {
this.replacementUrls = replacementUrls.filter((url) => { this.replacementUrls = replacementUrls.filter((url) => {
return (typeof(url) === "string"); return typeof url === "string";
}); });
return replacementUrls; return replacementUrls;
}); });
@ -167,23 +161,25 @@ class Resources {
* @param {method} [resolver] * @param {method} [resolver]
* @return {Promise} * @return {Promise}
*/ */
replaceCss(archive, resolver){ replaceCss(archive, resolver) {
var replaced = []; var replaced = [];
archive = archive || this.settings.archive; archive = archive || this.settings.archive;
resolver = resolver || this.settings.resolver; resolver = resolver || this.settings.resolver;
this.cssUrls.forEach(function(href) { this.cssUrls.forEach(
var replacement = this.createCssFile(href, archive, resolver) function (href) {
.then(function (replacementUrl) { var replacement = this.createCssFile(href, archive, resolver).then(
function (replacementUrl) {
// switch the url in the replacementUrls // switch the url in the replacementUrls
var indexInUrls = this.urls.indexOf(href); var indexInUrls = this.urls.indexOf(href);
if (indexInUrls > -1) { if (indexInUrls > -1) {
this.replacementUrls[indexInUrls] = replacementUrl; this.replacementUrls[indexInUrls] = replacementUrl;
} }
}.bind(this)) }.bind(this)
);
replaced.push(replacement); replaced.push(replacement);
}.bind(this)); }.bind(this)
);
return Promise.all(replaced); return Promise.all(replaced);
} }
@ -193,11 +189,11 @@ class Resources {
* @param {string} href the original css file * @param {string} href the original css file
* @return {Promise} returns a BlobUrl to the new CSS file or a data url * @return {Promise} returns a BlobUrl to the new CSS file or a data url
*/ */
createCssFile(href){ createCssFile(href) {
var newUrl; var newUrl;
if (path.isAbsolute(href)) { if (path.isAbsolute(href)) {
return new Promise(function(resolve){ return new Promise(function (resolve) {
resolve(); resolve();
}); });
} }
@ -214,7 +210,7 @@ class Resources {
} }
// Get asset links relative to css file // Get asset links relative to css file
var relUrls = this.urls.map( (assetHref) => { var relUrls = this.urls.map((assetHref) => {
var resolved = this.settings.resolver(assetHref); var resolved = this.settings.resolver(assetHref);
var relative = new Path(absolute).relative(resolved); var relative = new Path(absolute).relative(resolved);
@ -223,12 +219,13 @@ class Resources {
if (!textResponse) { if (!textResponse) {
// file not found, don't replace // file not found, don't replace
return new Promise(function(resolve){ return new Promise(function (resolve) {
resolve(); resolve();
}); });
} }
return textResponse.then( (text) => { return textResponse.then(
(text) => {
// Replacements in the css text // Replacements in the css text
text = substitute(text, relUrls, this.replacementUrls); text = substitute(text, relUrls, this.replacementUrls);
@ -240,13 +237,14 @@ class Resources {
} }
return newUrl; return newUrl;
}, (err) => { },
(err) => {
// handle response errors // handle response errors
return new Promise(function(resolve){ return new Promise(function (resolve) {
resolve(); resolve();
}); });
}); }
);
} }
/** /**
@ -255,16 +253,17 @@ class Resources {
* @param {resolver} [resolver] * @param {resolver} [resolver]
* @return {string[]} array with relative Urls * @return {string[]} array with relative Urls
*/ */
relativeTo(absolute, resolver){ relativeTo(absolute, resolver) {
resolver = resolver || this.settings.resolver; resolver = resolver || this.settings.resolver;
// Get Urls relative to current sections // Get Urls relative to current sections
return this.urls. return this.urls.map(
map(function(href) { function (href) {
var resolved = resolver(href); var resolved = resolver(href);
var relative = new Path(absolute).relative(resolved); var relative = new Path(absolute).relative(resolved);
return relative; return relative;
}.bind(this)); }.bind(this)
);
} }
/** /**
@ -278,9 +277,11 @@ class Resources {
return; return;
} }
if (this.replacementUrls.length) { if (this.replacementUrls.length) {
return new Promise(function(resolve, reject) { return new Promise(
function (resolve, reject) {
resolve(this.replacementUrls[indexInUrls]); resolve(this.replacementUrls[indexInUrls]);
}.bind(this)); }.bind(this)
);
} else { } else {
return this.createUrl(path); return this.createUrl(path);
} }

View file

@ -1,10 +1,9 @@
import { defer } from "./utils/core"; import { DOMParser as XMLDOMSerializer } from "@xmldom/xmldom";
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import { defer, sprint } from "./utils/core";
import Hook from "./utils/hook"; import Hook from "./utils/hook";
import { sprint } from "./utils/core";
import { replaceBase } from "./utils/replacements"; import { replaceBase } from "./utils/replacements";
import Request from "./utils/request"; import Request from "./utils/request";
import { DOMParser as XMLDOMSerializer } from "@xmldom/xmldom";
/** /**
* Represents a Section of the Book * Represents a Section of the Book
@ -14,7 +13,7 @@ import { DOMParser as XMLDOMSerializer } from "@xmldom/xmldom";
* @param {object} hooks hooks for serialize and content * @param {object} hooks hooks for serialize and content
*/ */
class Section { class Section {
constructor(item, hooks){ constructor(item, hooks) {
this.idref = item.idref; this.idref = item.idref;
this.linear = item.linear === "yes"; this.linear = item.linear === "yes";
this.properties = item.properties; this.properties = item.properties;
@ -45,27 +44,31 @@ class Section {
* @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 * @return {document} a promise with the xml document
*/ */
load(_request){ load(_request) {
var request = _request || this.request || Request; var request = _request || this.request || Request;
var loading = new defer(); var loading = new defer();
var loaded = loading.promise; var loaded = loading.promise;
if(this.contents) { if (this.contents) {
loading.resolve(this.contents); loading.resolve(this.contents);
} else { } else {
request(this.url) request(this.url)
.then(function(xml){ .then(
function (xml) {
// var directory = new Url(this.url).directory; // var directory = new Url(this.url).directory;
this.document = xml; this.document = xml;
this.contents = xml.documentElement; this.contents = xml.documentElement;
return this.hooks.content.trigger(this.document, this); return this.hooks.content.trigger(this.document, this);
}.bind(this)) }.bind(this)
.then(function(){ )
.then(
function () {
loading.resolve(this.contents); loading.resolve(this.contents);
}.bind(this)) }.bind(this)
.catch(function(error){ )
.catch(function (error) {
loading.reject(error); loading.reject(error);
}); });
} }
@ -77,7 +80,7 @@ class Section {
* Adds a base tag for resolving urls in the section * Adds a base tag for resolving urls in the section
* @private * @private
*/ */
base(){ base() {
return replaceBase(this.document, this); return replaceBase(this.document, this);
} }
@ -86,15 +89,17 @@ class 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 * @return {string} output a serialized XML Document
*/ */
render(_request){ render(_request) {
var rendering = new defer(); var rendering = new defer();
var rendered = rendering.promise; var rendered = rendering.promise;
this.output; // TODO: better way to return this from hooks? this.output; // TODO: better way to return this from hooks?
this.load(_request). this.load(_request)
then(function(contents){ .then(
var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''; function (contents) {
var isIE = userAgent.indexOf('Trident') >= 0; var userAgent =
(typeof navigator !== "undefined" && navigator.userAgent) || "";
var isIE = userAgent.indexOf("Trident") >= 0;
var Serializer; var Serializer;
if (typeof XMLSerializer === "undefined" || isIE) { if (typeof XMLSerializer === "undefined" || isIE) {
Serializer = XMLDOMSerializer; Serializer = XMLDOMSerializer;
@ -104,14 +109,19 @@ class Section {
var serializer = new Serializer(); var serializer = new Serializer();
this.output = serializer.serializeToString(contents); this.output = serializer.serializeToString(contents);
return this.output; return this.output;
}.bind(this)). }.bind(this)
then(function(){ )
.then(
function () {
return this.hooks.serialize.trigger(this.output, this); return this.hooks.serialize.trigger(this.output, this);
}.bind(this)). }.bind(this)
then(function(){ )
.then(
function () {
rendering.resolve(this.output); rendering.resolve(this.output);
}.bind(this)) }.bind(this)
.catch(function(error){ )
.catch(function (error) {
rendering.reject(error); rendering.reject(error);
}); });
@ -123,11 +133,11 @@ class Section {
* @param {string} _query The query string to find * @param {string} _query The query string to find
* @return {object[]} A list of matches, with form {cfi, excerpt} * @return {object[]} A list of matches, with form {cfi, excerpt}
*/ */
find(_query){ find(_query) {
var section = this; var section = this;
var matches = []; var matches = [];
var query = _query.toLowerCase(); var query = _query.toLowerCase();
var find = function(node){ var find = function (node) {
var text = node.textContent.toLowerCase(); var text = node.textContent.toLowerCase();
var range = section.document.createRange(); var range = section.document.createRange();
var cfi; var cfi;
@ -151,16 +161,18 @@ class Section {
// Generate the excerpt // Generate the excerpt
if (node.textContent.length < limit) { if (node.textContent.length < limit) {
excerpt = node.textContent; excerpt = node.textContent;
} } else {
else { excerpt = node.textContent.substring(
excerpt = node.textContent.substring(pos - limit/2, pos + limit/2); pos - limit / 2,
pos + limit / 2
);
excerpt = "..." + excerpt + "..."; excerpt = "..." + excerpt + "...";
} }
// Add the CFI to the matches list // Add the CFI to the matches list
matches.push({ matches.push({
cfi: cfi, cfi: cfi,
excerpt: excerpt excerpt: excerpt,
}); });
} }
@ -168,13 +180,12 @@ class Section {
} }
}; };
sprint(section.document, function(node) { sprint(section.document, function (node) {
find(node); find(node);
}); });
return matches; return matches;
}; }
/** /**
* Search a string in multiple sequential Element of the section. If the document.createTreeWalker api is missed(eg: IE8), use `find` as a fallback. * Search a string in multiple sequential Element of the section. If the document.createTreeWalker api is missed(eg: IE8), use `find` as a fallback.
@ -182,63 +193,88 @@ class Section {
* @param {int} maxSeqEle The maximum number of Element that are combined for search, default value is 5. * @param {int} maxSeqEle The maximum number of Element that are combined for search, default value is 5.
* @return {object[]} A list of matches, with form {cfi, excerpt} * @return {object[]} A list of matches, with form {cfi, excerpt}
*/ */
search(_query , maxSeqEle = 5){ search(_query, maxSeqEle = 5) {
if (typeof(document.createTreeWalker) == "undefined") { if (typeof document.createTreeWalker == "undefined") {
return this.find(_query); return this.find(_query);
} }
let matches = []; let matches = [];
const excerptLimit = 150; const excerptLimit = 150;
const section = this; const section = this;
const query = _query.toLowerCase(); const query = _query.toLowerCase();
const search = function(nodeList){ const search = function (nodeList) {
const textWithCase = nodeList.reduce((acc ,current)=>{ const textWithCase = nodeList.reduce((acc, current) => {
return acc + current.textContent; return acc + current.textContent;
},""); }, "");
const text = textWithCase.toLowerCase(); const text = textWithCase.toLowerCase();
const pos = text.indexOf(query); const pos = text.indexOf(query);
if (pos != -1){ if (pos != -1) {
const startNodeIndex = 0 , endPos = pos + query.length; const startNodeIndex = 0,
let endNodeIndex = 0 , l = 0; endPos = pos + query.length;
if (pos < nodeList[startNodeIndex].length){ let endNodeIndex = 0,
l = 0;
if (pos < nodeList[startNodeIndex].length) {
let cfi; let cfi;
while( endNodeIndex < nodeList.length - 1 ){ while (endNodeIndex < nodeList.length - 1) {
l += nodeList[endNodeIndex].length; l += nodeList[endNodeIndex].length;
if ( endPos <= l){ if (endPos <= l) {
break; break;
} }
endNodeIndex += 1; endNodeIndex += 1;
} }
let startNode = nodeList[startNodeIndex] , endNode = nodeList[endNodeIndex]; let startNode = nodeList[startNodeIndex],
endNode = nodeList[endNodeIndex];
let range = section.document.createRange(); let range = section.document.createRange();
range.setStart(startNode,pos); range.setStart(startNode, pos);
let beforeEndLengthCount = nodeList.slice(0, endNodeIndex).reduce((acc,current)=>{return acc+current.textContent.length;},0) ; let beforeEndLengthCount = nodeList
range.setEnd(endNode, beforeEndLengthCount > endPos ? endPos : endPos - beforeEndLengthCount ); .slice(0, endNodeIndex)
.reduce((acc, current) => {
return acc + current.textContent.length;
}, 0);
range.setEnd(
endNode,
beforeEndLengthCount > endPos
? endPos
: endPos - beforeEndLengthCount
);
cfi = section.cfiFromRange(range); cfi = section.cfiFromRange(range);
let excerpt = nodeList.slice(0, endNodeIndex+1).reduce((acc,current)=>{return acc+current.textContent ;},""); let excerpt = nodeList
if (excerpt.length > excerptLimit){ .slice(0, endNodeIndex + 1)
excerpt = excerpt.substring(pos - excerptLimit/2, pos + excerptLimit/2); .reduce((acc, current) => {
return acc + current.textContent;
}, "");
if (excerpt.length > excerptLimit) {
excerpt = excerpt.substring(
pos - excerptLimit / 2,
pos + excerptLimit / 2
);
excerpt = "..." + excerpt + "..."; excerpt = "..." + excerpt + "...";
} }
matches.push({ matches.push({
cfi: cfi, cfi: cfi,
excerpt: excerpt excerpt: excerpt,
}); });
} }
} }
} };
const treeWalker = document.createTreeWalker(section.document, NodeFilter.SHOW_TEXT, null, false); const treeWalker = document.createTreeWalker(
let node , nodeList = []; section.document,
while (node = treeWalker.nextNode()) { NodeFilter.SHOW_TEXT,
null,
false
);
let node,
nodeList = [];
while ((node = treeWalker.nextNode())) {
nodeList.push(node); nodeList.push(node);
if (nodeList.length == maxSeqEle){ if (nodeList.length == maxSeqEle) {
search(nodeList.slice(0 , maxSeqEle)); search(nodeList.slice(0, maxSeqEle));
nodeList = nodeList.slice(1, maxSeqEle); nodeList = nodeList.slice(1, maxSeqEle);
} }
} }
if (nodeList.length > 0){ if (nodeList.length > 0) {
search(nodeList); search(nodeList);
} }
return matches; return matches;
@ -250,23 +286,23 @@ class Section {
* @param {object} globalLayout The global layout settings object, chapter properties string * @param {object} globalLayout The global layout settings object, chapter properties string
* @return {object} layoutProperties Object with layout properties * @return {object} layoutProperties Object with layout properties
*/ */
reconcileLayoutSettings(globalLayout){ reconcileLayoutSettings(globalLayout) {
//-- Get the global defaults //-- Get the global defaults
var settings = { var settings = {
layout : globalLayout.layout, layout: globalLayout.layout,
spread : globalLayout.spread, spread: globalLayout.spread,
orientation : globalLayout.orientation orientation: globalLayout.orientation,
}; };
//-- Get the chapter's display type //-- Get the chapter's display type
this.properties.forEach(function(prop){ this.properties.forEach(function (prop) {
var rendition = prop.replace("rendition:", ""); var rendition = prop.replace("rendition:", "");
var split = rendition.indexOf("-"); var split = rendition.indexOf("-");
var property, value; var property, value;
if(split != -1){ if (split != -1) {
property = rendition.slice(0, split); property = rendition.slice(0, split);
value = rendition.slice(split+1); value = rendition.slice(split + 1);
settings[property] = value; settings[property] = value;
} }

View file

@ -1,7 +1,11 @@
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import Hook from "./utils/hook";
import Section from "./section"; import Section from "./section";
import {replaceBase, replaceCanonical, replaceMeta} from "./utils/replacements"; import Hook from "./utils/hook";
import {
replaceBase,
replaceCanonical,
replaceMeta,
} from "./utils/replacements";
/** /**
* A collection of Spine Items * A collection of Spine Items
@ -22,9 +26,7 @@ class Spine {
this.hooks.content.register(replaceMeta); this.hooks.content.register(replaceMeta);
this.epubcfi = new EpubCFI(); this.epubcfi = new EpubCFI();
this.loaded = false; this.loaded = false;
this.items = undefined; this.items = undefined;
this.manifest = undefined; this.manifest = undefined;
this.spineNodeIndex = undefined; this.spineNodeIndex = undefined;
@ -39,40 +41,43 @@ class Spine {
* @param {method} canonical Resolve canonical url * @param {method} canonical Resolve canonical url
*/ */
unpack(_package, resolver, canonical) { unpack(_package, resolver, canonical) {
this.items = _package.spine; this.items = _package.spine;
this.manifest = _package.manifest; this.manifest = _package.manifest;
this.spineNodeIndex = _package.spineNodeIndex; this.spineNodeIndex = _package.spineNodeIndex;
this.baseUrl = _package.baseUrl || _package.basePath || ""; this.baseUrl = _package.baseUrl || _package.basePath || "";
this.length = this.items.length; this.length = this.items.length;
this.items.forEach( (item, index) => { this.items.forEach((item, index) => {
var manifestItem = this.manifest[item.idref]; var manifestItem = this.manifest[item.idref];
var spineItem; var spineItem;
item.index = index; item.index = index;
item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.id); item.cfiBase = this.epubcfi.generateChapterComponent(
this.spineNodeIndex,
item.index,
item.id
);
if (item.href) { if (item.href) {
item.url = resolver(item.href, true); item.url = resolver(item.href, true);
item.canonical = canonical(item.href); item.canonical = canonical(item.href);
} }
if(manifestItem) { if (manifestItem) {
item.href = manifestItem.href; item.href = manifestItem.href;
item.url = resolver(item.href, true); item.url = resolver(item.href, true);
item.canonical = canonical(item.href); item.canonical = canonical(item.href);
if(manifestItem.properties.length){ if (manifestItem.properties.length) {
item.properties.push.apply(item.properties, manifestItem.properties); item.properties.push.apply(item.properties, manifestItem.properties);
} }
} }
if (item.linear === "yes") { if (item.linear === "yes") {
item.prev = function() { item.prev = function () {
let prevIndex = item.index; let prevIndex = item.index;
while (prevIndex > 0) { while (prevIndex > 0) {
let prev = this.get(prevIndex-1); let prev = this.get(prevIndex - 1);
if (prev && prev.linear) { if (prev && prev.linear) {
return prev; return prev;
} }
@ -80,10 +85,10 @@ class Spine {
} }
return; return;
}.bind(this); }.bind(this);
item.next = function() { item.next = function () {
let nextIndex = item.index; let nextIndex = item.index;
while (nextIndex < this.spineItems.length-1) { while (nextIndex < this.spineItems.length - 1) {
let next = this.get(nextIndex+1); let next = this.get(nextIndex + 1);
if (next && next.linear) { if (next && next.linear) {
return next; return next;
} }
@ -92,20 +97,17 @@ class Spine {
return; return;
}.bind(this); }.bind(this);
} else { } else {
item.prev = function() { item.prev = function () {
return; return;
} };
item.next = function() { item.next = function () {
return; return;
};
} }
}
spineItem = new Section(item, this.hooks); spineItem = new Section(item, this.hooks);
this.append(spineItem); this.append(spineItem);
}); });
this.loaded = true; this.loaded = true;
@ -131,14 +133,14 @@ class Spine {
} }
index += 1; index += 1;
} }
} else if(this.epubcfi.isCfiString(target)) { } else if (this.epubcfi.isCfiString(target)) {
let cfi = new EpubCFI(target); let cfi = new EpubCFI(target);
index = cfi.spinePos; index = cfi.spinePos;
} else if(typeof target === "number" || isNaN(target) === false){ } else if (typeof target === "number" || isNaN(target) === false) {
index = target; index = target;
} else if(typeof target === "string" && target.indexOf("#") === 0) { } else if (typeof target === "string" && target.indexOf("#") === 0) {
index = this.spineById[target.substring(1)]; index = this.spineById[target.substring(1)];
} else if(typeof target === "string") { } else if (typeof target === "string") {
// Remove fragments // Remove fragments
target = target.split("#")[0]; target = target.split("#")[0];
index = this.spineByHref[target] || this.spineByHref[encodeURI(target)]; index = this.spineByHref[target] || this.spineByHref[encodeURI(target)];
@ -180,7 +182,7 @@ class Spine {
this.spineById[section.idref] = 0; this.spineById[section.idref] = 0;
// Re-index // Re-index
this.spineItems.forEach(function(item, index){ this.spineItems.forEach(function (item, index) {
item.index = index; item.index = index;
}); });
@ -199,7 +201,7 @@ class Spine {
remove(section) { remove(section) {
var index = this.spineItems.indexOf(section); var index = this.spineItems.indexOf(section);
if(index > -1) { if (index > -1) {
delete this.spineByHref[section.href]; delete this.spineByHref[section.href];
delete this.spineById[section.idref]; delete this.spineById[section.idref];
@ -229,7 +231,7 @@ class Spine {
return next; return next;
} }
index += 1; index += 1;
} while (index < this.spineItems.length) ; } while (index < this.spineItems.length);
} }
/** /**
@ -237,7 +239,7 @@ class Spine {
* @return {Section} last section * @return {Section} last section
*/ */
last() { last() {
let index = this.spineItems.length-1; let index = this.spineItems.length - 1;
do { do {
let prev = this.get(index); let prev = this.get(index);
@ -251,9 +253,9 @@ class Spine {
destroy() { destroy() {
this.each((section) => section.destroy()); this.each((section) => section.destroy());
this.spineItems = undefined this.spineItems = undefined;
this.spineByHref = undefined this.spineByHref = undefined;
this.spineById = undefined this.spineById = undefined;
this.hooks.serialize.clear(); this.hooks.serialize.clear();
this.hooks.content.clear(); this.hooks.content.clear();

View file

@ -1,9 +1,9 @@
import {defer, isXml, parse} from "./utils/core";
import httpRequest from "./utils/request";
import mime from "./utils/mime";
import Path from "./utils/path";
import EventEmitter from "event-emitter"; import EventEmitter from "event-emitter";
import localforage from "localforage"; import localforage from "localforage";
import { defer, isXml, parse } from "./utils/core";
import mime from "./utils/mime";
import Path from "./utils/path";
import httpRequest from "./utils/request";
/** /**
* Handles saving and requesting files from local storage * Handles saving and requesting files from local storage
@ -13,20 +13,15 @@ import localforage from "localforage";
* @param {function} [resolver] * @param {function} [resolver]
*/ */
class Store { class Store {
constructor(name, requester, resolver) { constructor(name, requester, resolver) {
this.urlCache = {}; this.urlCache = {};
this.storage = undefined; this.storage = undefined;
this.name = name; this.name = name;
this.requester = requester || httpRequest; this.requester = requester || httpRequest;
this.resolver = resolver; this.resolver = resolver;
this.online = true; this.online = true;
this.checkRequirements(); this.checkRequirements();
this.addListeners(); this.addListeners();
} }
@ -35,14 +30,14 @@ class Store {
* Requires localForage if it isn't there * Requires localForage if it isn't there
* @private * @private
*/ */
checkRequirements(){ checkRequirements() {
try { try {
let store; let store;
if (typeof localforage === "undefined") { if (typeof localforage === "undefined") {
store = localforage; store = localforage;
} }
this.storage = store.createInstance({ this.storage = store.createInstance({
name: this.name name: this.name,
}); });
} catch (e) { } catch (e) {
throw new Error("localForage lib not loaded"); throw new Error("localForage lib not loaded");
@ -55,8 +50,8 @@ class Store {
*/ */
addListeners() { addListeners() {
this._status = this.status.bind(this); this._status = this.status.bind(this);
window.addEventListener('online', this._status); window.addEventListener("online", this._status);
window.addEventListener('offline', this._status); window.addEventListener("offline", this._status);
} }
/** /**
@ -64,8 +59,8 @@ class Store {
* @private * @private
*/ */
removeListeners() { removeListeners() {
window.removeEventListener('online', this._status); window.removeEventListener("online", this._status);
window.removeEventListener('offline', this._status); window.removeEventListener("offline", this._status);
this._status = undefined; this._status = undefined;
} }
@ -97,15 +92,13 @@ class Store {
return this.storage.getItem(encodedUrl).then((item) => { return this.storage.getItem(encodedUrl).then((item) => {
if (!item || force) { if (!item || force) {
return this.requester(url, "binary") return this.requester(url, "binary").then((data) => {
.then((data) => {
return this.storage.setItem(encodedUrl, data); return this.storage.setItem(encodedUrl, data);
}); });
} else { } else {
return item; return item;
} }
}); });
}); });
return Promise.all(mapped); return Promise.all(mapped);
} }
@ -122,9 +115,11 @@ class Store {
return this.storage.getItem(encodedUrl).then((result) => { return this.storage.getItem(encodedUrl).then((result) => {
if (!result) { if (!result) {
return this.requester(url, "binary", withCredentials, headers).then((data) => { return this.requester(url, "binary", withCredentials, headers).then(
(data) => {
return this.storage.setItem(encodedUrl, data); return this.storage.setItem(encodedUrl, data);
}); }
);
} }
return result; return result;
}); });
@ -138,19 +133,20 @@ class Store {
* @param {object} [headers] * @param {object} [headers]
* @return {Promise<Blob | string | JSON | Document | XMLDocument>} * @return {Promise<Blob | string | JSON | Document | XMLDocument>}
*/ */
request(url, type, withCredentials, headers){ request(url, type, withCredentials, headers) {
if (this.online) { if (this.online) {
// From network // From network
return this.requester(url, type, withCredentials, headers).then((data) => { return this.requester(url, type, withCredentials, headers).then(
(data) => {
// save to store if not present // save to store if not present
this.put(url); this.put(url);
return data; return data;
}) }
);
} else { } else {
// From store // From store
return this.retrieve(url, type); return this.retrieve(url, type);
} }
} }
/** /**
@ -160,22 +156,20 @@ class Store {
* @return {Promise<Blob | string | JSON | Document | XMLDocument>} * @return {Promise<Blob | string | JSON | Document | XMLDocument>}
*/ */
retrieve(url, type) { retrieve(url, type) {
var deferred = new defer();
var response; var response;
var path = new Path(url); var path = new Path(url);
// If type isn't set, determine it from the file extension // If type isn't set, determine it from the file extension
if(!type) { if (!type) {
type = path.extension; type = path.extension;
} }
if(type == "blob"){ if (type == "blob") {
response = this.getBlob(url); response = this.getBlob(url);
} else { } else {
response = this.getText(url); response = this.getText(url);
} }
return response.then((r) => { return response.then((r) => {
var deferred = new defer(); var deferred = new defer();
var result; var result;
@ -184,8 +178,8 @@ class Store {
deferred.resolve(result); deferred.resolve(result);
} else { } else {
deferred.reject({ deferred.reject({
message : "File not found in storage: " + url, message: "File not found in storage: " + url,
stack : new Error().stack stack: new Error().stack,
}); });
} }
return deferred.promise; return deferred.promise;
@ -199,22 +193,16 @@ class Store {
* @param {string} [type] * @param {string} [type]
* @return {any} the parsed result * @return {any} the parsed result
*/ */
handleResponse(response, type){ handleResponse(response, type) {
var r; var r;
if(type == "json") { if (type == "json") {
r = JSON.parse(response); r = JSON.parse(response);
} } else if (isXml(type)) {
else
if(isXml(type)) {
r = parse(response, "text/xml"); r = parse(response, "text/xml");
} } else if (type == "xhtml") {
else
if(type == "xhtml") {
r = parse(response, "application/xhtml+xml"); r = parse(response, "application/xhtml+xml");
} } else if (type == "html" || type == "htm") {
else
if(type == "html" || type == "htm") {
r = parse(response, "text/html"); r = parse(response, "text/html");
} else { } else {
r = response; r = response;
@ -229,17 +217,16 @@ class Store {
* @param {string} [mimeType] * @param {string} [mimeType]
* @return {Blob} * @return {Blob}
*/ */
getBlob(url, mimeType){ getBlob(url, mimeType) {
let encodedUrl = window.encodeURIComponent(url); let encodedUrl = window.encodeURIComponent(url);
return this.storage.getItem(encodedUrl).then(function(uint8array) { return this.storage.getItem(encodedUrl).then(function (uint8array) {
if(!uint8array) return; if (!uint8array) return;
mimeType = mimeType || mime.lookup(url); mimeType = mimeType || mime.lookup(url);
return new Blob([uint8array], {type : mimeType}); return new Blob([uint8array], { type: mimeType });
}); });
} }
/** /**
@ -248,19 +235,19 @@ class Store {
* @param {string} [mimeType] * @param {string} [mimeType]
* @return {string} * @return {string}
*/ */
getText(url, mimeType){ getText(url, mimeType) {
let encodedUrl = window.encodeURIComponent(url); let encodedUrl = window.encodeURIComponent(url);
mimeType = mimeType || mime.lookup(url); mimeType = mimeType || mime.lookup(url);
return this.storage.getItem(encodedUrl).then(function(uint8array) { return this.storage.getItem(encodedUrl).then(function (uint8array) {
var deferred = new defer(); var deferred = new defer();
var reader = new FileReader(); var reader = new FileReader();
var blob; var blob;
if(!uint8array) return; if (!uint8array) return;
blob = new Blob([uint8array], {type : mimeType}); blob = new Blob([uint8array], { type: mimeType });
reader.addEventListener("loadend", () => { reader.addEventListener("loadend", () => {
deferred.resolve(reader.result); deferred.resolve(reader.result);
@ -278,7 +265,7 @@ class Store {
* @param {string} [mimeType] * @param {string} [mimeType]
* @return {string} base64 encoded * @return {string} base64 encoded
*/ */
getBase64(url, mimeType){ getBase64(url, mimeType) {
let encodedUrl = window.encodeURIComponent(url); let encodedUrl = window.encodeURIComponent(url);
mimeType = mimeType || mime.lookup(url); mimeType = mimeType || mime.lookup(url);
@ -288,9 +275,9 @@ class Store {
var reader = new FileReader(); var reader = new FileReader();
var blob; var blob;
if(!uint8array) return; if (!uint8array) return;
blob = new Blob([uint8array], {type : mimeType}); blob = new Blob([uint8array], { type: mimeType });
reader.addEventListener("loadend", () => { reader.addEventListener("loadend", () => {
deferred.resolve(reader.result); deferred.resolve(reader.result);
@ -307,14 +294,14 @@ class Store {
* @param {object} [options.base64] use base64 encoding or blob url * @param {object} [options.base64] use base64 encoding or blob url
* @return {Promise} url promise with Url string * @return {Promise} url promise with Url string
*/ */
createUrl(url, options){ createUrl(url, options) {
var deferred = new defer(); var deferred = new defer();
var _URL = window.URL || window.webkitURL || window.mozURL; var _URL = window.URL || window.webkitURL || window.mozURL;
var tempUrl; var tempUrl;
var response; var response;
var useBase64 = options && options.base64; var useBase64 = options && options.base64;
if(url in this.urlCache) { if (url in this.urlCache) {
deferred.resolve(this.urlCache[url]); deferred.resolve(this.urlCache[url]);
return deferred.promise; return deferred.promise;
} }
@ -323,36 +310,31 @@ class Store {
response = this.getBase64(url); response = this.getBase64(url);
if (response) { if (response) {
response.then(function(tempUrl) { response.then(
function (tempUrl) {
this.urlCache[url] = tempUrl; this.urlCache[url] = tempUrl;
deferred.resolve(tempUrl); deferred.resolve(tempUrl);
}.bind(this)
}.bind(this)); );
} }
} else { } else {
response = this.getBlob(url); response = this.getBlob(url);
if (response) { if (response) {
response.then(function(blob) { response.then(
function (blob) {
tempUrl = _URL.createObjectURL(blob); tempUrl = _URL.createObjectURL(blob);
this.urlCache[url] = tempUrl; this.urlCache[url] = tempUrl;
deferred.resolve(tempUrl); deferred.resolve(tempUrl);
}.bind(this)
}.bind(this)); );
} }
} }
if (!response) { if (!response) {
deferred.reject({ deferred.reject({
message : "File not found in storage: " + url, message: "File not found in storage: " + url,
stack : new Error().stack stack: new Error().stack,
}); });
} }
@ -363,10 +345,10 @@ class Store {
* Revoke Temp Url for a archive item * Revoke Temp Url for a archive item
* @param {string} url url of the item in the store * @param {string} url url of the item in the store
*/ */
revokeUrl(url){ revokeUrl(url) {
var _URL = window.URL || window.webkitURL || window.mozURL; var _URL = window.URL || window.webkitURL || window.mozURL;
var fromCache = this.urlCache[url]; var fromCache = this.urlCache[url];
if(fromCache) _URL.revokeObjectURL(fromCache); if (fromCache) _URL.revokeObjectURL(fromCache);
} }
destroy() { destroy() {

View file

@ -9,18 +9,17 @@ class Themes {
constructor(rendition) { constructor(rendition) {
this.rendition = rendition; this.rendition = rendition;
this._themes = { this._themes = {
"default" : { default: {
"rules" : {}, rules: {},
"url" : "", url: "",
"serialized" : "" serialized: "",
} },
}; };
this._overrides = {}; this._overrides = {};
this._current = "default"; this._current = "default";
this._injected = []; this._injected = [];
this.rendition.hooks.content.register(this.inject.bind(this)); this.rendition.hooks.content.register(this.inject.bind(this));
this.rendition.hooks.content.register(this.overrides.bind(this)); this.rendition.hooks.content.register(this.overrides.bind(this));
} }
/** /**
@ -30,20 +29,20 @@ class Themes {
* @example themes.register("light", { "body": { "color": "purple"}}) * @example themes.register("light", { "body": { "color": "purple"}})
* @example themes.register({ "light" : {...}, "dark" : {...}}) * @example themes.register({ "light" : {...}, "dark" : {...}})
*/ */
register () { register() {
if (arguments.length === 0) { if (arguments.length === 0) {
return; return;
} }
if (arguments.length === 1 && typeof(arguments[0]) === "object") { if (arguments.length === 1 && typeof arguments[0] === "object") {
return this.registerThemes(arguments[0]); return this.registerThemes(arguments[0]);
} }
if (arguments.length === 1 && typeof(arguments[0]) === "string") { if (arguments.length === 1 && typeof arguments[0] === "string") {
return this.default(arguments[0]); return this.default(arguments[0]);
} }
if (arguments.length === 2 && typeof(arguments[1]) === "string") { if (arguments.length === 2 && typeof arguments[1] === "string") {
return this.registerUrl(arguments[0], arguments[1]); return this.registerUrl(arguments[0], arguments[1]);
} }
if (arguments.length === 2 && typeof(arguments[1]) === "object") { if (arguments.length === 2 && typeof arguments[1] === "object") {
return this.registerRules(arguments[0], arguments[1]); return this.registerRules(arguments[0], arguments[1]);
} }
} }
@ -54,14 +53,14 @@ class Themes {
* @example themes.register("http://example.com/default.css") * @example themes.register("http://example.com/default.css")
* @example themes.register({ "body": { "color": "purple"}}) * @example themes.register({ "body": { "color": "purple"}})
*/ */
default (theme) { default(theme) {
if (!theme) { if (!theme) {
return; return;
} }
if (typeof(theme) === "string") { if (typeof theme === "string") {
return this.registerUrl("default", theme); return this.registerUrl("default", theme);
} }
if (typeof(theme) === "object") { if (typeof theme === "object") {
return this.registerRules("default", theme); return this.registerRules("default", theme);
} }
} }
@ -70,10 +69,10 @@ class Themes {
* Register themes object * Register themes object
* @param {object} themes * @param {object} themes
*/ */
registerThemes (themes) { registerThemes(themes) {
for (var theme in themes) { for (var theme in themes) {
if (themes.hasOwnProperty(theme)) { if (themes.hasOwnProperty(theme)) {
if (typeof(themes[theme]) === "string") { if (typeof themes[theme] === "string") {
this.registerUrl(theme, themes[theme]); this.registerUrl(theme, themes[theme]);
} else { } else {
this.registerRules(theme, themes[theme]); this.registerRules(theme, themes[theme]);
@ -87,9 +86,9 @@ class Themes {
* @param {string} name * @param {string} name
* @param {string} css * @param {string} css
*/ */
registerCss (name, css) { registerCss(name, css) {
this._themes[name] = { "serialized" : css }; this._themes[name] = { serialized: css };
if (this._injected[name] || name == 'default') { if (this._injected[name] || name == "default") {
this.update(name); this.update(name);
} }
} }
@ -99,10 +98,10 @@ class Themes {
* @param {string} name * @param {string} name
* @param {string} input * @param {string} input
*/ */
registerUrl (name, input) { registerUrl(name, input) {
var url = new Url(input); var url = new Url(input);
this._themes[name] = { "url": url.toString() }; this._themes[name] = { url: url.toString() };
if (this._injected[name] || name == 'default') { if (this._injected[name] || name == "default") {
this.update(name); this.update(name);
} }
} }
@ -112,10 +111,10 @@ class Themes {
* @param {string} name * @param {string} name
* @param {object} rules * @param {object} rules
*/ */
registerRules (name, rules) { registerRules(name, rules) {
this._themes[name] = { "rules": rules }; this._themes[name] = { rules: rules };
// TODO: serialize css rules // TODO: serialize css rules
if (this._injected[name] || name == 'default') { if (this._injected[name] || name == "default") {
this.update(name); this.update(name);
} }
} }
@ -124,7 +123,7 @@ class Themes {
* Select a theme * Select a theme
* @param {string} name * @param {string} name
*/ */
select (name) { select(name) {
var prev = this._current; var prev = this._current;
var contents; var contents;
@ -132,7 +131,7 @@ class Themes {
this.update(name); this.update(name);
contents = this.rendition.getContents(); contents = this.rendition.getContents();
contents.forEach( (content) => { contents.forEach((content) => {
content.removeClass(prev); content.removeClass(prev);
content.addClass(name); content.addClass(name);
}); });
@ -142,9 +141,9 @@ class Themes {
* Update a theme * Update a theme
* @param {string} name * @param {string} name
*/ */
update (name) { update(name) {
var contents = this.rendition.getContents(); var contents = this.rendition.getContents();
contents.forEach( (content) => { contents.forEach((content) => {
this.add(name, content); this.add(name, content);
}); });
} }
@ -153,22 +152,28 @@ class Themes {
* Inject all themes into contents * Inject all themes into contents
* @param {Contents} contents * @param {Contents} contents
*/ */
inject (contents) { inject(contents) {
var links = []; var links = [];
var themes = this._themes; var themes = this._themes;
var theme; var theme;
for (var name in themes) { for (var name in themes) {
if (themes.hasOwnProperty(name) && (name === this._current || name === "default")) { if (
themes.hasOwnProperty(name) &&
(name === this._current || name === "default")
) {
theme = themes[name]; theme = themes[name];
if((theme.rules && Object.keys(theme.rules).length > 0) || (theme.url && links.indexOf(theme.url) === -1)) { if (
(theme.rules && Object.keys(theme.rules).length > 0) ||
(theme.url && links.indexOf(theme.url) === -1)
) {
this.add(name, contents); this.add(name, contents);
} }
this._injected.push(name); this._injected.push(name);
} }
} }
if(this._current != "default") { if (this._current != "default") {
contents.addClass(this._current); contents.addClass(this._current);
} }
} }
@ -178,7 +183,7 @@ class Themes {
* @param {string} name * @param {string} name
* @param {Contents} contents * @param {Contents} contents
*/ */
add (name, contents) { add(name, contents) {
var theme = this._themes[name]; var theme = this._themes[name];
if (!theme || !contents) { if (!theme || !contents) {
@ -202,25 +207,29 @@ class Themes {
* @param {string} value * @param {string} value
* @param {boolean} priority * @param {boolean} priority
*/ */
override (name, value, priority) { override(name, value, priority) {
var contents = this.rendition.getContents(); var contents = this.rendition.getContents();
this._overrides[name] = { this._overrides[name] = {
value: value, value: value,
priority: priority === true priority: priority === true,
}; };
contents.forEach( (content) => { contents.forEach((content) => {
content.css(name, this._overrides[name].value, this._overrides[name].priority); content.css(
name,
this._overrides[name].value,
this._overrides[name].priority
);
}); });
} }
removeOverride (name) { removeOverride(name) {
var contents = this.rendition.getContents(); var contents = this.rendition.getContents();
delete this._overrides[name]; delete this._overrides[name];
contents.forEach( (content) => { contents.forEach((content) => {
content.css(name); content.css(name);
}); });
} }
@ -229,7 +238,7 @@ class Themes {
* Add all overrides * Add all overrides
* @param {Content} content * @param {Content} content
*/ */
overrides (contents) { overrides(contents) {
var overrides = this._overrides; var overrides = this._overrides;
for (var rule in overrides) { for (var rule in overrides) {
@ -243,7 +252,7 @@ class Themes {
* Adjust the font size of a rendition * Adjust the font size of a rendition
* @param {number} size * @param {number} size
*/ */
fontSize (size) { fontSize(size) {
this.override("font-size", size); this.override("font-size", size);
} }
@ -251,7 +260,7 @@ class Themes {
* Adjust the font-family of a rendition * Adjust the font-family of a rendition
* @param {string} f * @param {string} f
*/ */
font (f) { font(f) {
this.override("font-family", f, true); this.override("font-family", f, true);
} }
@ -262,7 +271,6 @@ class Themes {
this._current = undefined; this._current = undefined;
this._injected = undefined; this._injected = undefined;
} }
} }
export default Themes; export default Themes;

View file

@ -1,62 +1,73 @@
export const EPUBJS_VERSION = "0.3"; export const EPUBJS_VERSION = "0.3";
// Dom events to listen for // Dom events to listen for
export const DOM_EVENTS = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "mousemove", "click", "touchend", "touchstart", "touchmove"]; export const DOM_EVENTS = [
"keydown",
"keyup",
"keypressed",
"mouseup",
"mousedown",
"mousemove",
"click",
"touchend",
"touchstart",
"touchmove",
];
export const EVENTS = { export const EVENTS = {
BOOK : { BOOK: {
OPEN_FAILED : "openFailed" OPEN_FAILED: "openFailed",
}, },
CONTENTS : { CONTENTS: {
EXPAND : "expand", EXPAND: "expand",
RESIZE : "resize", RESIZE: "resize",
SELECTED : "selected", SELECTED: "selected",
SELECTED_RANGE : "selectedRange", SELECTED_RANGE: "selectedRange",
LINK_CLICKED : "linkClicked" LINK_CLICKED: "linkClicked",
}, },
LOCATIONS : { LOCATIONS: {
CHANGED : "changed" CHANGED: "changed",
}, },
MANAGERS : { MANAGERS: {
RESIZE : "resize", RESIZE: "resize",
RESIZED : "resized", RESIZED: "resized",
ORIENTATION_CHANGE : "orientationchange", ORIENTATION_CHANGE: "orientationchange",
ADDED : "added", ADDED: "added",
SCROLL : "scroll", SCROLL: "scroll",
SCROLLED : "scrolled", SCROLLED: "scrolled",
REMOVED : "removed", REMOVED: "removed",
}, },
VIEWS : { VIEWS: {
AXIS: "axis", AXIS: "axis",
WRITING_MODE: "writingMode", WRITING_MODE: "writingMode",
LOAD_ERROR : "loaderror", LOAD_ERROR: "loaderror",
RENDERED : "rendered", RENDERED: "rendered",
RESIZED : "resized", RESIZED: "resized",
DISPLAYED : "displayed", DISPLAYED: "displayed",
SHOWN : "shown", SHOWN: "shown",
HIDDEN : "hidden", HIDDEN: "hidden",
MARK_CLICKED : "markClicked" MARK_CLICKED: "markClicked",
}, },
RENDITION : { RENDITION: {
STARTED : "started", STARTED: "started",
ATTACHED : "attached", ATTACHED: "attached",
DISPLAYED : "displayed", DISPLAYED: "displayed",
DISPLAY_ERROR : "displayerror", DISPLAY_ERROR: "displayerror",
RENDERED : "rendered", RENDERED: "rendered",
REMOVED : "removed", REMOVED: "removed",
RESIZED : "resized", RESIZED: "resized",
ORIENTATION_CHANGE : "orientationchange", ORIENTATION_CHANGE: "orientationchange",
LOCATION_CHANGED : "locationChanged", LOCATION_CHANGED: "locationChanged",
RELOCATED : "relocated", RELOCATED: "relocated",
MARK_CLICKED : "markClicked", MARK_CLICKED: "markClicked",
SELECTED : "selected", SELECTED: "selected",
LAYOUT: "layout" LAYOUT: "layout",
}, },
LAYOUT : { LAYOUT: {
UPDATED : "updated" UPDATED: "updated",
}, },
ANNOTATION : { ANNOTATION: {
ATTACH : "attach", ATTACH: "attach",
DETACH : "detach" DETACH: "detach",
} },
} };

View file

@ -1,7 +1,7 @@
/** /**
* Core Utilities and Helpers * Core Utilities and Helpers
* @module Core * @module Core
*/ */
import { DOMParser as XMLDOMParser } from "@xmldom/xmldom"; import { DOMParser as XMLDOMParser } from "@xmldom/xmldom";
/** /**
@ -9,12 +9,21 @@ import { DOMParser as XMLDOMParser } from "@xmldom/xmldom";
* @returns {function} requestAnimationFrame * @returns {function} requestAnimationFrame
* @memberof Core * @memberof Core
*/ */
export const requestAnimationFrame = (typeof window != "undefined") ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false; export const requestAnimationFrame =
typeof window != "undefined"
? window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame
: false;
const ELEMENT_NODE = 1; const ELEMENT_NODE = 1;
const TEXT_NODE = 3; const TEXT_NODE = 3;
const COMMENT_NODE = 8; const _URL =
const DOCUMENT_NODE = 9; typeof URL != "undefined"
const _URL = typeof URL != "undefined" ? URL : (typeof window != "undefined" ? (window.URL || window.webkitURL || window.mozURL) : undefined); ? URL
: typeof window != "undefined"
? window.URL || window.webkitURL || window.mozURL
: undefined;
/** /**
* Generates a UUID * Generates a UUID
@ -24,11 +33,14 @@ const _URL = typeof URL != "undefined" ? URL : (typeof window != "undefined" ? (
*/ */
export function uuid() { export function uuid() {
var d = new Date().getTime(); var d = new Date().getTime();
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
var r = (d + Math.random()*16)%16 | 0; /[xy]/g,
d = Math.floor(d/16); function (c) {
return (c=="x" ? r : (r&0x7|0x8)).toString(16); var r = (d + Math.random() * 16) % 16 | 0;
}); d = Math.floor(d / 16);
return (c == "x" ? r : (r & 0x7) | 0x8).toString(16);
}
);
return uuid; return uuid;
} }
@ -92,17 +104,20 @@ export function isFloat(n) {
* @memberof Core * @memberof Core
*/ */
export function prefixed(unprefixed) { export function prefixed(unprefixed) {
var vendors = ["Webkit", "webkit", "Moz", "O", "ms" ]; var vendors = ["Webkit", "webkit", "Moz", "O", "ms"];
var prefixes = ["-webkit-", "-webkit-", "-moz-", "-o-", "-ms-"]; var prefixes = ["-webkit-", "-webkit-", "-moz-", "-o-", "-ms-"];
var lower = unprefixed.toLowerCase(); var lower = unprefixed.toLowerCase();
var length = vendors.length; var length = vendors.length;
if (typeof(document) === "undefined" || typeof(document.body.style[lower]) != "undefined") { if (
typeof document === "undefined" ||
typeof document.body.style[lower] != "undefined"
) {
return unprefixed; return unprefixed;
} }
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
if (typeof(document.body.style[prefixes[i] + lower]) != "undefined") { if (typeof document.body.style[prefixes[i] + lower] != "undefined") {
return prefixes[i] + lower; return prefixes[i] + lower;
} }
} }
@ -135,9 +150,13 @@ export function defaults(obj) {
export function extend(target) { export function extend(target) {
var sources = [].slice.call(arguments, 1); var sources = [].slice.call(arguments, 1);
sources.forEach(function (source) { sources.forEach(function (source) {
if(!source) return; if (!source) return;
Object.getOwnPropertyNames(source).forEach(function(propName) { Object.getOwnPropertyNames(source).forEach(function (propName) {
Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); Object.defineProperty(
target,
propName,
Object.getOwnPropertyDescriptor(source, propName)
);
}); });
}); });
return target; return target;
@ -174,27 +193,27 @@ export function locationOf(item, array, compareFunction, _start, _end) {
var end = _end || array.length; var end = _end || array.length;
var pivot = parseInt(start + (end - start) / 2); var pivot = parseInt(start + (end - start) / 2);
var compared; var compared;
if(!compareFunction){ if (!compareFunction) {
compareFunction = function(a, b) { compareFunction = function (a, b) {
if(a > b) return 1; if (a > b) return 1;
if(a < b) return -1; if (a < b) return -1;
if(a == b) return 0; if (a == b) return 0;
}; };
} }
if(end-start <= 0) { if (end - start <= 0) {
return pivot; return pivot;
} }
compared = compareFunction(array[pivot], item); compared = compareFunction(array[pivot], item);
if(end-start === 1) { if (end - start === 1) {
return compared >= 0 ? pivot : pivot + 1; return compared >= 0 ? pivot : pivot + 1;
} }
if(compared === 0) { if (compared === 0) {
return pivot; return pivot;
} }
if(compared === -1) { if (compared === -1) {
return locationOf(item, array, compareFunction, pivot, end); return locationOf(item, array, compareFunction, pivot, end);
} else{ } else {
return locationOf(item, array, compareFunction, start, pivot); return locationOf(item, array, compareFunction, start, pivot);
} }
} }
@ -215,27 +234,27 @@ export function indexOfSorted(item, array, compareFunction, _start, _end) {
var end = _end || array.length; var end = _end || array.length;
var pivot = parseInt(start + (end - start) / 2); var pivot = parseInt(start + (end - start) / 2);
var compared; var compared;
if(!compareFunction){ if (!compareFunction) {
compareFunction = function(a, b) { compareFunction = function (a, b) {
if(a > b) return 1; if (a > b) return 1;
if(a < b) return -1; if (a < b) return -1;
if(a == b) return 0; if (a == b) return 0;
}; };
} }
if(end-start <= 0) { if (end - start <= 0) {
return -1; // Not found return -1; // Not found
} }
compared = compareFunction(array[pivot], item); compared = compareFunction(array[pivot], item);
if(end-start === 1) { if (end - start === 1) {
return compared === 0 ? pivot : -1; return compared === 0 ? pivot : -1;
} }
if(compared === 0) { if (compared === 0) {
return pivot; // Found return pivot; // Found
} }
if(compared === -1) { if (compared === -1) {
return indexOfSorted(item, array, compareFunction, pivot, end); return indexOfSorted(item, array, compareFunction, pivot, end);
} else{ } else {
return indexOfSorted(item, array, compareFunction, start, pivot); return indexOfSorted(item, array, compareFunction, start, pivot);
} }
} }
@ -247,27 +266,41 @@ export function indexOfSorted(item, array, compareFunction, _start, _end) {
* @memberof Core * @memberof Core
*/ */
export function bounds(el) { export function bounds(el) {
var style = window.getComputedStyle(el); var style = window.getComputedStyle(el);
var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; var widthProps = [
var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; "width",
"paddingRight",
"paddingLeft",
"marginRight",
"marginLeft",
"borderRightWidth",
"borderLeftWidth",
];
var heightProps = [
"height",
"paddingTop",
"paddingBottom",
"marginTop",
"marginBottom",
"borderTopWidth",
"borderBottomWidth",
];
var width = 0; var width = 0;
var height = 0; var height = 0;
widthProps.forEach(function(prop){ widthProps.forEach(function (prop) {
width += parseFloat(style[prop]) || 0; width += parseFloat(style[prop]) || 0;
}); });
heightProps.forEach(function(prop){ heightProps.forEach(function (prop) {
height += parseFloat(style[prop]) || 0; height += parseFloat(style[prop]) || 0;
}); });
return { return {
height: height, height: height,
width: width width: width,
}; };
} }
/** /**
@ -278,27 +311,39 @@ export function bounds(el) {
* @memberof Core * @memberof Core
*/ */
export function borders(el) { export function borders(el) {
var style = window.getComputedStyle(el); var style = window.getComputedStyle(el);
var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; var widthProps = [
var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; "paddingRight",
"paddingLeft",
"marginRight",
"marginLeft",
"borderRightWidth",
"borderLeftWidth",
];
var heightProps = [
"paddingTop",
"paddingBottom",
"marginTop",
"marginBottom",
"borderTopWidth",
"borderBottomWidth",
];
var width = 0; var width = 0;
var height = 0; var height = 0;
widthProps.forEach(function(prop){ widthProps.forEach(function (prop) {
width += parseFloat(style[prop]) || 0; width += parseFloat(style[prop]) || 0;
}); });
heightProps.forEach(function(prop){ heightProps.forEach(function (prop) {
height += parseFloat(style[prop]) || 0; height += parseFloat(style[prop]) || 0;
}); });
return { return {
height: height, height: height,
width: width width: width,
}; };
} }
/** /**
@ -311,7 +356,7 @@ export function borders(el) {
export function nodeBounds(node) { export function nodeBounds(node) {
let elPos; let elPos;
let doc = node.ownerDocument; let doc = node.ownerDocument;
if(node.nodeType == Node.TEXT_NODE){ if (node.nodeType == Node.TEXT_NODE) {
let elRange = doc.createRange(); let elRange = doc.createRange();
elRange.selectNodeContents(node); elRange.selectNodeContents(node);
elPos = elRange.getBoundingClientRect(); elPos = elRange.getBoundingClientRect();
@ -327,7 +372,6 @@ export function nodeBounds(node) {
* @memberof Core * @memberof Core
*/ */
export function windowBounds() { export function windowBounds() {
var width = window.innerWidth; var width = window.innerWidth;
var height = window.innerHeight; var height = window.innerHeight;
@ -337,9 +381,8 @@ export function windowBounds() {
right: width, right: width,
bottom: height, bottom: height,
width: width, width: width,
height: height height: height,
}; };
} }
/** /**
@ -402,8 +445,8 @@ export function isXml(ext) {
* @returns {Blob} * @returns {Blob}
* @memberof Core * @memberof Core
*/ */
export function createBlob(content, mime){ export function createBlob(content, mime) {
return new Blob([content], {type : mime }); return new Blob([content], { type: mime });
} }
/** /**
@ -413,7 +456,7 @@ export function createBlob(content, mime){
* @returns {string} url * @returns {string} url
* @memberof Core * @memberof Core
*/ */
export function createBlobUrl(content, mime){ export function createBlobUrl(content, mime) {
var tempUrl; var tempUrl;
var blob = createBlob(content, mime); var blob = createBlob(content, mime);
@ -427,7 +470,7 @@ export function createBlobUrl(content, mime){
* @param {string} url * @param {string} url
* @memberof Core * @memberof Core
*/ */
export function revokeBlobUrl(url){ export function revokeBlobUrl(url) {
return _URL.revokeObjectURL(url); return _URL.revokeObjectURL(url);
} }
@ -438,11 +481,11 @@ export function revokeBlobUrl(url){
* @returns {string} url * @returns {string} url
* @memberof Core * @memberof Core
*/ */
export function createBase64Url(content, mime){ export function createBase64Url(content, mime) {
var data; var data;
var datauri; var datauri;
if (typeof(content) !== "string") { if (typeof content !== "string") {
// Only handles strings // Only handles strings
return; return;
} }
@ -460,7 +503,7 @@ export function createBase64Url(content, mime){
* @returns {string} type * @returns {string} type
* @memberof Core * @memberof Core
*/ */
export function type(obj){ export function type(obj) {
return Object.prototype.toString.call(obj).slice(8, -1); return Object.prototype.toString.call(obj).slice(8, -1);
} }
@ -484,7 +527,7 @@ export function parse(markup, mime, forceXMLDom) {
// Remove byte order mark before parsing // Remove byte order mark before parsing
// https://www.w3.org/International/questions/qa-byte-order-mark // https://www.w3.org/International/questions/qa-byte-order-mark
if(markup.charCodeAt(0) === 0xFEFF) { if (markup.charCodeAt(0) === 0xfeff) {
markup = markup.slice(1); markup = markup.slice(1);
} }
@ -524,7 +567,6 @@ export function qs(el, sel) {
* @memberof Core * @memberof Core
*/ */
export function qsa(el, sel) { export function qsa(el, sel) {
if (typeof el.querySelector != "undefined") { if (typeof el.querySelector != "undefined") {
return el.querySelectorAll(sel); return el.querySelectorAll(sel);
} else { } else {
@ -551,9 +593,9 @@ export function qsp(el, sel, props) {
return el.querySelector(sel); return el.querySelector(sel);
} else { } else {
q = el.getElementsByTagName(sel); q = el.getElementsByTagName(sel);
filtered = Array.prototype.slice.call(q, 0).filter(function(el) { filtered = Array.prototype.slice.call(q, 0).filter(function (el) {
for (var prop in props) { for (var prop in props) {
if(el.getAttribute(prop) === props[prop]){ if (el.getAttribute(prop) === props[prop]) {
return true; return true;
} }
} }
@ -574,14 +616,19 @@ export function qsp(el, sel, props) {
*/ */
export function sprint(root, func) { export function sprint(root, func) {
var doc = root.ownerDocument || root; var doc = root.ownerDocument || root;
if (typeof(doc.createTreeWalker) !== "undefined") { if (typeof doc.createTreeWalker !== "undefined") {
treeWalker(root, func, NodeFilter.SHOW_TEXT); treeWalker(root, func, NodeFilter.SHOW_TEXT);
} else { } else {
walk(root, function(node) { walk(
if (node && node.nodeType === 3) { // Node.TEXT_NODE root,
function (node) {
if (node && node.nodeType === 3) {
// Node.TEXT_NODE
func(node); func(node);
} }
}, true); },
true
);
} }
} }
@ -605,19 +652,19 @@ export function treeWalker(root, func, filter) {
* @param {node} node * @param {node} node
* @param {callback} return false for continue,true for break inside callback * @param {callback} return false for continue,true for break inside callback
*/ */
export function walk(node,callback){ export function walk(node, callback) {
if(callback(node)){ if (callback(node)) {
return true; return true;
} }
node = node.firstChild; node = node.firstChild;
if(node){ if (node) {
do{ do {
let walked = walk(node,callback); let walked = walk(node, callback);
if(walked){ if (walked) {
return true; return true;
} }
node = node.nextSibling; node = node.nextSibling;
} while(node); } while (node);
} }
} }
@ -628,16 +675,15 @@ export function walk(node,callback){
* @memberof Core * @memberof Core
*/ */
export function blob2base64(blob) { export function blob2base64(blob) {
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
var reader = new FileReader(); var reader = new FileReader();
reader.readAsDataURL(blob); reader.readAsDataURL(blob);
reader.onloadend = function() { reader.onloadend = function () {
resolve(reader.result); resolve(reader.result);
}; };
}); });
} }
/** /**
* Creates a new pending promise and provides methods to resolve or reject it. * Creates a new pending promise and provides methods to resolve or reject it.
* From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible * From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible
@ -682,17 +728,20 @@ export function defer() {
* @returns {element[]} elements * @returns {element[]} elements
* @memberof Core * @memberof Core
*/ */
export function querySelectorByType(html, element, type){ export function querySelectorByType(html, element, type) {
var query; var query;
if (typeof html.querySelector != "undefined") { if (typeof html.querySelector != "undefined") {
query = html.querySelector(`${element}[*|type="${type}"]`); query = html.querySelector(`${element}[*|type="${type}"]`);
} }
// Handle IE not supporting namespaced epub:type in querySelector // Handle IE not supporting namespaced epub:type in querySelector
if(!query || query.length === 0) { if (!query || query.length === 0) {
query = qsa(html, element); query = qsa(html, element);
for (var i = 0; i < query.length; i++) { for (var i = 0; i < query.length; i++) {
if(query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type || if (
query[i].getAttribute("epub:type") === type) { query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") ===
type ||
query[i].getAttribute("epub:type") === type
) {
return query[i]; return query[i];
} }
} }
@ -730,7 +779,7 @@ export function parents(node) {
for (; node; node = node.parentNode) { for (; node; node = node.parentNode) {
nodes.unshift(node); nodes.unshift(node);
} }
return nodes return nodes;
} }
/** /**
@ -768,7 +817,7 @@ export function filterChildren(el, nodeName, single) {
*/ */
export function getParentByTagName(node, tagname) { export function getParentByTagName(node, tagname) {
let parent; let parent;
if (node === null || tagname === '') return; if (node === null || tagname === "") return;
parent = node.parentNode; parent = node.parentNode;
while (parent.nodeType === 1) { while (parent.nodeType === 1) {
if (parent.tagName.toLowerCase() === tagname) { if (parent.tagName.toLowerCase() === tagname) {
@ -841,9 +890,10 @@ export class RangeObject {
} }
selectNodeContents(referenceNode) { selectNodeContents(referenceNode) {
let end = referenceNode.childNodes[referenceNode.childNodes - 1]; let endIndex =
let endIndex = (referenceNode.nodeType === 3) ? referenceNode.nodeType === 3
referenceNode.textContent.length : parent.childNodes.length; ? referenceNode.textContent.length
: parent.childNodes.length;
this.setStart(referenceNode, 0); this.setStart(referenceNode, 0);
this.setEnd(referenceNode, endIndex); this.setEnd(referenceNode, endIndex);
} }
@ -862,8 +912,10 @@ export class RangeObject {
} }
_checkCollapsed() { _checkCollapsed() {
if (this.startContainer === this.endContainer && if (
this.startOffset === this.endOffset) { this.startContainer === this.endContainer &&
this.startOffset === this.endOffset
) {
this.collapsed = true; this.collapsed = true;
} else { } else {
this.collapsed = false; this.collapsed = false;

View file

@ -6,7 +6,7 @@
* @example this.content = new EPUBJS.Hook(this); * @example this.content = new EPUBJS.Hook(this);
*/ */
class Hook { class Hook {
constructor(context){ constructor(context) {
this.context = context || this; this.context = context || this;
this.hooks = []; this.hooks = [];
} }
@ -15,13 +15,13 @@ class Hook {
* 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(){...}); * @example this.content.register(function(){...});
*/ */
register(){ register() {
for(var i = 0; i < arguments.length; ++i) { for (var i = 0; i < arguments.length; ++i) {
if (typeof arguments[i] === "function") { if (typeof arguments[i] === "function") {
this.hooks.push(arguments[i]); this.hooks.push(arguments[i]);
} else { } else {
// unpack array // unpack array
for(var j = 0; j < arguments[i].length; ++j) { for (var j = 0; j < arguments[i].length; ++j) {
this.hooks.push(arguments[i][j]); this.hooks.push(arguments[i][j]);
} }
} }
@ -32,7 +32,7 @@ class Hook {
* Removes a function * Removes a function
* @example this.content.deregister(function(){...}); * @example this.content.deregister(function(){...});
*/ */
deregister(func){ deregister(func) {
let hook; let hook;
for (let i = 0; i < this.hooks.length; i++) { for (let i = 0; i < this.hooks.length; i++) {
hook = this.hooks[i]; hook = this.hooks[i];
@ -47,36 +47,35 @@ class Hook {
* Triggers a hook to run all functions * Triggers a hook to run all functions
* @example this.content.trigger(args).then(function(){...}); * @example this.content.trigger(args).then(function(){...});
*/ */
trigger(){ trigger() {
var args = arguments; var args = arguments;
var context = this.context; var context = this.context;
var promises = []; var promises = [];
this.hooks.forEach(function(task) { this.hooks.forEach(function (task) {
try { try {
var executing = task.apply(context, args); var executing = task.apply(context, args);
} catch (err) { } catch (err) {
console.log(err); console.error(err);
} }
if(executing && typeof executing["then"] === "function") { if (executing && typeof executing["then"] === "function") {
// Task is a function that returns a promise // Task is a function that returns a promise
promises.push(executing); promises.push(executing);
} }
// Otherwise Task resolves immediately, continue // Otherwise Task resolves immediately, continue
}); });
return Promise.all(promises); return Promise.all(promises);
} }
// Adds a function to be run before a hook completes // Adds a function to be run before a hook completes
list(){ list() {
return this.hooks; return this.hooks;
} }
clear(){ clear() {
return this.hooks = []; return (this.hooks = []);
} }
} }
export default Hook; export default Hook;

View file

@ -4,143 +4,147 @@ edited down
*/ */
var table = { var table = {
"application" : { application: {
"ecmascript" : [ "es", "ecma" ], ecmascript: ["es", "ecma"],
"javascript" : "js", javascript: "js",
"ogg" : "ogx", ogg: "ogx",
"pdf" : "pdf", pdf: "pdf",
"postscript" : [ "ps", "ai", "eps", "epsi", "epsf", "eps2", "eps3" ], postscript: ["ps", "ai", "eps", "epsi", "epsf", "eps2", "eps3"],
"rdf+xml" : "rdf", "rdf+xml": "rdf",
"smil" : [ "smi", "smil" ], smil: ["smi", "smil"],
"xhtml+xml" : [ "xhtml", "xht" ], "xhtml+xml": ["xhtml", "xht"],
"xml" : [ "xml", "xsl", "xsd", "opf", "ncx" ], xml: ["xml", "xsl", "xsd", "opf", "ncx"],
"zip" : "zip", zip: "zip",
"x-httpd-eruby" : "rhtml", "x-httpd-eruby": "rhtml",
"x-latex" : "latex", "x-latex": "latex",
"x-maker" : [ "frm", "maker", "frame", "fm", "fb", "book", "fbdoc" ], "x-maker": ["frm", "maker", "frame", "fm", "fb", "book", "fbdoc"],
"x-object" : "o", "x-object": "o",
"x-shockwave-flash" : [ "swf", "swfl" ], "x-shockwave-flash": ["swf", "swfl"],
"x-silverlight" : "scr", "x-silverlight": "scr",
"epub+zip" : "epub", "epub+zip": "epub",
"font-tdpfr" : "pfr", "font-tdpfr": "pfr",
"inkml+xml" : [ "ink", "inkml" ], "inkml+xml": ["ink", "inkml"],
"json" : "json", json: "json",
"jsonml+json" : "jsonml", "jsonml+json": "jsonml",
"mathml+xml" : "mathml", "mathml+xml": "mathml",
"metalink+xml" : "metalink", "metalink+xml": "metalink",
"mp4" : "mp4s", mp4: "mp4s",
// "oebps-package+xml" : "opf", // "oebps-package+xml" : "opf",
"omdoc+xml" : "omdoc", "omdoc+xml": "omdoc",
"oxps" : "oxps", oxps: "oxps",
"vnd.amazon.ebook" : "azw", "vnd.amazon.ebook": "azw",
"widget" : "wgt", widget: "wgt",
// "x-dtbncx+xml" : "ncx", // "x-dtbncx+xml" : "ncx",
"x-dtbook+xml" : "dtb", "x-dtbook+xml": "dtb",
"x-dtbresource+xml" : "res", "x-dtbresource+xml": "res",
"x-font-bdf" : "bdf", "x-font-bdf": "bdf",
"x-font-ghostscript" : "gsf", "x-font-ghostscript": "gsf",
"x-font-linux-psf" : "psf", "x-font-linux-psf": "psf",
"x-font-otf" : "otf", "x-font-otf": "otf",
"x-font-pcf" : "pcf", "x-font-pcf": "pcf",
"x-font-snf" : "snf", "x-font-snf": "snf",
"x-font-ttf" : [ "ttf", "ttc" ], "x-font-ttf": ["ttf", "ttc"],
"x-font-type1" : [ "pfa", "pfb", "pfm", "afm" ], "x-font-type1": ["pfa", "pfb", "pfm", "afm"],
"x-font-woff" : "woff", "x-font-woff": "woff",
"x-mobipocket-ebook" : [ "prc", "mobi" ], "x-mobipocket-ebook": ["prc", "mobi"],
"x-mspublisher" : "pub", "x-mspublisher": "pub",
"x-nzb" : "nzb", "x-nzb": "nzb",
"x-tgif" : "obj", "x-tgif": "obj",
"xaml+xml" : "xaml", "xaml+xml": "xaml",
"xml-dtd" : "dtd", "xml-dtd": "dtd",
"xproc+xml" : "xpl", "xproc+xml": "xpl",
"xslt+xml" : "xslt", "xslt+xml": "xslt",
"internet-property-stream" : "acx", "internet-property-stream": "acx",
"x-compress" : "z", "x-compress": "z",
"x-compressed" : "tgz", "x-compressed": "tgz",
"x-gzip" : "gz", "x-gzip": "gz",
}, },
"audio" : { audio: {
"flac" : "flac", flac: "flac",
"midi" : [ "mid", "midi", "kar", "rmi" ], midi: ["mid", "midi", "kar", "rmi"],
"mpeg" : [ "mpga", "mpega", "mp2", "mp3", "m4a", "mp2a", "m2a", "m3a" ], mpeg: ["mpga", "mpega", "mp2", "mp3", "m4a", "mp2a", "m2a", "m3a"],
"mpegurl" : "m3u", mpegurl: "m3u",
"ogg" : [ "oga", "ogg", "spx" ], ogg: ["oga", "ogg", "spx"],
"x-aiff" : [ "aif", "aiff", "aifc" ], "x-aiff": ["aif", "aiff", "aifc"],
"x-ms-wma" : "wma", "x-ms-wma": "wma",
"x-wav" : "wav", "x-wav": "wav",
"adpcm" : "adp", adpcm: "adp",
"mp4" : "mp4a", mp4: "mp4a",
"webm" : "weba", webm: "weba",
"x-aac" : "aac", "x-aac": "aac",
"x-caf" : "caf", "x-caf": "caf",
"x-matroska" : "mka", "x-matroska": "mka",
"x-pn-realaudio-plugin" : "rmp", "x-pn-realaudio-plugin": "rmp",
"xm" : "xm", xm: "xm",
"mid" : [ "mid", "rmi" ] mid: ["mid", "rmi"],
}, },
"image" : { image: {
"gif" : "gif", gif: "gif",
"ief" : "ief", ief: "ief",
"jpeg" : [ "jpeg", "jpg", "jpe" ], jpeg: ["jpeg", "jpg", "jpe"],
"pcx" : "pcx", pcx: "pcx",
"png" : "png", png: "png",
"svg+xml" : [ "svg", "svgz" ], "svg+xml": ["svg", "svgz"],
"tiff" : [ "tiff", "tif" ], tiff: ["tiff", "tif"],
"x-icon" : "ico", "x-icon": "ico",
"bmp" : "bmp", bmp: "bmp",
"webp" : "webp", webp: "webp",
"x-pict" : [ "pic", "pct" ], "x-pict": ["pic", "pct"],
"x-tga" : "tga", "x-tga": "tga",
"cis-cod" : "cod" "cis-cod": "cod",
}, },
"text" : { text: {
"cache-manifest" : [ "manifest", "appcache" ], "cache-manifest": ["manifest", "appcache"],
"css" : "css", css: "css",
"csv" : "csv", csv: "csv",
"html" : [ "html", "htm", "shtml", "stm" ], html: ["html", "htm", "shtml", "stm"],
"mathml" : "mml", mathml: "mml",
"plain" : [ "txt", "text", "brf", "conf", "def", "list", "log", "in", "bas" ], plain: ["txt", "text", "brf", "conf", "def", "list", "log", "in", "bas"],
"richtext" : "rtx", richtext: "rtx",
"tab-separated-values" : "tsv", "tab-separated-values": "tsv",
"x-bibtex" : "bib" "x-bibtex": "bib",
},
video: {
mpeg: ["mpeg", "mpg", "mpe", "m1v", "m2v", "mp2", "mpa", "mpv2"],
mp4: ["mp4", "mp4v", "mpg4"],
quicktime: ["qt", "mov"],
ogg: "ogv",
"vnd.mpegurl": ["mxu", "m4u"],
"x-flv": "flv",
"x-la-asf": ["lsf", "lsx"],
"x-mng": "mng",
"x-ms-asf": ["asf", "asx", "asr"],
"x-ms-wm": "wm",
"x-ms-wmv": "wmv",
"x-ms-wmx": "wmx",
"x-ms-wvx": "wvx",
"x-msvideo": "avi",
"x-sgi-movie": "movie",
"x-matroska": ["mpv", "mkv", "mk3d", "mks"],
"3gpp2": "3g2",
h261: "h261",
h263: "h263",
h264: "h264",
jpeg: "jpgv",
jpm: ["jpm", "jpgm"],
mj2: ["mj2", "mjp2"],
"vnd.ms-playready.media.pyv": "pyv",
"vnd.uvvu.mp4": ["uvu", "uvvu"],
"vnd.vivo": "viv",
webm: "webm",
"x-f4v": "f4v",
"x-m4v": "m4v",
"x-ms-vob": "vob",
"x-smv": "smv",
}, },
"video" : {
"mpeg" : [ "mpeg", "mpg", "mpe", "m1v", "m2v", "mp2", "mpa", "mpv2" ],
"mp4" : [ "mp4", "mp4v", "mpg4" ],
"quicktime" : [ "qt", "mov" ],
"ogg" : "ogv",
"vnd.mpegurl" : [ "mxu", "m4u" ],
"x-flv" : "flv",
"x-la-asf" : [ "lsf", "lsx" ],
"x-mng" : "mng",
"x-ms-asf" : [ "asf", "asx", "asr" ],
"x-ms-wm" : "wm",
"x-ms-wmv" : "wmv",
"x-ms-wmx" : "wmx",
"x-ms-wvx" : "wvx",
"x-msvideo" : "avi",
"x-sgi-movie" : "movie",
"x-matroska" : [ "mpv", "mkv", "mk3d", "mks" ],
"3gpp2" : "3g2",
"h261" : "h261",
"h263" : "h263",
"h264" : "h264",
"jpeg" : "jpgv",
"jpm" : [ "jpm", "jpgm" ],
"mj2" : [ "mj2", "mjp2" ],
"vnd.ms-playready.media.pyv" : "pyv",
"vnd.uvvu.mp4" : [ "uvu", "uvvu" ],
"vnd.vivo" : "viv",
"webm" : "webm",
"x-f4v" : "f4v",
"x-m4v" : "m4v",
"x-ms-vob" : "vob",
"x-smv" : "smv"
}
}; };
var mimeTypes = (function() { var mimeTypes = (function () {
var type, subtype, val, index, mimeTypes = {}; var type,
subtype,
val,
index,
mimeTypes = {};
for (type in table) { for (type in table) {
if (table.hasOwnProperty(type)) { if (table.hasOwnProperty(type)) {
for (subtype in table[type]) { for (subtype in table[type]) {
@ -160,10 +164,13 @@ var mimeTypes = (function() {
return mimeTypes; return mimeTypes;
})(); })();
var defaultValue = "text/plain";//"application/octet-stream"; var defaultValue = "text/plain"; //"application/octet-stream";
function lookup(filename) { function lookup(filename) {
return filename && mimeTypes[filename.split(".").pop().toLowerCase()] || defaultValue; return (
}; (filename && mimeTypes[filename.split(".").pop().toLowerCase()]) ||
defaultValue
);
}
export default { lookup }; export default { lookup };

View file

@ -29,7 +29,6 @@ class Path {
this.filename = parsed.base; this.filename = parsed.base;
this.extension = parsed.ext.slice(1); this.extension = parsed.ext.slice(1);
} }
/** /**
@ -37,7 +36,7 @@ class Path {
* @param {string} what * @param {string} what
* @returns {object} * @returns {object}
*/ */
parse (what) { parse(what) {
return path.parse(what); return path.parse(what);
} }
@ -45,7 +44,7 @@ class Path {
* @param {string} what * @param {string} what
* @returns {boolean} * @returns {boolean}
*/ */
isAbsolute (what) { isAbsolute(what) {
return path.isAbsolute(what || this.path); return path.isAbsolute(what || this.path);
} }
@ -54,8 +53,8 @@ class Path {
* @param {string} what * @param {string} what
* @returns {boolean} * @returns {boolean}
*/ */
isDirectory (what) { isDirectory(what) {
return (what.charAt(what.length-1) === "/"); return what.charAt(what.length - 1) === "/";
} }
/** /**
@ -65,7 +64,7 @@ class Path {
* @param {string} what * @param {string} what
* @returns {string} resolved * @returns {string} resolved
*/ */
resolve (what) { resolve(what) {
return path.resolve(this.directory, what); return path.resolve(this.directory, what);
} }
@ -76,8 +75,8 @@ class Path {
* @param {string} what * @param {string} what
* @returns {string} relative * @returns {string} relative
*/ */
relative (what) { relative(what) {
var isAbsolute = what && (what.indexOf("://") > -1); var isAbsolute = what && what.indexOf("://") > -1;
if (isAbsolute) { if (isAbsolute) {
return what; return what;
@ -94,7 +93,7 @@ class Path {
* Return the path string * Return the path string
* @returns {string} path * @returns {string} path
*/ */
toString () { toString() {
return this.path; return this.path;
} }
} }

View file

@ -1,4 +1,4 @@
import {defer, requestAnimationFrame} from "./core"; import { defer, requestAnimationFrame } from "./core";
/** /**
* Queue for handling tasks one at a time * Queue for handling tasks one at a time
@ -6,7 +6,7 @@ import {defer, requestAnimationFrame} from "./core";
* @param {scope} context what this will resolve to in the tasks * @param {scope} context what this will resolve to in the tasks
*/ */
class Queue { class Queue {
constructor(context){ constructor(context) {
this._q = []; this._q = [];
this.context = context; this.context = context;
this.tick = requestAnimationFrame; this.tick = requestAnimationFrame;
@ -28,29 +28,26 @@ class Queue {
// if(args && !Array.isArray(args)) { // if(args && !Array.isArray(args)) {
// args = [args]; // args = [args];
// } // }
if(!task) { if (!task) {
throw new Error("No Task Provided"); throw new Error("No Task Provided");
} }
if(typeof task === "function"){ if (typeof task === "function") {
deferred = new defer(); deferred = new defer();
promise = deferred.promise; promise = deferred.promise;
queued = { queued = {
"task" : task, task: task,
"args" : args, args: args,
//"context" : context, //"context" : context,
"deferred" : deferred, deferred: deferred,
"promise" : promise promise: promise,
}; };
} else { } else {
// Task is a promise // Task is a promise
queued = { queued = {
"promise" : task promise: task,
}; };
} }
this._q.push(queued); this._q.push(queued);
@ -69,48 +66,46 @@ class Queue {
* Run one item * Run one item
* @return {Promise} * @return {Promise}
*/ */
dequeue(){ dequeue() {
var inwait, task, result; var inwait, task, result;
if(this._q.length && !this.paused) { if (this._q.length && !this.paused) {
inwait = this._q.shift(); inwait = this._q.shift();
task = inwait.task; task = inwait.task;
if(task){ if (task) {
// console.log(task) // console.log(task)
result = task.apply(this.context, inwait.args); result = task.apply(this.context, inwait.args);
if(result && typeof result["then"] === "function") { if (result && typeof result["then"] === "function") {
// Task is a function that returns a promise // Task is a function that returns a promise
return result.then(function(){ return result.then(
function () {
inwait.deferred.resolve.apply(this.context, arguments); inwait.deferred.resolve.apply(this.context, arguments);
}.bind(this), function() { }.bind(this),
function () {
inwait.deferred.reject.apply(this.context, arguments); inwait.deferred.reject.apply(this.context, arguments);
}.bind(this)); }.bind(this)
);
} else { } else {
// Task resolves immediately // Task resolves immediately
inwait.deferred.resolve.apply(this.context, result); inwait.deferred.resolve.apply(this.context, result);
return inwait.promise; return inwait.promise;
} }
} else if (inwait.promise) {
} else if(inwait.promise) {
// Task is a promise // Task is a promise
return inwait.promise; return inwait.promise;
} }
} else { } else {
inwait = new defer(); inwait = new defer();
inwait.deferred.resolve(); inwait.deferred.resolve();
return inwait.promise; return inwait.promise;
} }
} }
// Run All Immediately // Run All Immediately
dump(){ dump() {
while(this._q.length) { while (this._q.length) {
this.dequeue(); this.dequeue();
} }
} }
@ -119,31 +114,27 @@ class Queue {
* Run all tasks sequentially, at convince * Run all tasks sequentially, at convince
* @return {Promise} * @return {Promise}
*/ */
run(){ run() {
if (!this.running) {
if(!this.running){
this.running = true; this.running = true;
this.defered = new defer(); this.defered = new defer();
} }
this.tick.call(window, () => { this.tick.call(window, () => {
if (this._q.length) {
if(this._q.length) { this.dequeue().then(
function () {
this.dequeue()
.then(function(){
this.run(); this.run();
}.bind(this)); }.bind(this)
);
} else { } else {
this.defered.resolve(); this.defered.resolve();
this.running = undefined; this.running = undefined;
} }
}); });
// Unpause // Unpause
if(this.paused == true) { if (this.paused == true) {
this.paused = false; this.paused = false;
} }
@ -154,28 +145,27 @@ class Queue {
* Flush all, as quickly as possible * Flush all, as quickly as possible
* @return {Promise} * @return {Promise}
*/ */
flush(){ flush() {
if (this.running) {
if(this.running){
return this.running; return this.running;
} }
if(this._q.length) { if (this._q.length) {
this.running = this.dequeue() this.running = this.dequeue().then(
.then(function(){ function () {
this.running = undefined; this.running = undefined;
return this.flush(); return this.flush();
}.bind(this)); }.bind(this)
);
return this.running; return this.running;
} }
} }
/** /**
* Clear all items in wait * Clear all items in wait
*/ */
clear(){ clear() {
this._q = []; this._q = [];
} }
@ -183,28 +173,27 @@ class Queue {
* Get the number of tasks in the queue * Get the number of tasks in the queue
* @return {number} tasks * @return {number} tasks
*/ */
length(){ length() {
return this._q.length; return this._q.length;
} }
/** /**
* Pause a running queue * Pause a running queue
*/ */
pause(){ pause() {
this.paused = true; this.paused = true;
} }
/** /**
* End the queue * End the queue
*/ */
stop(){ stop() {
this._q = []; this._q = [];
this.running = false; this.running = false;
this.paused = true; this.paused = true;
} }
} }
/** /**
* Create a new task from a callback * Create a new task from a callback
* @class * @class
@ -215,13 +204,12 @@ class Queue {
* @return {function} task * @return {function} task
*/ */
class Task { class Task {
constructor(task, args, context){ constructor(task, args, context) {
return function () {
return function(){
var toApply = arguments || []; var toApply = arguments || [];
return new Promise( (resolve, reject) => { return new Promise((resolve, reject) => {
var callback = function(value, err){ var callback = function (value, err) {
if (!value && err) { if (!value && err) {
reject(err); reject(err);
} else { } else {
@ -233,14 +221,10 @@ class Task {
// Apply all arguments to the functions // Apply all arguments to the functions
task.apply(context || this, toApply); task.apply(context || this, toApply);
}); });
}; };
} }
} }
export default Queue; export default Queue;
export { Task }; export { Task };

View file

@ -1,21 +1,20 @@
import { qs, qsa } from "./core"; import { qs } from "./core";
import Url from "./url"; import Url from "./url";
import Path from "./path";
export function replaceBase(doc, section){ export function replaceBase(doc, section) {
var base; var base;
var head; var head;
var url = section.url; var url = section.url;
var absolute = (url.indexOf("://") > -1); var absolute = url.indexOf("://") > -1;
if(!doc){ if (!doc) {
return; return;
} }
head = qs(doc, "head"); head = qs(doc, "head");
base = qs(head, "base"); base = qs(head, "base");
if(!base) { if (!base) {
base = doc.createElement("base"); base = doc.createElement("base");
head.insertBefore(base, head.firstChild); head.insertBefore(base, head.firstChild);
} }
@ -28,12 +27,12 @@ export function replaceBase(doc, section){
base.setAttribute("href", url); base.setAttribute("href", url);
} }
export function replaceCanonical(doc, section){ export function replaceCanonical(doc, section) {
var head; var head;
var link; var link;
var url = section.canonical; var url = section.canonical;
if(!doc){ if (!doc) {
return; return;
} }
@ -50,11 +49,11 @@ export function replaceCanonical(doc, section){
} }
} }
export function replaceMeta(doc, section){ export function replaceMeta(doc, section) {
var head; var head;
var meta; var meta;
var id = section.idref; var id = section.idref;
if(!doc){ if (!doc) {
return; return;
} }
@ -73,7 +72,6 @@ export function replaceMeta(doc, section){
// TODO: move me to Contents // TODO: move me to Contents
export function replaceLinks(contents, fn) { export function replaceLinks(contents, fn) {
var links = contents.querySelectorAll("a[href]"); var links = contents.querySelectorAll("a[href]");
if (!links.length) { if (!links.length) {
@ -82,32 +80,29 @@ export function replaceLinks(contents, fn) {
var base = qs(contents.ownerDocument, "base"); var base = qs(contents.ownerDocument, "base");
var location = base ? base.getAttribute("href") : undefined; var location = base ? base.getAttribute("href") : undefined;
var replaceLink = function(link){ var replaceLink = function (link) {
var href = link.getAttribute("href"); var href = link.getAttribute("href");
if(href.indexOf("mailto:") === 0){ if (href.indexOf("mailto:") === 0) {
return; return;
} }
var absolute = (href.indexOf("://") > -1); var absolute = href.indexOf("://") > -1;
if(absolute){
if (absolute) {
link.setAttribute("target", "_blank"); link.setAttribute("target", "_blank");
} else {
}else{
var linkUrl; var linkUrl;
try { try {
linkUrl = new Url(href, location); linkUrl = new Url(href, location);
} catch(error) { } catch (error) {
// NOOP // NOOP
} }
link.onclick = function(){ link.onclick = function () {
if (linkUrl && linkUrl.hash) {
if(linkUrl && linkUrl.hash) {
fn(linkUrl.Path.path + linkUrl.hash); fn(linkUrl.Path.path + linkUrl.hash);
} else if(linkUrl){ } else if (linkUrl) {
fn(linkUrl.Path.path); fn(linkUrl.Path.path);
} else { } else {
fn(href); fn(href);
@ -121,12 +116,10 @@ export function replaceLinks(contents, fn) {
for (var i = 0; i < links.length; i++) { for (var i = 0; i < links.length; i++) {
replaceLink(links[i]); replaceLink(links[i]);
} }
} }
export function substitute(content, urls, replacements) { export function substitute(content, urls, replacements) {
urls.forEach(function(url, i){ urls.forEach(function (url, i) {
if (url && replacements[i]) { if (url && replacements[i]) {
// Account for special characters in the file name. // Account for special characters in the file name.
// See https://stackoverflow.com/a/6318729. // See https://stackoverflow.com/a/6318729.

View file

@ -1,8 +1,8 @@
import {defer, isXml, parse} from "./core"; import { defer, isXml, parse } from "./core";
import Path from "./path"; import Path from "./path";
function request(url, type, withCredentials, headers) { function request(url, type, withCredentials, headers) {
var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined var supportsURL = typeof window != "undefined" ? window.URL : false; // TODO: fallback for url if window isn't defined
var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer"; var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
var deferred = new defer(); var deferred = new defer();
@ -18,11 +18,11 @@ function request(url, type, withCredentials, headers) {
if (!("overrideMimeType" in xhrPrototype)) { if (!("overrideMimeType" in xhrPrototype)) {
// IE10 might have response, but not overrideMimeType // IE10 might have response, but not overrideMimeType
Object.defineProperty(xhrPrototype, "overrideMimeType", { Object.defineProperty(xhrPrototype, "overrideMimeType", {
value: function xmlHttpRequestOverrideMimeType() {} value: function xmlHttpRequestOverrideMimeType() {},
}); });
} }
if(withCredentials) { if (withCredentials) {
xhr.withCredentials = true; xhr.withCredentials = true;
} }
@ -31,38 +31,28 @@ function request(url, type, withCredentials, headers) {
xhr.open("GET", url, true); xhr.open("GET", url, true);
for(header in headers) { for (header in headers) {
xhr.setRequestHeader(header, headers[header]); xhr.setRequestHeader(header, headers[header]);
} }
if(type == "json") { if (type == "json") {
xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Accept", "application/json");
} }
// If type isn"t set, determine it from the file extension // If type isn"t set, determine it from the file extension
if(!type) { if (!type) {
type = new Path(url).extension; type = new Path(url).extension;
} }
if(type == "blob"){ if (type == "blob") {
xhr.responseType = BLOB_RESPONSE; xhr.responseType = BLOB_RESPONSE;
} }
if (isXml(type)) {
if(isXml(type)) {
// xhr.responseType = "document";
xhr.overrideMimeType("text/xml"); // for OPF parsing xhr.overrideMimeType("text/xml"); // for OPF parsing
} }
if(type == "xhtml") { if (type == "binary") {
// xhr.responseType = "document";
}
if(type == "html" || type == "htm") {
// xhr.responseType = "document";
}
if(type == "binary") {
xhr.responseType = "arraybuffer"; xhr.responseType = "arraybuffer";
} }
@ -76,18 +66,19 @@ function request(url, type, withCredentials, headers) {
if (this.readyState === XMLHttpRequest.DONE) { if (this.readyState === XMLHttpRequest.DONE) {
var responseXML = false; var responseXML = false;
if(this.responseType === "" || this.responseType === "document") { if (this.responseType === "" || this.responseType === "document") {
responseXML = this.responseXML; responseXML = this.responseXML;
} }
if (this.status === 200 || this.status === 0 || responseXML) { //-- Firefox is reporting 0 for blob urls if (this.status === 200 || this.status === 0 || responseXML) {
//-- Firefox is reporting 0 for blob urls
var r; var r;
if (!this.response && !responseXML) { if (!this.response && !responseXML) {
deferred.reject({ deferred.reject({
status: this.status, status: this.status,
message : "Empty Response", message: "Empty Response",
stack : new Error().stack stack: new Error().stack,
}); });
return deferred.promise; return deferred.promise;
} }
@ -96,50 +87,41 @@ function request(url, type, withCredentials, headers) {
deferred.reject({ deferred.reject({
status: this.status, status: this.status,
response: this.response, response: this.response,
message : "Forbidden", message: "Forbidden",
stack : new Error().stack stack: new Error().stack,
}); });
return deferred.promise; return deferred.promise;
} }
if(responseXML){ if (responseXML) {
r = this.responseXML; r = this.responseXML;
} else } else if (isXml(type)) {
if(isXml(type)){
// xhr.overrideMimeType("text/xml"); // for OPF parsing // xhr.overrideMimeType("text/xml"); // for OPF parsing
// If this.responseXML wasn't set, try to parse using a DOMParser from text // If this.responseXML wasn't set, try to parse using a DOMParser from text
r = parse(this.response, "text/xml"); r = parse(this.response, "text/xml");
}else } else if (type == "xhtml") {
if(type == "xhtml"){
r = parse(this.response, "application/xhtml+xml"); r = parse(this.response, "application/xhtml+xml");
}else } else if (type == "html" || type == "htm") {
if(type == "html" || type == "htm"){
r = parse(this.response, "text/html"); r = parse(this.response, "text/html");
}else } else if (type == "json") {
if(type == "json"){
r = JSON.parse(this.response); r = JSON.parse(this.response);
}else } else if (type == "blob") {
if(type == "blob"){ if (supportsURL) {
if(supportsURL) {
r = this.response; r = this.response;
} else { } else {
//-- Safari doesn't support responseType blob, so create a blob from arraybuffer //-- Safari doesn't support responseType blob, so create a blob from arraybuffer
r = new Blob([this.response]); r = new Blob([this.response]);
} }
} else {
}else{
r = this.response; r = this.response;
} }
deferred.resolve(r); deferred.resolve(r);
} else { } else {
deferred.reject({ deferred.reject({
status: this.status, status: this.status,
message : this.response, message: this.response,
stack : new Error().stack stack: new Error().stack,
}); });
} }
} }
} }

View file

@ -8,7 +8,7 @@ export default function scrollType() {
if (definer.scrollLeft > 0) { if (definer.scrollLeft > 0) {
type = "default"; type = "default";
} else { } else {
if (typeof Element !== 'undefined' && Element.prototype.scrollIntoView) { if (typeof Element !== "undefined" && Element.prototype.scrollIntoView) {
definer.children[0].children[1].scrollIntoView(); definer.children[0].children[1].scrollIntoView();
if (definer.scrollLeft < 0) { if (definer.scrollLeft < 0) {
type = "negative"; type = "negative";
@ -26,8 +26,8 @@ export default function scrollType() {
} }
export function createDefiner() { export function createDefiner() {
var definer = document.createElement('div'); var definer = document.createElement("div");
definer.dir="rtl"; definer.dir = "rtl";
definer.style.position = "fixed"; definer.style.position = "fixed";
definer.style.width = "1px"; definer.style.width = "1px";
@ -36,14 +36,14 @@ export function createDefiner() {
definer.style.left = "0px"; definer.style.left = "0px";
definer.style.overflow = "hidden"; definer.style.overflow = "hidden";
var innerDiv = document.createElement('div'); var innerDiv = document.createElement("div");
innerDiv.style.width = "2px"; innerDiv.style.width = "2px";
var spanA = document.createElement('span'); var spanA = document.createElement("span");
spanA.style.width = "1px"; spanA.style.width = "1px";
spanA.style.display = "inline-block"; spanA.style.display = "inline-block";
var spanB = document.createElement('span'); var spanB = document.createElement("span");
spanB.style.width = "1px"; spanB.style.width = "1px";
spanB.style.display = "inline-block"; spanB.style.display = "inline-block";

View file

@ -1,5 +1,5 @@
import Path from "./path";
import path from "path-webpack"; import path from "path-webpack";
import Path from "./path";
/** /**
* creates a Url object for parsing and manipulation of a url string * creates a Url object for parsing and manipulation of a url string
@ -9,7 +9,7 @@ import path from "path-webpack";
*/ */
class Url { class Url {
constructor(urlString, baseString) { constructor(urlString, baseString) {
var absolute = (urlString.indexOf("://") > -1); var absolute = urlString.indexOf("://") > -1;
var pathname = urlString; var pathname = urlString;
var basePath; var basePath;
@ -22,17 +22,21 @@ class Url {
this.search = ""; this.search = "";
this.base = baseString; this.base = baseString;
if (!absolute && if (
!absolute &&
baseString !== false && baseString !== false &&
typeof(baseString) !== "string" && typeof baseString !== "string" &&
window && window.location) { window &&
window.location
) {
this.base = window.location.href; this.base = window.location.href;
} }
// URL Polyfill doesn't throw an error if base is empty // URL Polyfill doesn't throw an error if base is empty
if (absolute || this.base) { if (absolute || this.base) {
try { try {
if (this.base) { // Safari doesn't like an undefined base if (this.base) {
// Safari doesn't like an undefined base
this.Url = new URL(urlString, this.base); this.Url = new URL(urlString, this.base);
} else { } else {
this.Url = new URL(urlString); this.Url = new URL(urlString);
@ -44,7 +48,7 @@ class Url {
this.hash = this.Url.hash; this.hash = this.Url.hash;
this.search = this.Url.search; this.search = this.Url.search;
pathname = this.Url.pathname + (this.Url.search ? this.Url.search : ''); pathname = this.Url.pathname + (this.Url.search ? this.Url.search : "");
} catch (e) { } catch (e) {
// Skip URL parsing // Skip URL parsing
this.Url = undefined; this.Url = undefined;
@ -61,13 +65,12 @@ class Url {
this.directory = this.Path.directory; this.directory = this.Path.directory;
this.filename = this.Path.filename; this.filename = this.Path.filename;
this.extension = this.Path.extension; this.extension = this.Path.extension;
} }
/** /**
* @returns {Path} * @returns {Path}
*/ */
path () { path() {
return this.Path; return this.Path;
} }
@ -76,8 +79,8 @@ class Url {
* @param {string} what * @param {string} what
* @returns {string} url * @returns {string} url
*/ */
resolve (what) { resolve(what) {
var isAbsolute = (what.indexOf("://") > -1); var isAbsolute = what.indexOf("://") > -1;
var fullpath; var fullpath;
if (isAbsolute) { if (isAbsolute) {
@ -93,14 +96,14 @@ class Url {
* @param {string} what * @param {string} what
* @returns {string} path * @returns {string} path
*/ */
relative (what) { relative(what) {
return path.relative(what, this.directory); return path.relative(what, this.directory);
} }
/** /**
* @returns {string} * @returns {string}
*/ */
toString () { toString() {
return this.href; return this.href;
} }
} }

View file

@ -1,371 +0,0 @@
var domain = window.location.origin;
module('Core');
test("EPUBJS.core.resolveUrl", 1, function() {
var a = "http://example.com/fred/chasen/";
var b = "/chasen/derf.html";
var resolved = EPUBJS.core.resolveUrl(a, b);
equal( resolved, "http://example.com/fred/chasen/derf.html", "resolved" );
});
test("EPUBJS.core.resolveUrl ../", 1, function() {
var a = "http://example.com/fred/chasen/";
var b = "../derf.html";
var resolved = EPUBJS.core.resolveUrl(a, b);
equal( resolved, "http://example.com/fred/derf.html", "resolved" );
});
test("EPUBJS.core.resolveUrl folders", 1, function() {
var a = "/fred/chasen/";
var b = "/fred/chasen/derf.html";
var resolved = EPUBJS.core.resolveUrl(a, b);
equal( resolved, "/fred/chasen/derf.html", "resolved" );
});
test("EPUBJS.core.resolveUrl ../folders", 1, function() {
var a = "/fred/chasen/";
var b = "../../derf.html";
var resolved = EPUBJS.core.resolveUrl(a, b);
equal( resolved, "/derf.html", "resolved" );
});
module('Create');
asyncTest("Create new ePub(/path/to/epub/)", 1, function() {
var book = ePub("../books/moby-dick/");
book.opened.then(function(){
equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" );
start();
});
});
asyncTest("Create new ePub(/path/to/epub/package.opf)", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.url, domain + "/books/moby-dick/OPS/", "bookPath is passed to new EPUBJS.Book" );
start();
});
});
asyncTest("Open using ePub(/path/to/epub/package.opf)", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" );
start();
});
});
asyncTest("Open Remote ePub", 1, function() {
var book = ePub("https://s3.amazonaws.com/moby-dick/");
book.opened.then(function(){
equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" );
start();
});
});
asyncTest("Open Remote ePub from Package", 1, function() {
var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" );
start();
});
});
asyncTest("Find Epub Package", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" );
start();
});
});
module('Parse');
//TODO: add mocked tests for parser
asyncTest("Manifest", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( Object.keys(book.package.manifest).length, 152, "Manifest is parsed" );
start();
});
});
asyncTest("Metadata", 3, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.package.metadata.creator, "Herman Melville", "Creator metadata is parsed" );
equal( book.package.metadata.title, "Moby-Dick", "Title metadata is parsed" );
equal( book.package.metadata.identifier, "code.google.com.epub-samples.moby-dick-basic", "Identifier metadata is parsed" );
start();
});
});
asyncTest("Spine", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.package.spine.length, 144, "Spine is parsed" );
start();
});
});
asyncTest("Cover", 1, function() {
var book = ePub("../books/moby-dick/");
book.opened.then(function(){
equal( book.cover, "../books/moby-dick/OPS/images/9780316000000.jpg", "Cover is set" );
start();
});
});
module('Spine');
asyncTest("Length", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.spine.length, 144, "All spine items present" );
start();
});
});
asyncTest("Items", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
equal( book.spine.spineItems.length, 144, "All spine items added" );
start();
});
});
asyncTest("First Item", 2, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var section = book.spine.get(0);
equal( section.href, "cover.xhtml", "First spine item href found" );
equal( section.cfiBase, "/6/2[cover]", "First spine item cfi found" );
start();
});
});
asyncTest("Find Item by Href", 2, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var section = book.spine.get("chapter_001.xhtml");
equal( section.href, "chapter_001.xhtml", "chap 1 spine item href found" );
equal( section.cfiBase, "/6/14[xchapter_001]", "chap 1 spine item cfi found" );
start();
});
});
asyncTest("Find Item by ID", 2, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var section = book.spine.get("#xchapter_050");
equal( section.href, "chapter_050.xhtml", "chap 50 spine item href found" );
equal( section.cfiBase, "/6/112[xchapter_050]", "chap 50 spine item cfi found" );
start();
});
});
asyncTest("Render Spine Item", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var section = book.spine.get("#xchapter_050");
section.render().then(function(content){
equal( content.substring(377, 429), "<h1>Chapter 50. Ahabs Boat and Crew. Fedallah.</h1>", "Chapter text rendered as string" );
});
start();
});
});
module('Navigation');
asyncTest("NCX & Nav", 2, function() {
var book = ePub("../books/moby-dick/");
book.opened.then(function(){
equal( book.navigation.navUrl, "../books/moby-dick/OPS/toc.xhtml", "Nav URL found" );
equal( book.navigation.ncxUrl, "../books/moby-dick/OPS/toc.ncx", "NCX URL found" );
start();
});
});
asyncTest("Load TOC Auto Pick", 1, function() {
var book = ePub("../books/moby-dick/");
book.opened.then(function(){
book.navigation.load().then(function(toc){
equal( toc.length, 141, "Full Nav toc parsed" );
start();
});
});
});
asyncTest("Load TOC from Nav", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var nav = book.navigation.nav.load();
nav.then(function(toc){
equal( toc.length, 141, "Full Nav toc parsed" );
start();
});
});
});
asyncTest("Load TOC from NCX", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.opened.then(function(){
var ncx = book.navigation.ncx.load();
ncx.then(function(toc){
equal( toc.length, 14, "Full NCX toc parsed" );
start();
});
});
});
asyncTest("Get all TOC", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.loaded.navigation.then(function(){
equal( book.navigation.get().length, 141, "Full Nav toc parsed" );
start();
});
});
asyncTest("Get TOC item by href", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.loaded.navigation.then(function(){
var item = book.navigation.get("chapter_001.xhtml");
equal( item.id, "toc-chapter_001", "Found TOC item" );
start();
});
});
asyncTest("Get TOC item by ID", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
book.loaded.navigation.then(function(){
var item = book.navigation.get("#toc-chapter_001");
equal( item.href, "chapter_001.xhtml", "Found TOC item" );
start();
});
});
module('Hooks');
asyncTest("Register a new hook", 1, function() {
var beforeDisplay = new EPUBJS.Hook();
beforeDisplay.register(function(args){
var defer = new RSVP.defer();
console.log("ran", 1);
defer.resolve();
return defer.promise;
});
equal( beforeDisplay.hooks.length, 1, "Registered a hook" );
start();
// this.beforeDisplay.trigger(args).then(function(){});
});
asyncTest("Trigger all new hook", 4, function() {
var beforeDisplay = new EPUBJS.Hook(this);
this.testerObject = {tester: 1};
beforeDisplay.register(function(testerObject){
var defer = new RSVP.defer();
start();
equal( testerObject.tester, 1, "tester is 1" );
stop();
testerObject.tester += 1;
defer.resolve();
return defer.promise;
});
beforeDisplay.register(function(testerObject){
var defer = new RSVP.defer();
start();
equal(testerObject.tester, 2, "tester is 2" );
stop();
testerObject.tester += 1;
defer.resolve();
return defer.promise;
});
start();
equal( beforeDisplay.hooks.length, 2, "Added two hooks" );
stop();
beforeDisplay.trigger(this.testerObject).then(function(){
start();
equal( this.testerObject.tester, 3, "tester is 3" );
}.bind(this));
});

View file

@ -1,16 +0,0 @@
module('Rendering');
/*
asyncTest("Render To", 1, function() {
var book = ePub("../books/moby-dick/OPS/package.opf");
var rendition = book.renderTo("qunit-fixture", {width:400, height:600});
var displayed = rendition.display(0);
displayed.then(function(){
equal( $( "iframe", "#qunit-fixture" ).length, 1, "iframe added successfully" );
start();
});
});
*/

View file

@ -1,53 +1,60 @@
import Rendition from "./rendition";
import View from "./managers/view"; import View from "./managers/view";
import Rendition from "./rendition";
export default class Annotations { export default class Annotations {
constructor(rendition: Rendition); constructor(rendition: Rendition);
add(type: string, cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): Annotation; add(
type: string,
cfiRange: string,
data?: object,
cb?: Function,
className?: string,
styles?: object
): Annotation;
remove(cfiRange: string, type: string): void; remove(cfiRange: string, type: string): void;
highlight(
highlight(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; cfiRange: string,
data?: object,
underline(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; 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; mark(cfiRange: string, data?: object, cb?: Function): void;
each(): Array<Annotation>;
each(): Array<Annotation> private _removeFromAnnotationBySectionIndex(
sectionIndex: number,
private _removeFromAnnotationBySectionIndex(sectionIndex: number, hash: string): void; hash: string
): void;
private _annotationsAt(index: number): void; private _annotationsAt(index: number): void;
private inject(view: View): void; private inject(view: View): void;
private clear(view: View): void; private clear(view: View): void;
} }
declare class Annotation { declare class Annotation {
constructor(options: { constructor(options: {
type: string, type: string;
cfiRange: string, cfiRange: string;
data?: object, data?: object;
sectionIndex?: number, sectionIndex?: number;
cb?: Function, cb?: Function;
className?: string, className?: string;
styles?: object styles?: object;
}); });
update(data: object): void; update(data: object): void;
attach(view: View): any; attach(view: View): any;
detach(view: View): any; detach(view: View): any;
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
} }

20
types/archive.d.ts vendored
View file

@ -1,27 +1,25 @@
import JSZip = require('jszip'); import JSZip = require("jszip");
export default class Archive { export default class Archive {
constructor(); constructor();
open(input: BinaryType, isBase64?: boolean): Promise<JSZip>; open(input: BinaryType, isBase64?: boolean): Promise<JSZip>;
openUrl(zipUrl: string, isBase64?: boolean): Promise<JSZip>; openUrl(zipUrl: string, isBase64?: boolean): Promise<JSZip>;
request(url: string, type?: string): Promise<Blob | string | JSON | Document | XMLDocument>; request(
url: string,
type?: string
): Promise<Blob | string | JSON | Document | XMLDocument>;
getBlob(url: string, mimeType?: string): Promise<Blob>; getBlob(url: string, mimeType?: string): Promise<Blob>;
getText(url: string): Promise<string>; getText(url: string): Promise<string>;
getBase64(url: string, mimeType?: string): Promise<string>; getBase64(url: string, mimeType?: string): Promise<string>;
createUrl(url: string, options: { base64: boolean }): Promise<string>; createUrl(url: string, options: { base64: boolean }): Promise<string>;
revokeUrl(url: string): void; revokeUrl(url: string): void;
destroy(): void; destroy(): void;
private checkRequirements(): void; private checkRequirements(): void;
private handleResponse(
private handleResponse(response: any, type?: string): Blob | string | JSON | Document | XMLDocument; response: any,
type?: string
): Blob | string | JSON | Document | XMLDocument;
} }

90
types/book.d.ts vendored
View file

@ -1,32 +1,34 @@
import { import Archive from "./archive";
import Container from "./container";
import Locations from "./locations";
import Navigation from "./navigation";
import Packaging, {
PackagingManifestObject, PackagingManifestObject,
PackagingMetadataObject, PackagingMetadataObject,
PackagingSpineItem,
PackagingObject
} from "./packaging"; } from "./packaging";
import PageList, { PageListItem } from "./pagelist";
import Rendition, { RenditionOptions } from "./rendition"; 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 Resources from "./resources";
import Container from "./container"; import Section, { SpineItem } from "./section";
import Packaging from "./packaging"; import Spine from "./spine";
import Store from "./store"; import Store from "./store";
import Path from "./utils/path";
import Url from "./utils/url";
export interface BookOptions { export interface BookOptions {
requestMethod?: (url: string, type: string, withCredentials: object, headers: object) => Promise<object>; requestMethod?: (
requestCredentials?: object, url: string,
requestHeaders?: object, type: string,
encoding?: string, withCredentials: object,
replacements?: string, headers: object
canonical?: (path: string) => string, ) => Promise<object>;
openAs?: string, requestCredentials?: object;
store?: string requestHeaders?: object;
encoding?: string;
replacements?: string;
canonical?: (path: string) => string;
openAs?: string;
store?: string;
} }
export default class Book { export default class Book {
@ -38,14 +40,14 @@ export default class Book {
opened: Promise<Book>; opened: Promise<Book>;
isOpen: boolean; isOpen: boolean;
loaded: { loaded: {
metadata: Promise<PackagingMetadataObject>, metadata: Promise<PackagingMetadataObject>;
spine: Promise<SpineItem[]>, spine: Promise<SpineItem[]>;
manifest: Promise<PackagingManifestObject>, manifest: Promise<PackagingManifestObject>;
cover: Promise<string>, cover: Promise<string>;
navigation: Promise<Navigation>, navigation: Promise<Navigation>;
pageList: Promise<PageListItem[]>, pageList: Promise<PageListItem[]>;
resources: Promise<string[]>, resources: Promise<string[]>;
} };
ready: Promise<void>; ready: Promise<void>;
request: Function; request: Function;
spine: Spine; spine: Spine;
@ -57,66 +59,40 @@ export default class Book {
archived: boolean; archived: boolean;
archive: Archive; archive: Archive;
resources: Resources; resources: Resources;
rendition: Rendition rendition: Rendition;
container: Container; container: Container;
packaging: Packaging; packaging: Packaging;
storage: Store; storage: Store;
canonical(path: string): string; canonical(path: string): string;
coverUrl(): Promise<string | null>; coverUrl(): Promise<string | null>;
destroy(): void; destroy(): void;
determineType(input: string): string; determineType(input: string): string;
getRange(cfiRange: string): Promise<Range>; getRange(cfiRange: string): Promise<Range>;
key(identifier?: string): string; key(identifier?: string): string;
load(path: string): Promise<object>; load(path: string): Promise<object>;
loadNavigation(opf: XMLDocument): Promise<Navigation>; loadNavigation(opf: XMLDocument): Promise<Navigation>;
open(input: string, what?: string): Promise<object>; open(input: string, what?: string): Promise<object>;
open(input: ArrayBuffer, what?: string): Promise<object>; open(input: ArrayBuffer, what?: string): Promise<object>;
openContainer(url: string): Promise<string>; openContainer(url: string): Promise<string>;
openEpub(data: BinaryType, encoding?: string): Promise<Book>; openEpub(data: BinaryType, encoding?: string): Promise<Book>;
openManifest(url: string): Promise<Book>; openManifest(url: string): Promise<Book>;
openPackaging(url: string): Promise<Book>; openPackaging(url: string): Promise<Book>;
renderTo(element: Element, options?: RenditionOptions): Rendition; renderTo(element: Element, options?: RenditionOptions): Rendition;
renderTo(element: string, options?: RenditionOptions): Rendition; renderTo(element: string, options?: RenditionOptions): Rendition;
private replacements(): Promise<void>;
resolve(path: string, absolute?: boolean): string; resolve(path: string, absolute?: boolean): string;
section(target: string): Section; section(target: string): Section;
section(target: number): Section; section(target: number): Section;
setRequestCredentials(credentials: object): void; setRequestCredentials(credentials: object): void;
setRequestHeaders(headers: object): void; setRequestHeaders(headers: object): void;
unarchive(input: BinaryType, encoding?: string): Promise<Archive>; unarchive(input: BinaryType, encoding?: string): Promise<Archive>;
store(name: string): Store; store(name: string): Store;
unpack(opf: XMLDocument): Promise<Book>; unpack(opf: XMLDocument): Promise<Book>;
private replacements(): Promise<void>;
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
} }

View file

@ -2,6 +2,5 @@ export default class Container {
constructor(containerDocument: Document); constructor(containerDocument: Document);
parse(containerDocument: Document): void; parse(containerDocument: Document): void;
destroy(): void; destroy(): void;
} }

100
types/contents.d.ts vendored
View file

@ -1,16 +1,21 @@
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
export interface ViewportSettings { export interface ViewportSettings {
width: string, width: string;
height: string, height: string;
scale: string, scale: string;
scalable: string, scalable: string;
minimum: string, minimum: string;
maximum: string maximum: string;
} }
export default class Contents { export default class Contents {
constructor(doc: Document, content: Element, cfiBase: string, sectionIndex: number); constructor(
doc: Document,
content: Element,
cfiBase: string,
sectionIndex: number
);
epubcfi: EpubCFI; epubcfi: EpubCFI;
document: Document; document: Document;
@ -23,117 +28,80 @@ export default class Contents {
static listenedEvents: string[]; static listenedEvents: string[];
addClass(className: string): void; addClass(className: string): void;
addScript(src: string): Promise<boolean>; addScript(src: string): Promise<boolean>;
addStylesheet(src: string): Promise<boolean>; addStylesheet(src: string): Promise<boolean>;
addStylesheetRules(
addStylesheetRules(rules: Array<object> | object, key: string): Promise<boolean>; rules: Array<object> | object,
key: string
): Promise<boolean>;
addStylesheetCss(serializedCss: string, key: string): Promise<boolean>; addStylesheetCss(serializedCss: string, key: string): Promise<boolean>;
cfiFromNode(node: Node, ignoreClass?: string): string; cfiFromNode(node: Node, ignoreClass?: string): string;
cfiFromRange(range: Range, ignoreClass?: string): string; cfiFromRange(range: Range, ignoreClass?: string): string;
columns(
columns(width: number, height: number, columnWidth: number, gap: number, dir: string): void; width: number,
height: number,
columnWidth: number,
gap: number,
dir: string
): void;
contentHeight(h: number): number; contentHeight(h: number): number;
contentWidth(w: number): number; contentWidth(w: number): number;
css(property: string, value: string, priority?: boolean): string; css(property: string, value: string, priority?: boolean): string;
destroy(): void; destroy(): void;
direction(dir: string): void; direction(dir: string): void;
fit(width: number, height: number): void; fit(width: number, height: number): void;
height(h: number): number; height(h: number): number;
locationOf(
locationOf(target: string | EpubCFI, ignoreClass?: string): Promise<{ top: number, left: number }>; target: string | EpubCFI,
ignoreClass?: string
): Promise<{ top: number; left: number }>;
map(layout: any): any; map(layout: any): any;
mapPage(
mapPage(cfiBase: string, layout: object, start: number, end: number, dev: boolean): any; cfiBase: string,
layout: object,
start: number,
end: number,
dev: boolean
): any;
overflow(overflow: string): string; overflow(overflow: string): string;
overflowX(overflow: string): string; overflowX(overflow: string): string;
overflowY(overflow: string): string; overflowY(overflow: string): string;
range(cfi: string, ignoreClass?: string): Range; range(cfi: string, ignoreClass?: string): Range;
removeClass(className: any): void; removeClass(className: any): void;
root(): Element; root(): Element;
scaler(scale: number, offsetX: number, offsetY: number): void; scaler(scale: number, offsetX: number, offsetY: number): void;
scrollHeight(): number; scrollHeight(): number;
scrollWidth(): number; scrollWidth(): number;
size(width: number, height: number): void; size(width: number, height: number): void;
textHeight(): number; textHeight(): number;
textWidth(): number; textWidth(): number;
viewport(options: ViewportSettings): ViewportSettings; viewport(options: ViewportSettings): ViewportSettings;
width(w: number): number; width(w: number): number;
writingMode(mode: string): string; writingMode(mode: string): string;
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
private addEventListeners(): void; private addEventListeners(): void;
private addSelectionListeners(): void; private addSelectionListeners(): void;
private epubReadingSystem(name: string, version: string): object; private epubReadingSystem(name: string, version: string): object;
private expand(): void; private expand(): void;
private fontLoadListeners(): void; private fontLoadListeners(): void;
private imageLoadListeners(): void; private imageLoadListeners(): void;
private layoutStyle(style: string): string; private layoutStyle(style: string): string;
private linksHandler(): void; private linksHandler(): void;
private listeners(): void; private listeners(): void;
private mediaQueryListeners(): void; private mediaQueryListeners(): void;
private onSelectionChange(e: Event): void; private onSelectionChange(e: Event): void;
private removeEventListeners(): void; private removeEventListeners(): void;
private removeListeners(): void; private removeListeners(): void;
private removeSelectionListeners(): void; private removeSelectionListeners(): void;
private resizeCheck(): void; private resizeCheck(): void;
private resizeListeners(): void; private resizeListeners(): void;
private resizeObservers(): void; private resizeObservers(): void;
private transitionListeners(): void; private transitionListeners(): void;
private triggerEvent(e: Event): void; private triggerEvent(e: Event): void;
private triggerSelectedEvent(selection: Selection): void; private triggerSelectedEvent(selection: Selection): void;
} }

116
types/core.d.ts vendored
View file

@ -1,83 +1,87 @@
export module Core { export module Core {
export function uuid(): string; export function uuid(): string;
export function documentHeight(): number; export function documentHeight(): number;
export function isElement(obj: object): boolean; export function isElement(obj: object): boolean;
export function isNumber(n: any): boolean; export function isNumber(n: any): boolean;
export function isFloat(n: any): boolean; export function isFloat(n: any): boolean;
export function prefixed(unprefixed: string): string; export function prefixed(unprefixed: string): string;
export function defaults(obj: object): object; export function defaults(obj: object): object;
export function extend(target: object): object; export function extend(target: object): object;
export function insert(
export function insert(item: any, array: Array<any>, compareFunction: Function): number; item: any,
array: Array<any>,
export function locationOf(item: any, array: Array<any>, compareFunction: Function, _start: Function, _end: Function): number; compareFunction: Function
): number;
export function indexOfSorted(item: any, array: Array<any>, compareFunction: Function, _start: Function, _end: Function): number; export function locationOf(
item: any,
export function bounds(el: Element): { width: Number, height: Number}; array: Array<any>,
compareFunction: Function,
export function borders(el: Element): { width: Number, height: Number}; _start: Function,
_end: Function
): number;
export function indexOfSorted(
item: any,
array: Array<any>,
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 nodeBounds(node: Node): object;
export function windowBounds(): {
export function windowBounds(): { width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }; width: Number;
height: Number;
top: Number;
left: Number;
right: Number;
bottom: Number;
};
export function indexOfNode(node: Node, typeId: string): number; export function indexOfNode(node: Node, typeId: string): number;
export function indexOfTextNode(textNode: Node): number; export function indexOfTextNode(textNode: Node): number;
export function indexOfElementNode(elementNode: Element): number; export function indexOfElementNode(elementNode: Element): number;
export function isXml(ext: string): boolean; export function isXml(ext: string): boolean;
export function createBlob(content: any, mime: string): Blob; export function createBlob(content: any, mime: string): Blob;
export function createBlobUrl(content: any, mime: string): string; export function createBlobUrl(content: any, mime: string): string;
export function revokeBlobUrl(url: string): void; export function revokeBlobUrl(url: string): void;
export function createBase64Url(content: any, mime: string): string;
export function createBase64Url(content: any, mime: string): string
export function type(obj: object): string; export function type(obj: object): string;
export function parse(
export function parse(markup: string, mime: string, forceXMLDom: boolean): Document; markup: string,
mime: string,
forceXMLDom: boolean
): Document;
export function qs(el: Element, sel: string): Element; export function qs(el: Element, sel: string): Element;
export function qsa(el: Element, sel: string): ArrayLike<Element>; export function qsa(el: Element, sel: string): ArrayLike<Element>;
export function qsp(
export function qsp(el: Element, sel: string, props: Array<object>): ArrayLike<Element>; el: Element,
sel: string,
props: Array<object>
): ArrayLike<Element>;
export function sprint(root: Node, func: Function): void; export function sprint(root: Node, func: Function): void;
export function treeWalker(
export function treeWalker(root: Node, func: Function, filter: object | Function): void; root: Node,
func: Function,
filter: object | Function
): void;
export function walk(node: Node, callback: Function): void; export function walk(node: Node, callback: Function): void;
export function blob2base64(blob: Blob): string; export function blob2base64(blob: Blob): string;
export function defer(): Promise<any>; export function defer(): Promise<any>;
export function querySelectorByType(
export function querySelectorByType(html: Element, element: string, type: string): Array<Element>; html: Element,
element: string,
type: string
): Array<Element>;
export function findChildren(el: Element): Array<Element>; export function findChildren(el: Element): Array<Element>;
export function parents(node: Element): Array<Element>; export function parents(node: Element): Array<Element>;
export function filterChildren(
export function filterChildren(el: Element, nodeName: string, single: boolean): Array<Element>; el: Element,
nodeName: string,
export function getParentByTagName(node: Element, tagname: string): Array<Element>; single: boolean
): Array<Element>;
export class RangeObject extends Range { export function getParentByTagName(
node: Element,
} tagname: string
): Array<Element>;
export class RangeObject extends Range {}
} }

7
types/epub.d.ts vendored
View file

@ -2,5 +2,8 @@ import Book, { BookOptions } from "./book";
export default Epub; export default Epub;
declare function Epub(urlOrData: string | ArrayBuffer, options?: BookOptions) : Book; declare function Epub(
declare function Epub(options?: BookOptions) : Book; urlOrData: string | ArrayBuffer,
options?: BookOptions
): Book;
declare function Epub(options?: BookOptions): Book;

105
types/epubcfi.d.ts vendored
View file

@ -1,97 +1,98 @@
interface EpubCFISegment { interface EpubCFISegment {
steps: Array<object>, steps: Array<object>;
terminal: { terminal: {
offset: number, offset: number;
assertion: string assertion: string;
} };
} }
interface EpubCFIStep { interface EpubCFIStep {
id: string, id: string;
tagName: string, tagName: string;
type: number, type: number;
index: number index: number;
} }
interface EpubCFIComponent { interface EpubCFIComponent {
steps: Array<EpubCFIStep>, steps: Array<EpubCFIStep>;
terminal: { terminal: {
offset: number, offset: number;
assertion: string assertion: string;
} };
} }
export default class EpubCFI { export default class EpubCFI {
constructor(cfiFrom?: string | Range | Node, base?: string | object, ignoreClass?: string); constructor(
cfiFrom?: string | Range | Node,
base?: string | object,
ignoreClass?: string
);
base: EpubCFIComponent; base: EpubCFIComponent;
spinePos: number; spinePos: number;
range: boolean; range: boolean;
isCfiString(str: string): boolean; isCfiString(str: string): boolean;
fromNode(anchor: Node, base: string | object, ignoreClass?: string): EpubCFI; fromNode(anchor: Node, base: string | object, ignoreClass?: string): EpubCFI;
fromRange(range: Range, base: string | object, ignoreClass?: string): EpubCFI; fromRange(range: Range, base: string | object, ignoreClass?: string): EpubCFI;
parse(cfiStr: string): EpubCFI; parse(cfiStr: string): EpubCFI;
collapse(toStart?: boolean): void; collapse(toStart?: boolean): void;
compare(cfiOne: string | EpubCFI, cfiTwo: string | EpubCFI): number; compare(cfiOne: string | EpubCFI, cfiTwo: string | EpubCFI): number;
equalStep(stepA: object, stepB: object): boolean; equalStep(stepA: object, stepB: object): boolean;
filter(anchor: Element, ignoreClass?: string): Element | false; filter(anchor: Element, ignoreClass?: string): Element | false;
toRange(_doc?: Document, ignoreClass?: string): Range; toRange(_doc?: Document, ignoreClass?: string): Range;
toString(): string; toString(): string;
private filteredStep(node: Node, ignoreClass?: string): any; private filteredStep(node: Node, ignoreClass?: string): any;
private findNode(
private findNode(steps: Array<EpubCFIStep>, _doc?: Document, ignoreClass?: string): Node; steps: Array<EpubCFIStep>,
_doc?: Document,
private fixMiss(steps: Array<EpubCFIStep>, offset: number, _doc?: Document, ignoreClass?: string): any; ignoreClass?: string
): Node;
private fixMiss(
steps: Array<EpubCFIStep>,
offset: number,
_doc?: Document,
ignoreClass?: string
): any;
private checkType(cfi: string | Range | Node): string | false; private checkType(cfi: string | Range | Node): string | false;
private generateChapterComponent(
private generateChapterComponent(_spineNodeIndex: number, _pos: number, id: string): string; _spineNodeIndex: number,
_pos: number,
id: string
): string;
private getChapterComponent(cfiStr: string): string; private getChapterComponent(cfiStr: string): string;
private getCharecterOffsetComponent(cfiStr: string): string; private getCharecterOffsetComponent(cfiStr: string): string;
private getPathComponent(cfiStr: string): string; private getPathComponent(cfiStr: string): string;
private getRange(cfiStr: string): string; private getRange(cfiStr: string): string;
private joinSteps(steps: Array<EpubCFIStep>): Array<EpubCFIStep>; private joinSteps(steps: Array<EpubCFIStep>): Array<EpubCFIStep>;
private normalizedMap(
private normalizedMap(children: Array<Node>, nodeType: number, ignoreClass?: string): object; children: Array<Node>,
nodeType: number,
ignoreClass?: string
): object;
private parseComponent(componentStr: string): object; private parseComponent(componentStr: string): object;
private parseStep(stepStr: string): object; private parseStep(stepStr: string): object;
private parseTerminal(termialStr: string): object; private parseTerminal(termialStr: string): object;
private patchOffset(
private patchOffset(anchor: Node, offset: number, ignoreClass?: string): number; anchor: Node,
offset: number,
private pathTo(node: Node, offset: number, ignoreClass?: string): EpubCFISegment; ignoreClass?: string
): number;
private pathTo(
node: Node,
offset: number,
ignoreClass?: string
): EpubCFISegment;
private position(anchor: Node): number; private position(anchor: Node): number;
private segmentString(segment: EpubCFISegment): string; private segmentString(segment: EpubCFISegment): string;
private step(node: Node): EpubCFIStep; private step(node: Node): EpubCFIStep;
private stepsToQuerySelector(steps: Array<EpubCFIStep>): string; private stepsToQuerySelector(steps: Array<EpubCFIStep>): string;
private stepsToXpath(steps: Array<EpubCFIStep>): string; private stepsToXpath(steps: Array<EpubCFIStep>): string;
private textNodes(container: Node, ignoreClass?: string): Array<Node>; private textNodes(container: Node, ignoreClass?: string): Array<Node>;
private walkToNode(
private walkToNode(steps: Array<EpubCFIStep>, _doc?: Document, ignoreClass?: string): Node; steps: Array<EpubCFIStep>,
_doc?: Document,
ignoreClass?: string
): Node;
} }

View file

@ -1,9 +0,0 @@
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();

16
types/index.d.ts vendored
View file

@ -8,13 +8,9 @@ export as namespace ePub;
export default Epub; export default Epub;
export { default as Book } from './book'; export { default as Book } from "./book";
export { default as EpubCFI } from './epubcfi'; export { default as Contents } from "./contents";
export { default as Rendition, Location } from './rendition'; export { default as EpubCFI } from "./epubcfi";
export { default as Contents } from './contents'; export { default as Layout } from "./layout";
export { default as Layout } from './layout'; export { NavItem } from "./navigation";
export { NavItem } from './navigation'; export { Location, default as Rendition } from "./rendition";
declare namespace ePub {
}

43
types/layout.d.ts vendored
View file

@ -1,10 +1,10 @@
import Contents from "./contents"; import Contents from "./contents";
interface LayoutSettings { interface LayoutSettings {
layout: string, layout: string;
spread: string, spread: string;
minSpreadWidth: number, minSpreadWidth: number;
evenSpreads: boolean evenSpreads: boolean;
} }
export default class Layout { export default class Layout {
@ -13,35 +13,30 @@ export default class Layout {
settings: LayoutSettings; settings: LayoutSettings;
name: string; name: string;
props: { props: {
name: string, name: string;
spread: string, spread: string;
flow: string, flow: string;
width: number, width: number;
height: number, height: number;
spreadWidth: number, spreadWidth: number;
delta: number, delta: number;
columnWidth: number, columnWidth: number;
gap: number, gap: number;
divisor: number divisor: number;
}; };
flow(flow: string): string; flow(flow: string): string;
spread(spread: string, min: number): boolean; spread(spread: string, min: number): boolean;
calculate(_width: number, _height: number, _gap?: number): void;
calculate(_width:number, _height:number, _gap?:number): void;
format(contents: Contents): void | Promise<void>; format(contents: Contents): void | Promise<void>;
count(
count(totalLength: number, pageLength: number): {spreads: Number, pages: Number}; totalLength: number,
pageLength: number
): { spreads: Number; pages: Number };
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
private update(props: object): void; private update(props: object): void;

26
types/locations.d.ts vendored
View file

@ -1,41 +1,29 @@
import Spine from "./spine";
import Section from "./section";
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
import Section from "./section";
import Spine from "./spine";
export default class Locations { export default class Locations {
constructor(spine: Spine, request?: Function, pause?: number); constructor(spine: Spine, request?: Function, pause?: number);
generate(chars: number): Promise<Array<string>>; generate(chars: number): Promise<Array<string>>;
process(section: Section): Promise<Array<string>>; process(section: Section): Promise<Array<string>>;
locationFromCfi(cfi: string | EpubCFI): Location; locationFromCfi(cfi: string | EpubCFI): Location;
percentageFromCfi(cfi: string | EpubCFI): number; percentageFromCfi(cfi: string | EpubCFI): number;
percentageFromLocation(loc: number): number; percentageFromLocation(loc: number): number;
cfiFromLocation(loc: number): string; cfiFromLocation(loc: number): string;
cfiFromPercentage(percentage: number): string; cfiFromPercentage(percentage: number): string;
load(locations: string): Array<string>; load(locations: string): Array<string>;
save(): string; save(): string;
currentLocation(): Location; currentLocation(): Location;
currentLocation(curr: string | number): void; currentLocation(curr: string | number): void;
length(): number; length(): number;
destroy(): void; destroy(): void;
private createRange(): { private createRange(): {
startContainer: Element, startContainer: Element;
startOffset: number, startOffset: number;
endContainer: Element, endContainer: Element;
endOffset: number endOffset: number;
}; };
private parse(contents: Node, cfiBase: string, chars: number): Array<string>;
private parse(contents: Node, cfiBase: string, chars: number) : Array<string>;
} }

View file

@ -1,90 +1,59 @@
import Section from "../section";
import Layout from "../layout";
import Contents from "../contents"; import Contents from "../contents";
import View, { ViewSettings } from "./view"; import Layout from "../layout";
import { EpubCFIPair } from "../mapping"; import { EpubCFIPair } from "../mapping";
import Section from "../section";
import View, { ViewSettings } from "./view";
export interface ViewLocation { export interface ViewLocation {
index: number, index: number;
href: string, href: string;
pages: number[], pages: number[];
totalPages: number, totalPages: number;
mapping: EpubCFIPair mapping: EpubCFIPair;
} }
export interface ManagerOptions extends ViewSettings { export interface ManagerOptions extends ViewSettings {
infinite?: boolean, infinite?: boolean;
overflow?: string, overflow?: string;
[key: string]: any [key: string]: any;
} }
export default class Manager { export default class Manager {
constructor(options: object); constructor(options: object);
render(element: Element, size?: { width: Number, height: Number }): void; applyLayout(layout: Layout): void;
bounds(): object;
resize(width: Number, height: Number): void;
onOrientationChange(e: Event): void;
private createView(section: Section): View;
display(section: Section, target: string | number): Promise<void>;
private afterDisplayed(view: View): void;
private afterResized(view: View): void;
private moveTo(offset: {top: Number, left: Number}): void;
private append(section: Section): Promise<void>;
private prepend(section: Section): Promise<void>;
next(): Promise<void>;
prev(): Promise<void>;
current(): View;
clear(): void; clear(): void;
current(): View;
currentLocation(): ViewLocation[]; currentLocation(): ViewLocation[];
destroy(): void;
direction(dir: string): void;
display(section: Section, target: string | number): Promise<void>;
getContents(): Contents[];
isRendered(): boolean;
next(): Promise<void>;
onOrientationChange(e: Event): void;
prev(): Promise<void>;
render(element: Element, size?: { width: Number; height: Number }): void;
resize(width: Number, height: Number): void;
setLayout(layout: Layout): void;
updateAxis(axis: string, forceUpdate: boolean): void;
updateFlow(flow: string): void;
updateLayout(): void;
visible(): View[]; visible(): View[];
private createView(section: Section): View;
private afterDisplayed(view: View): void;
private afterResized(view: View): void;
private moveTo(offset: { top: Number; left: Number }): void;
private append(section: Section): Promise<void>;
private prepend(section: Section): Promise<void>;
private scrollBy(x: number, y: number, silent: boolean): void; private scrollBy(x: number, y: number, silent: boolean): void;
private scrollTo(x: number, y: number, silent: boolean): void; private scrollTo(x: number, y: number, silent: boolean): void;
private onScroll(): 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 // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
} }

View file

@ -1,80 +1,65 @@
import Section from "../section";
import Contents from "../contents"; import Contents from "../contents";
import Layout from "../layout"; import Layout from "../layout";
import Section from "../section";
export interface ViewSettings { export interface ViewSettings {
ignoreClass?: string, ignoreClass?: string;
axis?: string, axis?: string;
flow?: string, flow?: string;
layout?: Layout, layout?: Layout;
method?: string, method?: string;
width?: number, width?: number;
height?: number, height?: number;
forceEvenPages?: boolean, forceEvenPages?: boolean;
allowScriptedContent?: boolean allowScriptedContent?: boolean;
} }
export default class View { export default class View {
constructor(section: Section, options: ViewSettings); constructor(section: Section, options: ViewSettings);
create(): any; create(): any;
render(request?: Function, show?: boolean): Promise<void>; render(request?: Function, show?: boolean): Promise<void>;
reset(): void; reset(): void;
size(_width: Number, _height: Number): void; size(_width: Number, _height: Number): void;
load(content: Contents): Promise<any>; load(content: Contents): Promise<any>;
setLayout(layout: Layout): void; setLayout(layout: Layout): void;
setAxis(axis: string): void; setAxis(axis: string): void;
display(request?: Function): Promise<any>; display(request?: Function): Promise<any>;
show(): void; show(): void;
hide(): void; hide(): void;
offset(): { top: Number; left: Number };
offset(): { top: Number, left: Number };
width(): Number; width(): Number;
height(): Number; height(): Number;
position(): object; position(): object;
locationOf(target: string): { top: Number; left: Number };
locationOf(target: string): { top: Number, left: Number };
onDisplayed(view: View): void; onDisplayed(view: View): void;
onResize(view: View): void; onResize(view: View): void;
bounds(force?: boolean): object; bounds(force?: boolean): object;
highlight(
cfiRange: string,
data?: object,
cb?: Function,
className?: string,
styles?: object
): void;
highlight(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; underline(
cfiRange: string,
underline(cfiRange: string, data?: object, cb?: Function, className?: string, styles?: object): void; data?: object,
cb?: Function,
className?: string,
styles?: object
): void;
mark(cfiRange: string, data?: object, cb?: Function): void; mark(cfiRange: string, data?: object, cb?: Function): void;
unhighlight(cfiRange: string): void; unhighlight(cfiRange: string): void;
ununderline(cfiRange: string): void; ununderline(cfiRange: string): void;
unmark(cfiRange: string): void; unmark(cfiRange: string): void;
destroy(): void; destroy(): void;
private onLoad(event: Event, promise: Promise<any>): void; private onLoad(event: Event, promise: Promise<any>): void;
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
} }

29
types/mapping.d.ts vendored
View file

@ -1,34 +1,35 @@
import Layout from "./layout";
import Contents from "./contents"; import Contents from "./contents";
import Layout from "./layout";
export interface EpubCFIPair { export interface EpubCFIPair {
start: string, start: string;
end: string end: string;
} }
export interface RangePair { export interface RangePair {
start: Range, start: Range;
end: Range end: Range;
} }
export default class Mapping { export default class Mapping {
constructor(layout: Layout, direction?: string, axis?: string, dev?: boolean); constructor(layout: Layout, direction?: string, axis?: string, dev?: boolean);
page(contents: Contents, cfiBase: string, start: number, end: number): EpubCFIPair; page(
contents: Contents,
cfiBase: string,
start: number,
end: number
): EpubCFIPair;
axis(axis: string): boolean; axis(axis: string): boolean;
private walk(root: Node, func: Function); private walk(root: Node, func: Function);
private findStart(root: Node, start: number, end: number): Range; private findStart(root: Node, start: number, end: number): Range;
private findEnd(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 findTextStartRange(node: Node, start: number, end: number): Range;
private findTextEndRange(node: Node, start: number, end: number): Range; private findTextEndRange(node: Node, start: number, end: number): Range;
private splitTextNodeIntoRanges(node: Node, _splitter?: string): Array<Range>; private splitTextNodeIntoRanges(node: Node, _splitter?: string): Array<Range>;
private rangePairToCfiPair(
private rangePairToCfiPair(cfiBase: string, rangePair: RangePair): EpubCFIPair; cfiBase: string,
rangePair: RangePair
): EpubCFIPair;
} }

37
types/navigation.d.ts vendored
View file

@ -1,15 +1,15 @@
export interface NavItem { export interface NavItem {
id: string, id: string;
href: string, href: string;
label: string, label: string;
subitems?: Array<NavItem>, subitems?: Array<NavItem>;
parent?: string parent?: string;
} }
export interface LandmarkItem { export interface LandmarkItem {
href?: string, href?: string;
label?: string, label?: string;
type?: string type?: string;
} }
export default class Navigation { export default class Navigation {
@ -19,28 +19,21 @@ export default class Navigation {
landmarks: Array<LandmarkItem>; landmarks: Array<LandmarkItem>;
parse(xml: XMLDocument): void; parse(xml: XMLDocument): void;
get(target: string): NavItem;
get(target: string) : NavItem; landmark(type: string): LandmarkItem;
landmark(type: string) : LandmarkItem;
load(json: string): Array<NavItem>; load(json: string): Array<NavItem>;
forEach(fn: (item: NavItem) => {}): any; forEach(fn: (item: NavItem) => {}): any;
private unpack(toc: Array<NavItem>): void; private unpack(toc: Array<NavItem>): void;
private parseNav(navHtml: XMLDocument): Array<NavItem>; private parseNav(navHtml: XMLDocument): Array<NavItem>;
private navItem(item: Element): NavItem; private navItem(item: Element): NavItem;
private parseLandmarks(navHtml: XMLDocument): Array<LandmarkItem>; private parseLandmarks(navHtml: XMLDocument): Array<LandmarkItem>;
private landmarkItem(item: Element): LandmarkItem; private landmarkItem(item: Element): LandmarkItem;
private parseNcx(navHtml: XMLDocument): Array<NavItem>; private parseNcx(navHtml: XMLDocument): Array<NavItem>;
private ncxItem(item: Element): NavItem; private ncxItem(item: Element): NavItem;
private getByIndex(
private getByIndex(target: string, index: number, navItems: NavItem[]): NavItem; target: string,
index: number,
navItems: NavItem[]
): NavItem;
} }

76
types/packaging.d.ts vendored
View file

@ -1,47 +1,47 @@
import { SpineItem } from "./section"; import { SpineItem } from "./section";
export interface PackagingObject { export interface PackagingObject {
metadata: PackagingMetadataObject, metadata: PackagingMetadataObject;
spine: Array<SpineItem>, spine: Array<SpineItem>;
manifest: PackagingManifestObject, manifest: PackagingManifestObject;
navPath: string, navPath: string;
ncxPath: string, ncxPath: string;
coverPath: string, coverPath: string;
spineNodeIndex: number spineNodeIndex: number;
} }
export interface PackagingMetadataObject { export interface PackagingMetadataObject {
title: string, title: string;
creator: string, creator: string;
description: string, description: string;
pubdate: string, pubdate: string;
publisher: string, publisher: string;
identifier: string, identifier: string;
language: string, language: string;
rights: string, rights: string;
modified_date: string, modified_date: string;
layout: string, layout: string;
orientation: string, orientation: string;
flow: string, flow: string;
viewport: string, viewport: string;
spread: string, spread: string;
direction: string, direction: string;
} }
export interface PackagingSpineItem { export interface PackagingSpineItem {
idref: string, idref: string;
properties: Array<string>, properties: Array<string>;
index: number index: number;
} }
export interface PackagingManifestItem { export interface PackagingManifestItem {
href: string, href: string;
type: string, type: string;
properties: Array<string> properties: Array<string>;
} }
export interface PackagingManifestObject { export interface PackagingManifestObject {
[key: string]: PackagingManifestItem [key: string]: PackagingManifestItem;
} }
export default class Packaging { export default class Packaging {
@ -56,24 +56,18 @@ export default class Packaging {
metadata: PackagingMetadataObject; metadata: PackagingMetadataObject;
parse(packageDocument: XMLDocument): PackagingObject; parse(packageDocument: XMLDocument): PackagingObject;
load(json: string): PackagingObject; load(json: string): PackagingObject;
destroy(): void; destroy(): void;
private parseMetadata(xml: Node): PackagingMetadataObject; private parseMetadata(xml: Node): PackagingMetadataObject;
private parseManifest(xml: Node): PackagingManifestObject; private parseManifest(xml: Node): PackagingManifestObject;
private parseSpine(
private parseSpine(xml: Node, manifest: PackagingManifestObject): Array<PackagingSpineItem>; xml: Node,
manifest: PackagingManifestObject
): Array<PackagingSpineItem>;
private findNavPath(manifestNode: Node): string | false; private findNavPath(manifestNode: Node): string | false;
private findNcxPath(manifestNode: Node, spineNode: Node): string | false; private findNcxPath(manifestNode: Node, spineNode: Node): string | false;
private findCoverPath(packageXml: Node): string; private findCoverPath(packageXml: Node): string;
private getElementText(xml: Node, tag: string): string;
private getElementText(xml: Node, tag: string): string private getPropertyText(xml: Node, property: string): string;
private getPropertyText(xml: Node, property: string): string
} }

16
types/pagelist.d.ts vendored
View file

@ -1,29 +1,21 @@
export interface PageListItem { export interface PageListItem {
href: string, href: string;
page: string, page: string;
cfi?: string, cfi?: string;
packageUrl?: string packageUrl?: string;
} }
export default class Pagelist { export default class Pagelist {
constructor(xml: XMLDocument); constructor(xml: XMLDocument);
parse(xml: XMLDocument): Array<PageListItem>; parse(xml: XMLDocument): Array<PageListItem>;
pageFromCfi(cfi: string): number; pageFromCfi(cfi: string): number;
cfiFromPage(pg: string | number): string; cfiFromPage(pg: string | number): string;
pageFromPercentage(percent: number): number; pageFromPercentage(percent: number): number;
percentageFromPage(pg: number): number; percentageFromPage(pg: number): number;
destroy(): void; destroy(): void;
private parseNav(navHtml: Node): Array<PageListItem>; private parseNav(navHtml: Node): Array<PageListItem>;
private item(item: Node): PageListItem; private item(item: Node): PageListItem;
private process(pageList: Array<PageListItem>): void; private process(pageList: Array<PageListItem>): void;
} }

134
types/rendition.d.ts vendored
View file

@ -1,67 +1,66 @@
import Annotations from "./annotations";
import Book from "./book"; import Book from "./book";
import Contents from "./contents"; 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 EpubCFI from "./epubcfi";
import Annotations from "./annotations"; import View from "./managers/view";
import Section from "./section";
import Themes from "./themes";
import Hook from "./utils/hook";
import Queue from "./utils/queue"; import Queue from "./utils/queue";
export interface RenditionOptions { export interface RenditionOptions {
width?: number | string, width?: number | string;
height?: number | string, height?: number | string;
ignoreClass?: string, ignoreClass?: string;
manager?: string | Function | object, manager?: string | Function | object;
view?: string | Function | object, view?: string | Function | object;
flow?: string, flow?: string;
layout?: string, layout?: string;
spread?: string, spread?: string;
minSpreadWidth?: number, minSpreadWidth?: number;
stylesheet?: string, stylesheet?: string;
resizeOnOrientationChange?: boolean, resizeOnOrientationChange?: boolean;
script?: string, script?: string;
infinite?: boolean, infinite?: boolean;
overflow?: string, overflow?: string;
snap?: boolean | object, snap?: boolean | object;
defaultDirection?: string, defaultDirection?: string;
allowScriptedContent?: boolean, allowScriptedContent?: boolean;
allowPopups?: boolean allowPopups?: boolean;
} }
export interface DisplayedLocation { export interface DisplayedLocation {
index: number, index: number;
href: string, href: string;
cfi: string, cfi: string;
location: number, location: number;
percentage: number, percentage: number;
displayed: { displayed: {
page: number, page: number;
total: number total: number;
} };
} }
export interface Location { export interface Location {
start: DisplayedLocation, start: DisplayedLocation;
end: DisplayedLocation, end: DisplayedLocation;
atStart: boolean, atStart: boolean;
atEnd: boolean atEnd: boolean;
} }
export default class Rendition { export default class Rendition {
constructor(book: Book, options: RenditionOptions); constructor(book: Book, options: RenditionOptions);
settings: RenditionOptions; settings: RenditionOptions;
book: Book; book: Book;
hooks: { hooks: {
display: Hook, display: Hook;
serialize: Hook, serialize: Hook;
content: Hook, content: Hook;
unloaded: Hook, unloaded: Hook;
layout: Hook, layout: Hook;
render: Hook, render: Hook;
show: Hook show: Hook;
} };
themes: Themes; themes: Themes;
annotations: Annotations; annotations: Annotations;
epubcfi: EpubCFI; epubcfi: EpubCFI;
@ -70,86 +69,51 @@ export default class Rendition {
started: Promise<void>; started: Promise<void>;
adjustImages(contents: Contents): Promise<void>; adjustImages(contents: Contents): Promise<void>;
attachTo(element: Element): Promise<void>; attachTo(element: Element): Promise<void>;
clear(): void; clear(): void;
currentLocation(): DisplayedLocation; currentLocation(): DisplayedLocation;
currentLocation(): Promise<DisplayedLocation>; currentLocation(): Promise<DisplayedLocation>;
destroy(): void; destroy(): void;
determineLayoutProperties(metadata: object): object; determineLayoutProperties(metadata: object): object;
direction(dir: string): void; direction(dir: string): void;
display(target?: string): Promise<void>; display(target?: string): Promise<void>;
display(target?: number): Promise<void>; display(target?: number): Promise<void>;
flow(flow: string): void; flow(flow: string): void;
getContents(): Contents; getContents(): Contents;
getRange(cfi: string, ignoreClass?: string): Range; getRange(cfi: string, ignoreClass?: string): Range;
handleLinks(contents: Contents): void; handleLinks(contents: Contents): void;
injectIdentifier(doc: Document, section: Section): void; injectIdentifier(doc: Document, section: Section): void;
injectScript(doc: Document, section: Section): void; injectScript(doc: Document, section: Section): void;
injectStylesheet(doc: Document, section: Section): void; injectStylesheet(doc: Document, section: Section): void;
layout(settings: any): any; layout(settings: any): any;
located(location: Location): DisplayedLocation; located(location: Location): DisplayedLocation;
moveTo(offset: number): void; moveTo(offset: number): void;
next(): Promise<void>; next(): Promise<void>;
onOrientationChange(orientation: string): void; onOrientationChange(orientation: string): void;
passEvents(contents: Contents): void; passEvents(contents: Contents): void;
prev(): Promise<void>; prev(): Promise<void>;
reportLocation(): Promise<void>; reportLocation(): Promise<void>;
requireManager(manager: string | Function | object): any; requireManager(manager: string | Function | object): any;
requireView(view: string | Function | object): any; requireView(view: string | Function | object): any;
resize(width: number, height: number): void; resize(width: number, height: number): void;
setManager(manager: Function): void; setManager(manager: Function): void;
spread(spread: string, min?: number): void; spread(spread: string, min?: number): void;
start(): void; start(): void;
views(): Array<View>; views(): Array<View>;
// Event emitters // Event emitters
emit(type: any, ...args: any[]): void; emit(type: any, ...args: any[]): void;
off(type: any, listener: any): any; off(type: any, listener: any): any;
on(type: any, listener: any): any; on(type: any, listener: any): any;
once(type: any, listener: any, ...args: any[]): any; once(type: any, listener: any, ...args: any[]): any;
private triggerMarkEvent(cfiRange: string, data: object, contents: Contents): void; private triggerMarkEvent(
cfiRange: string,
data: object,
contents: Contents
): void;
private triggerSelectedEvent(cfirange: string, contents: Contents): void; private triggerSelectedEvent(cfirange: string, contents: Contents): void;
private triggerViewEvent(e: Event, contents: Contents): void; private triggerViewEvent(e: Event, contents: Contents): void;
private onResized(size: { width: number; height: number }): void;
private onResized(size: { width: number, height: number }): void;
private afterDisplayed(view: any): void; private afterDisplayed(view: any): void;
private afterRemoved(view: any): void; private afterRemoved(view: any): void;
} }

32
types/resources.d.ts vendored
View file

@ -1,33 +1,29 @@
import { PackagingManifestObject } from "./packaging";
import Archive from "./archive"; import Archive from "./archive";
import { PackagingManifestObject } from "./packaging";
export default class Resources { export default class Resources {
constructor(manifest: PackagingManifestObject, options: { constructor(
replacements?: string, manifest: PackagingManifestObject,
archive?: Archive, options: {
resolver?: Function, replacements?: string;
request?: Function archive?: Archive;
}); resolver?: Function;
request?: Function;
}
);
process(manifest: PackagingManifestObject): void; process(manifest: PackagingManifestObject): void;
createUrl(url: string): Promise<string>; createUrl(url: string): Promise<string>;
replacements(): Promise<Array<string>>; replacements(): Promise<Array<string>>;
relativeTo(absolute: boolean, resolver?: Function): Array<string>; relativeTo(absolute: boolean, resolver?: Function): Array<string>;
get(path: string): string; get(path: string): string;
substitute(content: string, url?: string): string; substitute(content: string, url?: string): string;
destroy(): void; destroy(): void;
private split(): void; private split(): void;
private splitUrls(): void; private splitUrls(): void;
private replaceCss(
private replaceCss(archive: Archive, resolver?: Function): Promise<Array<string>>; archive: Archive,
resolver?: Function
): Promise<Array<string>>;
private createCssFile(href: string): Promise<string>; private createCssFile(href: string): Promise<string>;
} }

42
types/section.d.ts vendored
View file

@ -1,32 +1,31 @@
import { HooksObject } from "./utils/hook"; import { HooksObject } from "./utils/hook";
export interface GlobalLayout { export interface GlobalLayout {
layout: string, layout: string;
spread: string, spread: string;
orientation: string orientation: string;
} }
export interface LayoutSettings { export interface LayoutSettings {
layout: string, layout: string;
spread: string, spread: string;
orientation: string orientation: string;
} }
export interface SpineItem { export interface SpineItem {
index: number, index: number;
cfiBase: string, cfiBase: string;
href?: string, href?: string;
url?: string, url?: string;
canonical?: string, canonical?: string;
properties?: Array<string>, properties?: Array<string>;
linear?: string, linear?: string;
next: () => SpineItem, next: () => SpineItem;
prev: () => SpineItem, prev: () => SpineItem;
} }
export default class Section { export default class Section {
constructor(item: SpineItem, hooks: HooksObject); constructor(item: SpineItem, hooks: HooksObject);
idref: string; idref: string;
linear: boolean; linear: boolean;
properties: Array<string>; properties: Array<string>;
@ -37,28 +36,17 @@ export default class Section {
next: () => SpineItem; next: () => SpineItem;
prev: () => SpineItem; prev: () => SpineItem;
cfiBase: string; cfiBase: string;
document: Document; document: Document;
contents: Element; contents: Element;
output: string; output: string;
hooks: HooksObject; hooks: HooksObject;
load(_request?: Function): Document; load(_request?: Function): Document;
render(_request?: Function): string; render(_request?: Function): string;
find(_query: string): Array<Element>; find(_query: string): Array<Element>;
reconcileLayoutSettings(globalLayout: GlobalLayout): LayoutSettings; reconcileLayoutSettings(globalLayout: GlobalLayout): LayoutSettings;
cfiFromRange(_range: Range): string; cfiFromRange(_range: Range): string;
cfiFromElement(el: Element): string; cfiFromElement(el: Element): string;
unload(): void; unload(): void;
destroy(): void; destroy(): void;
private base(): void; private base(): void;
} }

14
types/spine.d.ts vendored
View file

@ -4,27 +4,17 @@ import Hook from "./utils/hook";
export default class Spine { export default class Spine {
constructor(); constructor();
hooks: { hooks: {
serialize: Hook, serialize: Hook;
content: Hook content: Hook;
}; };
unpack(_package: Packaging, resolver: Function, canonical: Function): void; unpack(_package: Packaging, resolver: Function, canonical: Function): void;
get(target?: string | number): Section; get(target?: string | number): Section;
each(...args: any[]): any; each(...args: any[]): any;
first(): Section; first(): Section;
last(): Section; last(): Section;
destroy(): void; destroy(): void;
private append(section: Section): number; private append(section: Section): number;
private prepend(section: Section): number; private prepend(section: Section): number;
private remove(section: Section): number; private remove(section: Section): number;
} }

31
types/store.d.ts vendored
View file

@ -1,30 +1,29 @@
import localForage = require('localforage'); import localForage = require("localforage");
import Resources from "./resources"; import Resources from "./resources";
export default class Store { export default class Store {
constructor(name: string, request?: Function, resolver?: Function); constructor(name: string, request?: Function, resolver?: Function);
add(resources: Resources, force?: boolean): Promise<Array<object>>; add(resources: Resources, force?: boolean): Promise<Array<object>>;
put(url: string, withCredentials?: boolean, headers?: object): Promise<Blob>; put(url: string, withCredentials?: boolean, headers?: object): Promise<Blob>;
request(
request(url: string, type?: string, withCredentials?: boolean, headers?: object): Promise<Blob | string | JSON | Document | XMLDocument>; url: string,
type?: string,
retrieve(url: string, type?: string): Promise<Blob | string | JSON | Document | XMLDocument>; withCredentials?: boolean,
headers?: object
): Promise<Blob | string | JSON | Document | XMLDocument>;
retrieve(
url: string,
type?: string
): Promise<Blob | string | JSON | Document | XMLDocument>;
getBlob(url: string, mimeType?: string): Promise<Blob>; getBlob(url: string, mimeType?: string): Promise<Blob>;
getText(url: string): Promise<string>; getText(url: string): Promise<string>;
getBase64(url: string, mimeType?: string): Promise<string>; getBase64(url: string, mimeType?: string): Promise<string>;
createUrl(url: string, options: { base64: boolean }): Promise<string>; createUrl(url: string, options: { base64: boolean }): Promise<string>;
revokeUrl(url: string): void; revokeUrl(url: string): void;
destroy(): void; destroy(): void;
private checkRequirements(): void; private checkRequirements(): void;
private handleResponse(
private handleResponse(response: any, type?: string): Blob | string | JSON | Document | XMLDocument; response: any,
type?: string
): Blob | string | JSON | Document | XMLDocument;
} }

43
types/themes.d.ts vendored
View file

@ -1,40 +1,23 @@
import Rendition from "./rendition";
import Contents from "./contents"; import Contents from "./contents";
import Rendition from "./rendition";
export default class Themes { export default class Themes {
constructor(rendition: Rendition); constructor(rendition: Rendition);
register(themeObject: object): void;
register( themeObject: object ): void; register(theme: string, url: string): void;
register(theme: string, themeObject: object): void;
register( theme: string, url: string ): void; default(theme: object | string): void;
registerThemes(themes: object): void;
register( theme: string, themeObject: object ): void; registerCss(name: string, css: string): void;
registerUrl(name: string, input: string): void;
default( theme: object | string ): void; registerRules(name: string, rules: object): void;
select(name: string): void;
registerThemes( themes: object ): void; update(name: string): void;
inject(content: Contents): void;
registerCss( name: string, css: string ): void; add(name: string, contents: Contents): 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; override(name: string, value: string, priority?: boolean): void;
overrides(contents: Contents): void; overrides(contents: Contents): void;
fontSize(size: string): void; fontSize(size: string): void;
font(f: string): void; font(f: string): void;
destroy(): void; destroy(): void;
} }

View file

@ -1,24 +1,16 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "commonjs",
"lib": [ "lib": ["es6", "dom"],
"es6",
"dom"
],
"noImplicitAny": true, "noImplicitAny": true,
"noImplicitThis": true, "noImplicitThis": true,
"strictNullChecks": true, "strictNullChecks": true,
"strictFunctionTypes": true, "strictFunctionTypes": true,
"baseUrl": "../", "baseUrl": "../",
"typeRoots": [ "typeRoots": ["../"],
"../"
],
"types": [], "types": [],
"noEmit": true, "noEmit": true,
"forceConsistentCasingInFileNames": true "forceConsistentCasingInFileNames": true
}, },
"files": [ "files": ["index.d.ts"]
"index.d.ts",
"epubjs-tests.ts"
]
} }

View file

@ -4,6 +4,6 @@ export const DOM_EVENTS: Array<string>;
export const EVENTS: { export const EVENTS: {
[key: string]: { [key: string]: {
[key: string]: string [key: string]: string;
} };
} };

114
types/utils/core.d.ts vendored
View file

@ -1,79 +1,85 @@
export function uuid(): string; export function uuid(): string;
export function documentHeight(): number; export function documentHeight(): number;
export function isElement(obj: object): boolean; export function isElement(obj: object): boolean;
export function isNumber(n: any): boolean; export function isNumber(n: any): boolean;
export function isFloat(n: any): boolean; export function isFloat(n: any): boolean;
export function prefixed(unprefixed: string): string; export function prefixed(unprefixed: string): string;
export function defaults(obj: object): object; export function defaults(obj: object): object;
export function extend(target: object): object; export function extend(target: object): object;
export function insert(
export function insert(item: any, array: Array<any>, compareFunction: Function): number; item: any,
array: Array<any>,
export function locationOf(item: any, array: Array<any>, compareFunction: Function, _start: Function, _end: Function): number; compareFunction: Function
): number;
export function indexOfSorted(item: any, array: Array<any>, compareFunction: Function, _start: Function, _end: Function): number; export function locationOf(
item: any,
export function bounds(el: Element): { width: Number, height: Number}; array: Array<any>,
compareFunction: Function,
export function borders(el: Element): { width: Number, height: Number}; _start: Function,
_end: Function
): number;
export function indexOfSorted(
item: any,
array: Array<any>,
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 nodeBounds(node: Node): object;
export function windowBounds(): {
export function windowBounds(): { width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }; width: Number;
height: Number;
top: Number;
left: Number;
right: Number;
bottom: Number;
};
export function indexOfNode(node: Node, typeId: string): number; export function indexOfNode(node: Node, typeId: string): number;
export function indexOfTextNode(textNode: Node): number; export function indexOfTextNode(textNode: Node): number;
export function indexOfElementNode(elementNode: Element): number; export function indexOfElementNode(elementNode: Element): number;
export function isXml(ext: string): boolean; export function isXml(ext: string): boolean;
export function createBlob(content: any, mime: string): Blob; export function createBlob(content: any, mime: string): Blob;
export function createBlobUrl(content: any, mime: string): string; export function createBlobUrl(content: any, mime: string): string;
export function revokeBlobUrl(url: string): void; export function revokeBlobUrl(url: string): void;
export function createBase64Url(content: any, mime: string): string;
export function createBase64Url(content: any, mime: string): string
export function type(obj: object): string; export function type(obj: object): string;
export function parse(
export function parse(markup: string, mime: string, forceXMLDom: boolean): Document; markup: string,
mime: string,
forceXMLDom: boolean
): Document;
export function qs(el: Element, sel: string): Element; export function qs(el: Element, sel: string): Element;
export function qsa(el: Element, sel: string): ArrayLike<Element>; export function qsa(el: Element, sel: string): ArrayLike<Element>;
export function qsp(
export function qsp(el: Element, sel: string, props: Array<object>): ArrayLike<Element>; el: Element,
sel: string,
props: Array<object>
): ArrayLike<Element>;
export function sprint(root: Node, func: Function): void; export function sprint(root: Node, func: Function): void;
export function treeWalker(
export function treeWalker(root: Node, func: Function, filter: object | Function): void; root: Node,
func: Function,
filter: object | Function
): void;
export function walk(node: Node, callback: Function): void; export function walk(node: Node, callback: Function): void;
export function blob2base64(blob: Blob): string; export function blob2base64(blob: Blob): string;
export function defer(): Promise<any>; export function defer(): Promise<any>;
export function querySelectorByType(
export function querySelectorByType(html: Element, element: string, type: string): Array<Element>; html: Element,
element: string,
type: string
): Array<Element>;
export function findChildren(el: Element): Array<Element>; export function findChildren(el: Element): Array<Element>;
export function parents(node: Element): Array<Element>; export function parents(node: Element): Array<Element>;
export function filterChildren(
export function filterChildren(el: Element, nodeName: string, single: boolean): Array<Element>; el: Element,
nodeName: string,
export function getParentByTagName(node: Element, tagname: string): Array<Element>; single: boolean
): Array<Element>;
export class RangeObject extends Range { export function getParentByTagName(
node: Element,
} tagname: string
): Array<Element>;
export class RangeObject extends Range {}

View file

@ -1,5 +1,5 @@
interface HooksObject { interface HooksObject {
[key: string]: Hook [key: string]: Hook;
} }
export default class Hook { export default class Hook {
@ -7,12 +7,8 @@ export default class Hook {
register(func: Function): void; register(func: Function): void;
register(arr: Array<Function>): void; register(arr: Array<Function>): void;
deregister(func: Function): void; deregister(func: Function): void;
trigger(...args: any[]): Promise<any>; trigger(...args: any[]): Promise<any>;
list(): Array<any>; list(): Array<any>;
clear(): void; clear(): void;
} }

View file

@ -2,16 +2,10 @@ export default class Path {
constructor(pathString: string); constructor(pathString: string);
parse(what: string): object; parse(what: string): object;
isAbsolute(what: string): boolean; isAbsolute(what: string): boolean;
isDirectory(what: string): boolean; isDirectory(what: string): boolean;
resolve(what: string): string; resolve(what: string): string;
relative(what: string): string; relative(what: string): string;
splitPath(filename: string): string; splitPath(filename: string): string;
toString(): string; toString(): string;
} }

View file

@ -1,31 +1,21 @@
import { defer } from "./core";
export interface QueuedTask { export interface QueuedTask {
task: any | Task, task: any | Task;
args: any[], args: any[];
deferred: any, // should be defer, but not working deferred: any; // should be defer, but not working
promise: Promise<any> promise: Promise<any>;
} }
export default class Queue { export default class Queue {
constructor(context: any); constructor(context: any);
enqueue(func: Promise<Function> | Function, ...args: any[]): Promise<any>; enqueue(func: Promise<Function> | Function, ...args: any[]): Promise<any>;
dequeue(): Promise<QueuedTask>; dequeue(): Promise<QueuedTask>;
dump(): void; dump(): void;
run(): Promise<void>; run(): Promise<void>;
flush(): Promise<void>; flush(): Promise<void>;
clear(): void; clear(): void;
length(): number; length(): number;
pause(): void; pause(): void;
stop(): void; stop(): void;
} }

View file

@ -1,12 +1,12 @@
import Section from "../section";
import Contents from "../contents"; import Contents from "../contents";
import Section from "../section";
export function replaceBase(doc: Document, section: Section): void; export function replaceBase(doc: Document, section: Section): void;
export function replaceCanonical(doc: Document, section: Section): void; export function replaceCanonical(doc: Document, section: Section): void;
export function replaceMeta(doc: Document, section: Section): void; export function replaceMeta(doc: Document, section: Section): void;
export function replaceLinks(contents: Contents, fn: Function): void; export function replaceLinks(contents: Contents, fn: Function): void;
export function substitute(
export function substitute(contents: Contents, urls: string[], replacements: string[]): void; contents: Contents,
urls: string[],
replacements: string[]
): void;

View file

@ -1 +1,6 @@
export default function request(url: string, type?: string, withCredentials?: boolean, headers?: object): Promise<Blob | string | JSON | Document | XMLDocument>; export default function request(
url: string,
type?: string,
withCredentials?: boolean,
headers?: object
): Promise<Blob | string | JSON | Document | XMLDocument>;

View file

@ -1,3 +1,2 @@
export default function scrollType(): string; export default function scrollType(): string;
export function createDefiner(): Node; export function createDefiner(): Node;

View file

@ -4,10 +4,7 @@ export default class Url {
constructor(urlString: string, baseString: string); constructor(urlString: string, baseString: string);
path(): Path; path(): Path;
resolve(what: string): string; resolve(what: string): string;
relative(what: string): string; relative(what: string): string;
toString(): string; toString(): string;
} }

View file

@ -1,8 +1,6 @@
var webpack = require("webpack");
var path = require("path"); var path = require("path");
var PROD = (process.env.NODE_ENV === "production") var LEGACY = process.env.LEGACY;
var LEGACY = (process.env.LEGACY) var MINIMIZE = process.env.MINIMIZE === "true";
var MINIMIZE = (process.env.MINIMIZE === "true")
var hostname = "localhost"; var hostname = "localhost";
var port = 8080; var port = 8080;
@ -22,9 +20,9 @@ if (MINIMIZE) {
module.exports = { module.exports = {
mode: process.env.NODE_ENV, mode: process.env.NODE_ENV,
entry: { entry: {
"epub": "./src/epub.js", epub: "./src/epub.js",
}, },
devtool: MINIMIZE ? false : 'source-map', devtool: MINIMIZE ? false : "source-map",
output: { output: {
path: path.resolve("./dist"), path: path.resolve("./dist"),
filename: filename, filename: filename,
@ -32,20 +30,20 @@ module.exports = {
library: "ePub", library: "ePub",
libraryTarget: "umd", libraryTarget: "umd",
libraryExport: "default", libraryExport: "default",
publicPath: "/dist/" publicPath: "/dist/",
}, },
optimization: { optimization: {
minimize: MINIMIZE minimize: MINIMIZE,
}, },
externals: { externals: {
"jszip/dist/jszip": "JSZip", "jszip/dist/jszip": "JSZip",
"xmldom": "xmldom" xmldom: "xmldom",
}, },
plugins: [], plugins: [],
resolve: { resolve: {
alias: { alias: {
path: "path-webpack" path: "path-webpack",
} },
}, },
devServer: { devServer: {
host: hostname, host: hostname,
@ -54,8 +52,8 @@ module.exports = {
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE", "Access-Control-Allow-Methods": "GET,PUT,POST,DELETE",
"Access-Control-Allow-Headers": "Content-Type" "Access-Control-Allow-Headers": "Content-Type",
} },
}, },
module: { module: {
rules: [ rules: [
@ -65,19 +63,26 @@ module.exports = {
use: { use: {
loader: "babel-loader", loader: "babel-loader",
options: { options: {
presets: [["@babel/preset-env", { presets: [
targets: LEGACY ? "defaults" : "last 2 Chrome versions, last 2 Safari versions, last 2 ChromeAndroid versions, last 2 iOS versions, last 2 Firefox versions, last 2 Edge versions", [
"@babel/preset-env",
{
targets: LEGACY
? "defaults"
: "last 2 Chrome versions, last 2 Safari versions, last 2 ChromeAndroid versions, last 2 iOS versions, last 2 Firefox versions, last 2 Edge versions",
corejs: 3, corejs: 3,
useBuiltIns: "usage", useBuiltIns: "usage",
bugfixes: true, bugfixes: true,
modules: false modules: false,
}]] },
} ],
} ],
} },
] },
},
],
}, },
performance: { performance: {
hints: false hints: false,
} },
} };