M?M:I+U));return 1==A?(B=N[R-1],O+=C[B>>2],O+=C[63&B<<4],O+='=='):2==A&&(B=(N[R-2]<<8)+N[R-1],O+=C[B>>10],O+=C[63&B>>4],O+=C[63&B<<2],O+='='),W.push(O),W.join('')};var C=[],S=[],k='undefined'==typeof Uint8Array?Array:Uint8Array,E='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';for(var T=0,P=E.length;Targuments.length||'string'!=typeof E?(B=T,T=E,E=null):B=arguments[2],null==E?(P=N=!0,z=!1):(P=S.call(E,'c'),z=S.call(E,'e'),N=S.call(E,'w')),R={value:T,configurable:P,enumerable:z,writable:N},B?v(_(B),R):R},k.gs=function(E,T,P){var z,N,B,R;return'string'==typeof E?B=arguments[3]:(B=P,P=T,T=E,E=null),null==T?T=void 0:C(T)?null==P?P=void 0:!C(P)&&(B=P,P=void 0):(B=T,T=P=void 0),null==E?(z=!0,N=!1):(z=S.call(E,'c'),N=S.call(E,'e')),R={get:T,set:P,configurable:z,enumerable:N},B?v(_(B),R):R}},function(p,u,f){'use strict';'use strict';p.exports=f(34)()?Object.assign:f(35)},function(p){'use strict';'use strict';p.exports=function(){var f,u=Object.assign;return!('function'!=typeof u)&&(f={foo:'raz'},u(f,{bar:'dwa'},{trzy:'trzy'}),'razdwatrzy'===f.foo+f.bar+f.trzy)}},function(p,u,f){'use strict';'use strict';var v=f(37),_=f(42),C=Math.max;p.exports=function(S,k){var E,T,z,P=C(arguments.length,2);for(S=Object(_(S)),z=function(N){try{S[N]=k[N]}catch(B){E||(E=B)}},T=1;T
0x20 &&
- unicode < 0x7F &&
- // " # < > ? `
- [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- function percentEscapeQuery(c) {
- // XXX This actually needs to encode c using encoding and then
- // convert the bytes one-by-one.
-
- var unicode = c.charCodeAt(0);
- if (unicode > 0x20 &&
- unicode < 0x7F &&
- // " # < > ` (do not escape '?')
- [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
- ) {
- return c;
- }
- return encodeURIComponent(c);
- }
-
- var EOF = undefined,
- ALPHA = /[a-zA-Z]/,
- ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
-
- function parse(input, stateOverride, base) {
- function err(message) {
- errors.push(message)
- }
-
- var state = stateOverride || 'scheme start',
- cursor = 0,
- buffer = '',
- seenAt = false,
- seenBracket = false,
- errors = [];
-
- loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
- var c = input[cursor];
- switch (state) {
- case 'scheme start':
- if (c && ALPHA.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- state = 'scheme';
- } else if (!stateOverride) {
- buffer = '';
- state = 'no scheme';
- continue;
- } else {
- err('Invalid scheme.');
- break loop;
- }
- break;
-
- case 'scheme':
- if (c && ALPHANUMERIC.test(c)) {
- buffer += c.toLowerCase(); // ASCII-safe
- } else if (':' == c) {
- this._scheme = buffer;
- buffer = '';
- if (stateOverride) {
- break loop;
- }
- if (isRelativeScheme(this._scheme)) {
- this._isRelative = true;
- }
- if ('file' == this._scheme) {
- state = 'relative';
- } else if (this._isRelative && base && base._scheme == this._scheme) {
- state = 'relative or authority';
- } else if (this._isRelative) {
- state = 'authority first slash';
- } else {
- state = 'scheme data';
- }
- } else if (!stateOverride) {
- buffer = '';
- cursor = 0;
- state = 'no scheme';
- continue;
- } else if (EOF == c) {
- break loop;
- } else {
- err('Code point not allowed in scheme: ' + c)
- break loop;
- }
- break;
-
- case 'scheme data':
- if ('?' == c) {
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else {
- // XXX error handling
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._schemeData += percentEscape(c);
- }
- }
- break;
-
- case 'no scheme':
- if (!base || !(isRelativeScheme(base._scheme))) {
- err('Missing scheme.');
- invalid.call(this);
- } else {
- state = 'relative';
- continue;
- }
- break;
-
- case 'relative or authority':
- if ('/' == c && '/' == input[cursor+1]) {
- state = 'authority ignore slashes';
- } else {
- err('Expected /, got: ' + c);
- state = 'relative';
- continue
- }
- break;
-
- case 'relative':
- this._isRelative = true;
- if ('file' != this._scheme)
- this._scheme = base._scheme;
- if (EOF == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- this._username = base._username;
- this._password = base._password;
- break loop;
- } else if ('/' == c || '\\' == c) {
- if ('\\' == c)
- err('\\ is an invalid code point.');
- state = 'relative slash';
- } else if ('?' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = '?';
- this._username = base._username;
- this._password = base._password;
- state = 'query';
- } else if ('#' == c) {
- this._host = base._host;
- this._port = base._port;
- this._path = base._path.slice();
- this._query = base._query;
- this._fragment = '#';
- this._username = base._username;
- this._password = base._password;
- state = 'fragment';
- } else {
- var nextC = input[cursor+1]
- var nextNextC = input[cursor+2]
- if (
- 'file' != this._scheme || !ALPHA.test(c) ||
- (nextC != ':' && nextC != '|') ||
- (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
- this._host = base._host;
- this._port = base._port;
- this._username = base._username;
- this._password = base._password;
- this._path = base._path.slice();
- this._path.pop();
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'relative slash':
- if ('/' == c || '\\' == c) {
- if ('\\' == c) {
- err('\\ is an invalid code point.');
- }
- if ('file' == this._scheme) {
- state = 'file host';
- } else {
- state = 'authority ignore slashes';
- }
- } else {
- if ('file' != this._scheme) {
- this._host = base._host;
- this._port = base._port;
- this._username = base._username;
- this._password = base._password;
- }
- state = 'relative path';
- continue;
- }
- break;
-
- case 'authority first slash':
- if ('/' == c) {
- state = 'authority second slash';
- } else {
- err("Expected '/', got: " + c);
- state = 'authority ignore slashes';
- continue;
- }
- break;
-
- case 'authority second slash':
- state = 'authority ignore slashes';
- if ('/' != c) {
- err("Expected '/', got: " + c);
- continue;
- }
- break;
-
- case 'authority ignore slashes':
- if ('/' != c && '\\' != c) {
- state = 'authority';
- continue;
- } else {
- err('Expected authority, got: ' + c);
- }
- break;
-
- case 'authority':
- if ('@' == c) {
- if (seenAt) {
- err('@ already seen.');
- buffer += '%40';
- }
- seenAt = true;
- for (var i = 0; i < buffer.length; i++) {
- var cp = buffer[i];
- if ('\t' == cp || '\n' == cp || '\r' == cp) {
- err('Invalid whitespace in authority.');
- continue;
- }
- // XXX check URL code points
- if (':' == cp && null === this._password) {
- this._password = '';
- continue;
- }
- var tempC = percentEscape(cp);
- (null !== this._password) ? this._password += tempC : this._username += tempC;
- }
- buffer = '';
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- cursor -= buffer.length;
- buffer = '';
- state = 'host';
- continue;
- } else {
- buffer += c;
- }
- break;
-
- case 'file host':
- if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
- state = 'relative path';
- } else if (buffer.length == 0) {
- state = 'relative path start';
- } else {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- }
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid whitespace in file host.');
- } else {
- buffer += c;
- }
- break;
-
- case 'host':
- case 'hostname':
- if (':' == c && !seenBracket) {
- // XXX host parsing
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'port';
- if ('hostname' == stateOverride) {
- break loop;
- }
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
- this._host = IDNAToASCII.call(this, buffer);
- buffer = '';
- state = 'relative path start';
- if (stateOverride) {
- break loop;
- }
- continue;
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- if ('[' == c) {
- seenBracket = true;
- } else if (']' == c) {
- seenBracket = false;
- }
- buffer += c;
- } else {
- err('Invalid code point in host/hostname: ' + c);
- }
- break;
-
- case 'port':
- if (/[0-9]/.test(c)) {
- buffer += c;
- } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
- if ('' != buffer) {
- var temp = parseInt(buffer, 10);
- if (temp != relative[this._scheme]) {
- this._port = temp + '';
- }
- buffer = '';
- }
- if (stateOverride) {
- break loop;
- }
- state = 'relative path start';
- continue;
- } else if ('\t' == c || '\n' == c || '\r' == c) {
- err('Invalid code point in port: ' + c);
- } else {
- invalid.call(this);
- }
- break;
-
- case 'relative path start':
- if ('\\' == c)
- err("'\\' not allowed in path.");
- state = 'relative path';
- if ('/' != c && '\\' != c) {
- continue;
- }
- break;
-
- case 'relative path':
- if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
- if ('\\' == c) {
- err('\\ not allowed in relative path.');
- }
- var tmp;
- if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
- buffer = tmp;
- }
- if ('..' == buffer) {
- this._path.pop();
- if ('/' != c && '\\' != c) {
- this._path.push('');
- }
- } else if ('.' == buffer && '/' != c && '\\' != c) {
- this._path.push('');
- } else if ('.' != buffer) {
- if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
- buffer = buffer[0] + ':';
- }
- this._path.push(buffer);
- }
- buffer = '';
- if ('?' == c) {
- this._query = '?';
- state = 'query';
- } else if ('#' == c) {
- this._fragment = '#';
- state = 'fragment';
- }
- } else if ('\t' != c && '\n' != c && '\r' != c) {
- buffer += percentEscape(c);
- }
- break;
-
- case 'query':
- if (!stateOverride && '#' == c) {
- this._fragment = '#';
- state = 'fragment';
- } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._query += percentEscapeQuery(c);
- }
- break;
-
- case 'fragment':
- if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
- this._fragment += c;
- }
- break;
- }
-
- cursor++;
- }
- }
-
- function clear() {
- this._scheme = '';
- this._schemeData = '';
- this._username = '';
- this._password = null;
- this._host = '';
- this._port = '';
- this._path = [];
- this._query = '';
- this._fragment = '';
- this._isInvalid = false;
- this._isRelative = false;
- }
-
- // Does not process domain names or IP addresses.
- // Does not handle encoding for the query parameter.
- function jURL(url, base /* , encoding */) {
- if (base !== undefined && !(base instanceof jURL))
- base = new jURL(String(base));
-
- this._url = url;
- clear.call(this);
-
- var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
- // encoding = encoding || 'utf-8'
-
- parse.call(this, input, null, base);
- }
-
- jURL.prototype = {
- toString: function() {
- return this.href;
- },
- get href() {
- if (this._isInvalid)
- return this._url;
-
- var authority = '';
- if ('' != this._username || null != this._password) {
- authority = this._username +
- (null != this._password ? ':' + this._password : '') + '@';
- }
-
- return this.protocol +
- (this._isRelative ? '//' + authority + this.host : '') +
- this.pathname + this._query + this._fragment;
- },
- set href(href) {
- clear.call(this);
- parse.call(this, href);
- },
-
- get protocol() {
- return this._scheme + ':';
- },
- set protocol(protocol) {
- if (this._isInvalid)
- return;
- parse.call(this, protocol + ':', 'scheme start');
- },
-
- get host() {
- return this._isInvalid ? '' : this._port ?
- this._host + ':' + this._port : this._host;
- },
- set host(host) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, host, 'host');
- },
-
- get hostname() {
- return this._host;
- },
- set hostname(hostname) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, hostname, 'hostname');
- },
-
- get port() {
- return this._port;
- },
- set port(port) {
- if (this._isInvalid || !this._isRelative)
- return;
- parse.call(this, port, 'port');
- },
-
- get pathname() {
- return this._isInvalid ? '' : this._isRelative ?
- '/' + this._path.join('/') : this._schemeData;
- },
- set pathname(pathname) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._path = [];
- parse.call(this, pathname, 'relative path start');
- },
-
- get search() {
- return this._isInvalid || !this._query || '?' == this._query ?
- '' : this._query;
- },
- set search(search) {
- if (this._isInvalid || !this._isRelative)
- return;
- this._query = '?';
- if ('?' == search[0])
- search = search.slice(1);
- parse.call(this, search, 'query');
- },
-
- get hash() {
- return this._isInvalid || !this._fragment || '#' == this._fragment ?
- '' : this._fragment;
- },
- set hash(hash) {
- if (this._isInvalid)
- return;
- this._fragment = '#';
- if ('#' == hash[0])
- hash = hash.slice(1);
- parse.call(this, hash, 'fragment');
- },
-
- get origin() {
- var host;
- if (this._isInvalid || !this._scheme) {
- return '';
- }
- // javascript: Gecko returns String(""), WebKit/Blink String("null")
- // Gecko throws error for "data://"
- // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
- // Gecko returns String("") for file: mailto:
- // WebKit/Blink returns String("SCHEME://") for file: mailto:
- switch (this._scheme) {
- case 'data':
- case 'file':
- case 'javascript':
- case 'mailto':
- return 'null';
- }
- host = this.host;
- if (!host) {
- return '';
- }
- return this._scheme + '://' + host;
- }
- };
-
- // Copy over the static methods
- var OriginalURL = scope.URL;
- if (OriginalURL) {
- jURL.createObjectURL = function(blob) {
- // IE extension allows a second optional options argument.
- // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
- return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
- };
- jURL.revokeObjectURL = function(url) {
- OriginalURL.revokeObjectURL(url);
- };
- }
-
- return jURL;
-}));
-
-
-/***/ },
-
-/***/ 16:
-/***/ function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(process, global) {var require;/*!
- * @overview es6-promise - a tiny implementation of Promises/A+.
- * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
- * @license Licensed under MIT license
- * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
- * @version 4.0.5
- */
-
-(function (global, factory) {
- true ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global.ES6Promise = factory());
-}(this, (function () { 'use strict';
-
-function objectOrFunction(x) {
- return typeof x === 'function' || typeof x === 'object' && x !== null;
-}
-
-function isFunction(x) {
- return typeof x === 'function';
-}
-
-var _isArray = undefined;
-if (!Array.isArray) {
- _isArray = function (x) {
- return Object.prototype.toString.call(x) === '[object Array]';
- };
-} else {
- _isArray = Array.isArray;
-}
-
-var isArray = _isArray;
-
-var len = 0;
-var vertxNext = undefined;
-var customSchedulerFn = undefined;
-
-var asap = function asap(callback, arg) {
- queue[len] = callback;
- queue[len + 1] = arg;
- len += 2;
- if (len === 2) {
- // If len is 2, that means that we need to schedule an async flush.
- // If additional callbacks are queued before the queue is flushed, they
- // will be processed by this flush that we are scheduling.
- if (customSchedulerFn) {
- customSchedulerFn(flush);
- } else {
- scheduleFlush();
- }
- }
-};
-
-function setScheduler(scheduleFn) {
- customSchedulerFn = scheduleFn;
-}
-
-function setAsap(asapFn) {
- asap = asapFn;
-}
-
-var browserWindow = typeof window !== 'undefined' ? window : undefined;
-var browserGlobal = browserWindow || {};
-var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
-var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';
-
-// test for web worker but not in IE10
-var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
-
-// node
-function useNextTick() {
- // node version 0.10.x displays a deprecation warning when nextTick is used recursively
- // see https://github.com/cujojs/when/issues/410 for details
- return function () {
- return process.nextTick(flush);
- };
-}
-
-// vertx
-function useVertxTimer() {
- if (typeof vertxNext !== 'undefined') {
- return function () {
- vertxNext(flush);
- };
- }
-
- return useSetTimeout();
-}
-
-function useMutationObserver() {
- var iterations = 0;
- var observer = new BrowserMutationObserver(flush);
- var node = document.createTextNode('');
- observer.observe(node, { characterData: true });
-
- return function () {
- node.data = iterations = ++iterations % 2;
- };
-}
-
-// web worker
-function useMessageChannel() {
- var channel = new MessageChannel();
- channel.port1.onmessage = flush;
- return function () {
- return channel.port2.postMessage(0);
- };
-}
-
-function useSetTimeout() {
- // Store setTimeout reference so es6-promise will be unaffected by
- // other code modifying setTimeout (like sinon.useFakeTimers())
- var globalSetTimeout = setTimeout;
- return function () {
- return globalSetTimeout(flush, 1);
- };
-}
-
-var queue = new Array(1000);
-function flush() {
- for (var i = 0; i < len; i += 2) {
- var callback = queue[i];
- var arg = queue[i + 1];
-
- callback(arg);
-
- queue[i] = undefined;
- queue[i + 1] = undefined;
- }
-
- len = 0;
-}
-
-function attemptVertx() {
- try {
- var r = require;
- var vertx = __webpack_require__(49);
- vertxNext = vertx.runOnLoop || vertx.runOnContext;
- return useVertxTimer();
- } catch (e) {
- return useSetTimeout();
- }
-}
-
-var scheduleFlush = undefined;
-// Decide what async method to use to triggering processing of queued callbacks:
-if (isNode) {
- scheduleFlush = useNextTick();
-} else if (BrowserMutationObserver) {
- scheduleFlush = useMutationObserver();
-} else if (isWorker) {
- scheduleFlush = useMessageChannel();
-} else if (browserWindow === undefined && "function" === 'function') {
- scheduleFlush = attemptVertx();
-} else {
- scheduleFlush = useSetTimeout();
-}
-
-function then(onFulfillment, onRejection) {
- var _arguments = arguments;
-
- var parent = this;
-
- var child = new this.constructor(noop);
-
- if (child[PROMISE_ID] === undefined) {
- makePromise(child);
- }
-
- var _state = parent._state;
-
- if (_state) {
- (function () {
- var callback = _arguments[_state - 1];
- asap(function () {
- return invokeCallback(_state, child, callback, parent._result);
- });
- })();
- } else {
- subscribe(parent, child, onFulfillment, onRejection);
- }
-
- return child;
-}
-
-/**
- `Promise.resolve` returns a promise that will become resolved with the
- passed `value`. It is shorthand for the following:
-
- ```javascript
- let promise = new Promise(function(resolve, reject){
- resolve(1);
- });
-
- promise.then(function(value){
- // value === 1
- });
- ```
-
- Instead of writing the above, your code now simply becomes the following:
-
- ```javascript
- let promise = Promise.resolve(1);
-
- promise.then(function(value){
- // value === 1
- });
- ```
-
- @method resolve
- @static
- @param {Any} value value that the returned promise will be resolved with
- Useful for tooling.
- @return {Promise} a promise that will become fulfilled with the given
- `value`
-*/
-function resolve(object) {
- /*jshint validthis:true */
- var Constructor = this;
-
- if (object && typeof object === 'object' && object.constructor === Constructor) {
- return object;
- }
-
- var promise = new Constructor(noop);
- _resolve(promise, object);
- return promise;
-}
-
-var PROMISE_ID = Math.random().toString(36).substring(16);
-
-function noop() {}
-
-var PENDING = void 0;
-var FULFILLED = 1;
-var REJECTED = 2;
-
-var GET_THEN_ERROR = new ErrorObject();
-
-function selfFulfillment() {
- return new TypeError("You cannot resolve a promise with itself");
-}
-
-function cannotReturnOwn() {
- return new TypeError('A promises callback cannot return that same promise.');
-}
-
-function getThen(promise) {
- try {
- return promise.then;
- } catch (error) {
- GET_THEN_ERROR.error = error;
- return GET_THEN_ERROR;
- }
-}
-
-function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
- try {
- then.call(value, fulfillmentHandler, rejectionHandler);
- } catch (e) {
- return e;
- }
-}
-
-function handleForeignThenable(promise, thenable, then) {
- asap(function (promise) {
- var sealed = false;
- var error = tryThen(then, thenable, function (value) {
- if (sealed) {
- return;
- }
- sealed = true;
- if (thenable !== value) {
- _resolve(promise, value);
- } else {
- fulfill(promise, value);
- }
- }, function (reason) {
- if (sealed) {
- return;
- }
- sealed = true;
-
- _reject(promise, reason);
- }, 'Settle: ' + (promise._label || ' unknown promise'));
-
- if (!sealed && error) {
- sealed = true;
- _reject(promise, error);
- }
- }, promise);
-}
-
-function handleOwnThenable(promise, thenable) {
- if (thenable._state === FULFILLED) {
- fulfill(promise, thenable._result);
- } else if (thenable._state === REJECTED) {
- _reject(promise, thenable._result);
- } else {
- subscribe(thenable, undefined, function (value) {
- return _resolve(promise, value);
- }, function (reason) {
- return _reject(promise, reason);
- });
- }
-}
-
-function handleMaybeThenable(promise, maybeThenable, then$$) {
- if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {
- handleOwnThenable(promise, maybeThenable);
- } else {
- if (then$$ === GET_THEN_ERROR) {
- _reject(promise, GET_THEN_ERROR.error);
- } else if (then$$ === undefined) {
- fulfill(promise, maybeThenable);
- } else if (isFunction(then$$)) {
- handleForeignThenable(promise, maybeThenable, then$$);
- } else {
- fulfill(promise, maybeThenable);
- }
- }
-}
-
-function _resolve(promise, value) {
- if (promise === value) {
- _reject(promise, selfFulfillment());
- } else if (objectOrFunction(value)) {
- handleMaybeThenable(promise, value, getThen(value));
- } else {
- fulfill(promise, value);
- }
-}
-
-function publishRejection(promise) {
- if (promise._onerror) {
- promise._onerror(promise._result);
- }
-
- publish(promise);
-}
-
-function fulfill(promise, value) {
- if (promise._state !== PENDING) {
- return;
- }
-
- promise._result = value;
- promise._state = FULFILLED;
-
- if (promise._subscribers.length !== 0) {
- asap(publish, promise);
- }
-}
-
-function _reject(promise, reason) {
- if (promise._state !== PENDING) {
- return;
- }
- promise._state = REJECTED;
- promise._result = reason;
-
- asap(publishRejection, promise);
-}
-
-function subscribe(parent, child, onFulfillment, onRejection) {
- var _subscribers = parent._subscribers;
- var length = _subscribers.length;
-
- parent._onerror = null;
-
- _subscribers[length] = child;
- _subscribers[length + FULFILLED] = onFulfillment;
- _subscribers[length + REJECTED] = onRejection;
-
- if (length === 0 && parent._state) {
- asap(publish, parent);
- }
-}
-
-function publish(promise) {
- var subscribers = promise._subscribers;
- var settled = promise._state;
-
- if (subscribers.length === 0) {
- return;
- }
-
- var child = undefined,
- callback = undefined,
- detail = promise._result;
-
- for (var i = 0; i < subscribers.length; i += 3) {
- child = subscribers[i];
- callback = subscribers[i + settled];
-
- if (child) {
- invokeCallback(settled, child, callback, detail);
- } else {
- callback(detail);
- }
- }
-
- promise._subscribers.length = 0;
-}
-
-function ErrorObject() {
- this.error = null;
-}
-
-var TRY_CATCH_ERROR = new ErrorObject();
-
-function tryCatch(callback, detail) {
- try {
- return callback(detail);
- } catch (e) {
- TRY_CATCH_ERROR.error = e;
- return TRY_CATCH_ERROR;
- }
-}
-
-function invokeCallback(settled, promise, callback, detail) {
- var hasCallback = isFunction(callback),
- value = undefined,
- error = undefined,
- succeeded = undefined,
- failed = undefined;
-
- if (hasCallback) {
- value = tryCatch(callback, detail);
-
- if (value === TRY_CATCH_ERROR) {
- failed = true;
- error = value.error;
- value = null;
- } else {
- succeeded = true;
- }
-
- if (promise === value) {
- _reject(promise, cannotReturnOwn());
- return;
- }
- } else {
- value = detail;
- succeeded = true;
- }
-
- if (promise._state !== PENDING) {
- // noop
- } else if (hasCallback && succeeded) {
- _resolve(promise, value);
- } else if (failed) {
- _reject(promise, error);
- } else if (settled === FULFILLED) {
- fulfill(promise, value);
- } else if (settled === REJECTED) {
- _reject(promise, value);
- }
-}
-
-function initializePromise(promise, resolver) {
- try {
- resolver(function resolvePromise(value) {
- _resolve(promise, value);
- }, function rejectPromise(reason) {
- _reject(promise, reason);
- });
- } catch (e) {
- _reject(promise, e);
- }
-}
-
-var id = 0;
-function nextId() {
- return id++;
-}
-
-function makePromise(promise) {
- promise[PROMISE_ID] = id++;
- promise._state = undefined;
- promise._result = undefined;
- promise._subscribers = [];
-}
-
-function Enumerator(Constructor, input) {
- this._instanceConstructor = Constructor;
- this.promise = new Constructor(noop);
-
- if (!this.promise[PROMISE_ID]) {
- makePromise(this.promise);
- }
-
- if (isArray(input)) {
- this._input = input;
- this.length = input.length;
- this._remaining = input.length;
-
- this._result = new Array(this.length);
-
- if (this.length === 0) {
- fulfill(this.promise, this._result);
- } else {
- this.length = this.length || 0;
- this._enumerate();
- if (this._remaining === 0) {
- fulfill(this.promise, this._result);
- }
- }
- } else {
- _reject(this.promise, validationError());
- }
-}
-
-function validationError() {
- return new Error('Array Methods must be provided an Array');
-};
-
-Enumerator.prototype._enumerate = function () {
- var length = this.length;
- var _input = this._input;
-
- for (var i = 0; this._state === PENDING && i < length; i++) {
- this._eachEntry(_input[i], i);
- }
-};
-
-Enumerator.prototype._eachEntry = function (entry, i) {
- var c = this._instanceConstructor;
- var resolve$$ = c.resolve;
-
- if (resolve$$ === resolve) {
- var _then = getThen(entry);
-
- if (_then === then && entry._state !== PENDING) {
- this._settledAt(entry._state, i, entry._result);
- } else if (typeof _then !== 'function') {
- this._remaining--;
- this._result[i] = entry;
- } else if (c === Promise) {
- var promise = new c(noop);
- handleMaybeThenable(promise, entry, _then);
- this._willSettleAt(promise, i);
- } else {
- this._willSettleAt(new c(function (resolve$$) {
- return resolve$$(entry);
- }), i);
- }
- } else {
- this._willSettleAt(resolve$$(entry), i);
- }
-};
-
-Enumerator.prototype._settledAt = function (state, i, value) {
- var promise = this.promise;
-
- if (promise._state === PENDING) {
- this._remaining--;
-
- if (state === REJECTED) {
- _reject(promise, value);
- } else {
- this._result[i] = value;
- }
- }
-
- if (this._remaining === 0) {
- fulfill(promise, this._result);
- }
-};
-
-Enumerator.prototype._willSettleAt = function (promise, i) {
- var enumerator = this;
-
- subscribe(promise, undefined, function (value) {
- return enumerator._settledAt(FULFILLED, i, value);
- }, function (reason) {
- return enumerator._settledAt(REJECTED, i, reason);
- });
-};
-
-/**
- `Promise.all` accepts an array of promises, and returns a new promise which
- is fulfilled with an array of fulfillment values for the passed promises, or
- rejected with the reason of the first passed promise to be rejected. It casts all
- elements of the passed iterable to promises as it runs this algorithm.
-
- Example:
-
- ```javascript
- let promise1 = resolve(1);
- let promise2 = resolve(2);
- let promise3 = resolve(3);
- let promises = [ promise1, promise2, promise3 ];
-
- Promise.all(promises).then(function(array){
- // The array here would be [ 1, 2, 3 ];
- });
- ```
-
- If any of the `promises` given to `all` are rejected, the first promise
- that is rejected will be given as an argument to the returned promises's
- rejection handler. For example:
-
- Example:
-
- ```javascript
- let promise1 = resolve(1);
- let promise2 = reject(new Error("2"));
- let promise3 = reject(new Error("3"));
- let promises = [ promise1, promise2, promise3 ];
-
- Promise.all(promises).then(function(array){
- // Code here never runs because there are rejected promises!
- }, function(error) {
- // error.message === "2"
- });
- ```
-
- @method all
- @static
- @param {Array} entries array of promises
- @param {String} label optional string for labeling the promise.
- Useful for tooling.
- @return {Promise} promise that is fulfilled when all `promises` have been
- fulfilled, or rejected if any of them become rejected.
- @static
-*/
-function all(entries) {
- return new Enumerator(this, entries).promise;
-}
-
-/**
- `Promise.race` returns a new promise which is settled in the same way as the
- first passed promise to settle.
-
- Example:
-
- ```javascript
- let promise1 = new Promise(function(resolve, reject){
- setTimeout(function(){
- resolve('promise 1');
- }, 200);
- });
-
- let promise2 = new Promise(function(resolve, reject){
- setTimeout(function(){
- resolve('promise 2');
- }, 100);
- });
-
- Promise.race([promise1, promise2]).then(function(result){
- // result === 'promise 2' because it was resolved before promise1
- // was resolved.
- });
- ```
-
- `Promise.race` is deterministic in that only the state of the first
- settled promise matters. For example, even if other promises given to the
- `promises` array argument are resolved, but the first settled promise has
- become rejected before the other promises became fulfilled, the returned
- promise will become rejected:
-
- ```javascript
- let promise1 = new Promise(function(resolve, reject){
- setTimeout(function(){
- resolve('promise 1');
- }, 200);
- });
-
- let promise2 = new Promise(function(resolve, reject){
- setTimeout(function(){
- reject(new Error('promise 2'));
- }, 100);
- });
-
- Promise.race([promise1, promise2]).then(function(result){
- // Code here never runs
- }, function(reason){
- // reason.message === 'promise 2' because promise 2 became rejected before
- // promise 1 became fulfilled
- });
- ```
-
- An example real-world use case is implementing timeouts:
-
- ```javascript
- Promise.race([ajax('foo.json'), timeout(5000)])
- ```
-
- @method race
- @static
- @param {Array} promises array of promises to observe
- Useful for tooling.
- @return {Promise} a promise which settles in the same way as the first passed
- promise to settle.
-*/
-function race(entries) {
- /*jshint validthis:true */
- var Constructor = this;
-
- if (!isArray(entries)) {
- return new Constructor(function (_, reject) {
- return reject(new TypeError('You must pass an array to race.'));
- });
- } else {
- return new Constructor(function (resolve, reject) {
- var length = entries.length;
- for (var i = 0; i < length; i++) {
- Constructor.resolve(entries[i]).then(resolve, reject);
- }
- });
- }
-}
-
-/**
- `Promise.reject` returns a promise rejected with the passed `reason`.
- It is shorthand for the following:
-
- ```javascript
- let promise = new Promise(function(resolve, reject){
- reject(new Error('WHOOPS'));
- });
-
- promise.then(function(value){
- // Code here doesn't run because the promise is rejected!
- }, function(reason){
- // reason.message === 'WHOOPS'
- });
- ```
-
- Instead of writing the above, your code now simply becomes the following:
-
- ```javascript
- let promise = Promise.reject(new Error('WHOOPS'));
-
- promise.then(function(value){
- // Code here doesn't run because the promise is rejected!
- }, function(reason){
- // reason.message === 'WHOOPS'
- });
- ```
-
- @method reject
- @static
- @param {Any} reason value that the returned promise will be rejected with.
- Useful for tooling.
- @return {Promise} a promise rejected with the given `reason`.
-*/
-function reject(reason) {
- /*jshint validthis:true */
- var Constructor = this;
- var promise = new Constructor(noop);
- _reject(promise, reason);
- return promise;
-}
-
-function needsResolver() {
- throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
-}
-
-function needsNew() {
- throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
-}
-
-/**
- Promise objects represent the eventual result of an asynchronous operation. The
- primary way of interacting with a promise is through its `then` method, which
- registers callbacks to receive either a promise's eventual value or the reason
- why the promise cannot be fulfilled.
-
- Terminology
- -----------
-
- - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- - `thenable` is an object or function that defines a `then` method.
- - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- - `exception` is a value that is thrown using the throw statement.
- - `reason` is a value that indicates why a promise was rejected.
- - `settled` the final resting state of a promise, fulfilled or rejected.
-
- A promise can be in one of three states: pending, fulfilled, or rejected.
-
- Promises that are fulfilled have a fulfillment value and are in the fulfilled
- state. Promises that are rejected have a rejection reason and are in the
- rejected state. A fulfillment value is never a thenable.
-
- Promises can also be said to *resolve* a value. If this value is also a
- promise, then the original promise's settled state will match the value's
- settled state. So a promise that *resolves* a promise that rejects will
- itself reject, and a promise that *resolves* a promise that fulfills will
- itself fulfill.
-
-
- Basic Usage:
- ------------
-
- ```js
- let promise = new Promise(function(resolve, reject) {
- // on success
- resolve(value);
-
- // on failure
- reject(reason);
- });
-
- promise.then(function(value) {
- // on fulfillment
- }, function(reason) {
- // on rejection
- });
- ```
-
- Advanced Usage:
- ---------------
-
- Promises shine when abstracting away asynchronous interactions such as
- `XMLHttpRequest`s.
-
- ```js
- function getJSON(url) {
- return new Promise(function(resolve, reject){
- let xhr = new XMLHttpRequest();
-
- xhr.open('GET', url);
- xhr.onreadystatechange = handler;
- xhr.responseType = 'json';
- xhr.setRequestHeader('Accept', 'application/json');
- xhr.send();
-
- function handler() {
- if (this.readyState === this.DONE) {
- if (this.status === 200) {
- resolve(this.response);
- } else {
- reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
- }
- }
- };
- });
- }
-
- getJSON('/posts.json').then(function(json) {
- // on fulfillment
- }, function(reason) {
- // on rejection
- });
- ```
-
- Unlike callbacks, promises are great composable primitives.
-
- ```js
- Promise.all([
- getJSON('/posts'),
- getJSON('/comments')
- ]).then(function(values){
- values[0] // => postsJSON
- values[1] // => commentsJSON
-
- return values;
- });
- ```
-
- @class Promise
- @param {function} resolver
- Useful for tooling.
- @constructor
-*/
-function Promise(resolver) {
- this[PROMISE_ID] = nextId();
- this._result = this._state = undefined;
- this._subscribers = [];
-
- if (noop !== resolver) {
- typeof resolver !== 'function' && needsResolver();
- this instanceof Promise ? initializePromise(this, resolver) : needsNew();
- }
-}
-
-Promise.all = all;
-Promise.race = race;
-Promise.resolve = resolve;
-Promise.reject = reject;
-Promise._setScheduler = setScheduler;
-Promise._setAsap = setAsap;
-Promise._asap = asap;
-
-Promise.prototype = {
- constructor: Promise,
-
- /**
- The primary way of interacting with a promise is through its `then` method,
- which registers callbacks to receive either a promise's eventual value or the
- reason why the promise cannot be fulfilled.
-
- ```js
- findUser().then(function(user){
- // user is available
- }, function(reason){
- // user is unavailable, and you are given the reason why
- });
- ```
-
- Chaining
- --------
-
- The return value of `then` is itself a promise. This second, 'downstream'
- promise is resolved with the return value of the first promise's fulfillment
- or rejection handler, or rejected if the handler throws an exception.
-
- ```js
- findUser().then(function (user) {
- return user.name;
- }, function (reason) {
- return 'default name';
- }).then(function (userName) {
- // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
- // will be `'default name'`
- });
-
- findUser().then(function (user) {
- throw new Error('Found user, but still unhappy');
- }, function (reason) {
- throw new Error('`findUser` rejected and we're unhappy');
- }).then(function (value) {
- // never reached
- }, function (reason) {
- // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
- // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
- });
- ```
- If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
-
- ```js
- findUser().then(function (user) {
- throw new PedagogicalException('Upstream error');
- }).then(function (value) {
- // never reached
- }).then(function (value) {
- // never reached
- }, function (reason) {
- // The `PedgagocialException` is propagated all the way down to here
- });
- ```
-
- Assimilation
- ------------
-
- Sometimes the value you want to propagate to a downstream promise can only be
- retrieved asynchronously. This can be achieved by returning a promise in the
- fulfillment or rejection handler. The downstream promise will then be pending
- until the returned promise is settled. This is called *assimilation*.
-
- ```js
- findUser().then(function (user) {
- return findCommentsByAuthor(user);
- }).then(function (comments) {
- // The user's comments are now available
- });
- ```
-
- If the assimliated promise rejects, then the downstream promise will also reject.
-
- ```js
- findUser().then(function (user) {
- return findCommentsByAuthor(user);
- }).then(function (comments) {
- // If `findCommentsByAuthor` fulfills, we'll have the value here
- }, function (reason) {
- // If `findCommentsByAuthor` rejects, we'll have the reason here
- });
- ```
-
- Simple Example
- --------------
-
- Synchronous Example
-
- ```javascript
- let result;
-
- try {
- result = findResult();
- // success
- } catch(reason) {
- // failure
- }
- ```
-
- Errback Example
-
- ```js
- findResult(function(result, err){
- if (err) {
- // failure
- } else {
- // success
- }
- });
- ```
-
- Promise Example;
-
- ```javascript
- findResult().then(function(result){
- // success
- }, function(reason){
- // failure
- });
- ```
-
- Advanced Example
- --------------
-
- Synchronous Example
-
- ```javascript
- let author, books;
-
- try {
- author = findAuthor();
- books = findBooksByAuthor(author);
- // success
- } catch(reason) {
- // failure
- }
- ```
-
- Errback Example
-
- ```js
-
- function foundBooks(books) {
-
- }
-
- function failure(reason) {
-
- }
-
- findAuthor(function(author, err){
- if (err) {
- failure(err);
- // failure
- } else {
- try {
- findBoooksByAuthor(author, function(books, err) {
- if (err) {
- failure(err);
- } else {
- try {
- foundBooks(books);
- } catch(reason) {
- failure(reason);
- }
- }
- });
- } catch(error) {
- failure(err);
- }
- // success
- }
- });
- ```
-
- Promise Example;
-
- ```javascript
- findAuthor().
- then(findBooksByAuthor).
- then(function(books){
- // found books
- }).catch(function(reason){
- // something went wrong
- });
- ```
-
- @method then
- @param {Function} onFulfilled
- @param {Function} onRejected
- Useful for tooling.
- @return {Promise}
- */
- then: then,
-
- /**
- `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
- as the catch block of a try/catch statement.
-
- ```js
- function findAuthor(){
- throw new Error('couldn't find that author');
- }
-
- // synchronous
- try {
- findAuthor();
- } catch(reason) {
- // something went wrong
- }
-
- // async with promises
- findAuthor().catch(function(reason){
- // something went wrong
- });
- ```
-
- @method catch
- @param {Function} onRejection
- Useful for tooling.
- @return {Promise}
- */
- 'catch': function _catch(onRejection) {
- return this.then(null, onRejection);
- }
-};
-
-function polyfill() {
- var local = undefined;
-
- if (typeof global !== 'undefined') {
- local = global;
- } else if (typeof self !== 'undefined') {
- local = self;
- } else {
- try {
- local = Function('return this')();
- } catch (e) {
- throw new Error('polyfill failed because global object is unavailable in this environment');
- }
- }
-
- var P = local.Promise;
-
- if (P) {
- var promiseToString = null;
- try {
- promiseToString = Object.prototype.toString.call(P.resolve());
- } catch (e) {
- // silently ignored
- }
-
- if (promiseToString === '[object Promise]' && !P.cast) {
- return;
- }
- }
-
- local.Promise = Promise;
-}
-
-// Strange compat..
-Promise.polyfill = polyfill;
-Promise.Promise = Promise;
-
-return Promise;
-
-})));
-
-ES6Promise.polyfill();
-//# sourceMappingURL=es6-promise.auto.map
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5), __webpack_require__(4)))
-
-/***/ },
-
-/***/ 4:
-/***/ function(module, exports) {
-
-var g;
-
-// This works in non-strict mode
-g = (function() { return this; })();
-
-try {
- // This works if eval is allowed (see CSP)
- g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
- // This works if the window reference is available
- if(typeof window === "object")
- g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
-
-
-/***/ },
-
-/***/ 49:
-/***/ function(module, exports) {
-
-/* (ignored) */
-
-/***/ },
-
-/***/ 5:
-/***/ function(module, exports) {
-
-// shim for using process in browser
-var process = module.exports = {};
-
-// cached from whatever global is present so that test runners that stub it
-// don't break things. But we need to wrap it in a try catch in case it is
-// wrapped in strict mode code which doesn't define any globals. It's inside a
-// function because try/catches deoptimize in certain engines.
-
-var cachedSetTimeout;
-var cachedClearTimeout;
-
-function defaultSetTimout() {
- throw new Error('setTimeout has not been defined');
-}
-function defaultClearTimeout () {
- throw new Error('clearTimeout has not been defined');
-}
-(function () {
- try {
- if (typeof setTimeout === 'function') {
- cachedSetTimeout = setTimeout;
- } else {
- cachedSetTimeout = defaultSetTimout;
- }
- } catch (e) {
- cachedSetTimeout = defaultSetTimout;
- }
- try {
- if (typeof clearTimeout === 'function') {
- cachedClearTimeout = clearTimeout;
- } else {
- cachedClearTimeout = defaultClearTimeout;
- }
- } catch (e) {
- cachedClearTimeout = defaultClearTimeout;
- }
-} ())
-function runTimeout(fun) {
- if (cachedSetTimeout === setTimeout) {
- //normal enviroments in sane situations
- return setTimeout(fun, 0);
- }
- // if setTimeout wasn't available but was latter defined
- if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
- cachedSetTimeout = setTimeout;
- return setTimeout(fun, 0);
- }
- try {
- // when when somebody has screwed with setTimeout but no I.E. maddness
- return cachedSetTimeout(fun, 0);
- } catch(e){
- try {
- // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
- return cachedSetTimeout.call(null, fun, 0);
- } catch(e){
- // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
- return cachedSetTimeout.call(this, fun, 0);
- }
- }
-
-
-}
-function runClearTimeout(marker) {
- if (cachedClearTimeout === clearTimeout) {
- //normal enviroments in sane situations
- return clearTimeout(marker);
- }
- // if clearTimeout wasn't available but was latter defined
- if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
- cachedClearTimeout = clearTimeout;
- return clearTimeout(marker);
- }
- try {
- // when when somebody has screwed with setTimeout but no I.E. maddness
- return cachedClearTimeout(marker);
- } catch (e){
- try {
- // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
- return cachedClearTimeout.call(null, marker);
- } catch (e){
- // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
- // Some versions of I.E. have different rules for clearTimeout vs setTimeout
- return cachedClearTimeout.call(this, marker);
- }
- }
-
-
-
-}
-var queue = [];
-var draining = false;
-var currentQueue;
-var queueIndex = -1;
-
-function cleanUpNextTick() {
- if (!draining || !currentQueue) {
- return;
- }
- draining = false;
- if (currentQueue.length) {
- queue = currentQueue.concat(queue);
- } else {
- queueIndex = -1;
- }
- if (queue.length) {
- drainQueue();
- }
-}
-
-function drainQueue() {
- if (draining) {
- return;
- }
- var timeout = runTimeout(cleanUpNextTick);
- draining = true;
-
- var len = queue.length;
- while(len) {
- currentQueue = queue;
- queue = [];
- while (++queueIndex < len) {
- if (currentQueue) {
- currentQueue[queueIndex].run();
- }
- }
- queueIndex = -1;
- len = queue.length;
- }
- currentQueue = null;
- draining = false;
- runClearTimeout(timeout);
-}
-
-process.nextTick = function (fun) {
- var args = new Array(arguments.length - 1);
- if (arguments.length > 1) {
- for (var i = 1; i < arguments.length; i++) {
- args[i - 1] = arguments[i];
- }
- }
- queue.push(new Item(fun, args));
- if (queue.length === 1 && !draining) {
- runTimeout(drainQueue);
- }
-};
-
-// v8 likes predictible objects
-function Item(fun, array) {
- this.fun = fun;
- this.array = array;
-}
-Item.prototype.run = function () {
- this.fun.apply(null, this.array);
-};
-process.title = 'browser';
-process.browser = true;
-process.env = {};
-process.argv = [];
-process.version = ''; // empty string to avoid regexp issues
-process.versions = {};
-
-function noop() {}
-
-process.on = noop;
-process.addListener = noop;
-process.once = noop;
-process.off = noop;
-process.removeListener = noop;
-process.removeAllListeners = noop;
-process.emit = noop;
-
-process.binding = function (name) {
- throw new Error('process.binding is not supported');
-};
-
-process.cwd = function () { return '/' };
-process.chdir = function (dir) {
- throw new Error('process.chdir is not supported');
-};
-process.umask = function() { return 0; };
-
-
-/***/ },
-
-/***/ 51:
-/***/ function(module, exports, __webpack_require__) {
-
-__webpack_require__(16);
-module.exports = __webpack_require__(15);
-
-
-/***/ }
-
-/******/ })
-});
-;
-//# sourceMappingURL=polyfills.js.map
\ No newline at end of file
diff --git a/dist/polyfills.js.map b/dist/polyfills.js.map
deleted file mode 100644
index e91b0ba..0000000
--- a/dist/polyfills.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["webpack:///webpack/universalModuleDefinition?5ca6","webpack:///webpack/bootstrap 62784d0a706852d180f0?e3e7","webpack:///./libs/url/url.js","webpack:///./~/es6-promise/dist/es6-promise.auto.js","webpack:///(webpack)/buildin/global.js?3698","webpack:///vertx (ignored)","webpack:///./~/process/browser.js?82e4"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA,YAAI;AACJ;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;AC9DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC;AACtC,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,aAAa;AACb;AACA,aAAa;AACb;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,mBAAmB;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;;;;;;;uDChnBD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,CAAC,qBAAqB;;AAEtB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,iFAAiF;;AAEjF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,0BAA0B,sBAAsB;;AAEhD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA,CAAC;AACD;AACA,CAAC;AACD;AACA,CAAC;AACD;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA,UAAU,IAAI;AACd;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,iBAAiB,wBAAwB;AACzC;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,iBAAiB,uCAAuC;AACxD;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;AACA;AACA,UAAU,MAAM;AAChB,UAAU,OAAO;AACjB;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,UAAU,MAAM;AAChB;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA,qBAAqB,YAAY;AACjC;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;AACA;AACA,UAAU,IAAI;AACd;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA,UAAU,SAAS;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,eAAe;AACf;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;;AAEA;AACA,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB;AACA,aAAa;AACb;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA,YAAY,SAAS;AACrB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,CAAC;;AAED;AACA,yC;;;;;;;;ACtoCA;;AAEA;AACA,iBAAiB,aAAa,EAAE;;AAEhC;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;;AAEA;AACA;AACA,4CAA4C;;AAE5C;;;;;;;;AClBA,e;;;;;;;ACAA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;AACL;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;;;;AAIA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,sBAAsB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,2BAA2B;AAC3B;AACA;AACA;AACA,4BAA4B,UAAU","file":"polyfills.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ePub\"] = factory();\n\telse\n\t\troot[\"ePub\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmory imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmory exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tObject.defineProperty(exports, name, {\n \t\t\tconfigurable: false,\n \t\t\tenumerable: true,\n \t\t\tget: getter\n \t\t});\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/dist/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 51);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 62784d0a706852d180f0","/* Any copyright is dedicated to the Public Domain.\n * http://creativecommons.org/publicdomain/zero/1.0/ */\n'use strict';\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define([], factory);\n } else if (typeof module === 'object' && module.exports) {\n // Node\n module.exports = factory(global);\n } else {\n // Browser globals (root is window)\n root.URL = factory(root);\n }\n}(this, function (scope) {\n\n // feature detect for URL constructor\n var hasWorkingUrl = false;\n if (!scope.forceJURL) {\n try {\n var u = new URL('b', 'http://a');\n u.pathname = 'c%20d';\n hasWorkingUrl = u.href === 'http://a/c%20d';\n } catch(e) {}\n }\n\n if (hasWorkingUrl)\n return scope.URL;\n\n var relative = Object.create(null);\n relative['ftp'] = 21;\n relative['file'] = 0;\n relative['gopher'] = 70;\n relative['http'] = 80;\n relative['https'] = 443;\n relative['ws'] = 80;\n relative['wss'] = 443;\n\n var relativePathDotMapping = Object.create(null);\n relativePathDotMapping['%2e'] = '.';\n relativePathDotMapping['.%2e'] = '..';\n relativePathDotMapping['%2e.'] = '..';\n relativePathDotMapping['%2e%2e'] = '..';\n\n function isRelativeScheme(scheme) {\n return relative[scheme] !== undefined;\n }\n\n function invalid() {\n clear.call(this);\n this._isInvalid = true;\n }\n\n function IDNAToASCII(h) {\n if ('' == h) {\n invalid.call(this)\n }\n // XXX\n return h.toLowerCase()\n }\n\n function percentEscape(c) {\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ? `\n [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n function percentEscapeQuery(c) {\n // XXX This actually needs to encode c using encoding and then\n // convert the bytes one-by-one.\n\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ` (do not escape '?')\n [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n var EOF = undefined,\n ALPHA = /[a-zA-Z]/,\n ALPHANUMERIC = /[a-zA-Z0-9\\+\\-\\.]/;\n\n function parse(input, stateOverride, base) {\n function err(message) {\n errors.push(message)\n }\n\n var state = stateOverride || 'scheme start',\n cursor = 0,\n buffer = '',\n seenAt = false,\n seenBracket = false,\n errors = [];\n\n loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {\n var c = input[cursor];\n switch (state) {\n case 'scheme start':\n if (c && ALPHA.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n state = 'scheme';\n } else if (!stateOverride) {\n buffer = '';\n state = 'no scheme';\n continue;\n } else {\n err('Invalid scheme.');\n break loop;\n }\n break;\n\n case 'scheme':\n if (c && ALPHANUMERIC.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n } else if (':' == c) {\n this._scheme = buffer;\n buffer = '';\n if (stateOverride) {\n break loop;\n }\n if (isRelativeScheme(this._scheme)) {\n this._isRelative = true;\n }\n if ('file' == this._scheme) {\n state = 'relative';\n } else if (this._isRelative && base && base._scheme == this._scheme) {\n state = 'relative or authority';\n } else if (this._isRelative) {\n state = 'authority first slash';\n } else {\n state = 'scheme data';\n }\n } else if (!stateOverride) {\n buffer = '';\n cursor = 0;\n state = 'no scheme';\n continue;\n } else if (EOF == c) {\n break loop;\n } else {\n err('Code point not allowed in scheme: ' + c)\n break loop;\n }\n break;\n\n case 'scheme data':\n if ('?' == c) {\n this._query = '?';\n state = 'query';\n } else if ('#' == c) {\n this._fragment = '#';\n state = 'fragment';\n } else {\n // XXX error handling\n if (EOF != c && '\\t' != c && '\\n' != c && '\\r' != c) {\n this._schemeData += percentEscape(c);\n }\n }\n break;\n\n case 'no scheme':\n if (!base || !(isRelativeScheme(base._scheme))) {\n err('Missing scheme.');\n invalid.call(this);\n } else {\n state = 'relative';\n continue;\n }\n break;\n\n case 'relative or authority':\n if ('/' == c && '/' == input[cursor+1]) {\n state = 'authority ignore slashes';\n } else {\n err('Expected /, got: ' + c);\n state = 'relative';\n continue\n }\n break;\n\n case 'relative':\n this._isRelative = true;\n if ('file' != this._scheme)\n this._scheme = base._scheme;\n if (EOF == c) {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._username = base._username;\n this._password = base._password;\n break loop;\n } else if ('/' == c || '\\\\' == c) {\n if ('\\\\' == c)\n err('\\\\ is an invalid code point.');\n state = 'relative slash';\n } else if ('?' == c) {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = '?';\n this._username = base._username;\n this._password = base._password;\n state = 'query';\n } else if ('#' == c) {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._fragment = '#';\n this._username = base._username;\n this._password = base._password;\n state = 'fragment';\n } else {\n var nextC = input[cursor+1]\n var nextNextC = input[cursor+2]\n if (\n 'file' != this._scheme || !ALPHA.test(c) ||\n (nextC != ':' && nextC != '|') ||\n (EOF != nextNextC && '/' != nextNextC && '\\\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n this._path = base._path.slice();\n this._path.pop();\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'relative slash':\n if ('/' == c || '\\\\' == c) {\n if ('\\\\' == c) {\n err('\\\\ is an invalid code point.');\n }\n if ('file' == this._scheme) {\n state = 'file host';\n } else {\n state = 'authority ignore slashes';\n }\n } else {\n if ('file' != this._scheme) {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'authority first slash':\n if ('/' == c) {\n state = 'authority second slash';\n } else {\n err(\"Expected '/', got: \" + c);\n state = 'authority ignore slashes';\n continue;\n }\n break;\n\n case 'authority second slash':\n state = 'authority ignore slashes';\n if ('/' != c) {\n err(\"Expected '/', got: \" + c);\n continue;\n }\n break;\n\n case 'authority ignore slashes':\n if ('/' != c && '\\\\' != c) {\n state = 'authority';\n continue;\n } else {\n err('Expected authority, got: ' + c);\n }\n break;\n\n case 'authority':\n if ('@' == c) {\n if (seenAt) {\n err('@ already seen.');\n buffer += '%40';\n }\n seenAt = true;\n for (var i = 0; i < buffer.length; i++) {\n var cp = buffer[i];\n if ('\\t' == cp || '\\n' == cp || '\\r' == cp) {\n err('Invalid whitespace in authority.');\n continue;\n }\n // XXX check URL code points\n if (':' == cp && null === this._password) {\n this._password = '';\n continue;\n }\n var tempC = percentEscape(cp);\n (null !== this._password) ? this._password += tempC : this._username += tempC;\n }\n buffer = '';\n } else if (EOF == c || '/' == c || '\\\\' == c || '?' == c || '#' == c) {\n cursor -= buffer.length;\n buffer = '';\n state = 'host';\n continue;\n } else {\n buffer += c;\n }\n break;\n\n case 'file host':\n if (EOF == c || '/' == c || '\\\\' == c || '?' == c || '#' == c) {\n if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {\n state = 'relative path';\n } else if (buffer.length == 0) {\n state = 'relative path start';\n } else {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n }\n continue;\n } else if ('\\t' == c || '\\n' == c || '\\r' == c) {\n err('Invalid whitespace in file host.');\n } else {\n buffer += c;\n }\n break;\n\n case 'host':\n case 'hostname':\n if (':' == c && !seenBracket) {\n // XXX host parsing\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'port';\n if ('hostname' == stateOverride) {\n break loop;\n }\n } else if (EOF == c || '/' == c || '\\\\' == c || '?' == c || '#' == c) {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n if (stateOverride) {\n break loop;\n }\n continue;\n } else if ('\\t' != c && '\\n' != c && '\\r' != c) {\n if ('[' == c) {\n seenBracket = true;\n } else if (']' == c) {\n seenBracket = false;\n }\n buffer += c;\n } else {\n err('Invalid code point in host/hostname: ' + c);\n }\n break;\n\n case 'port':\n if (/[0-9]/.test(c)) {\n buffer += c;\n } else if (EOF == c || '/' == c || '\\\\' == c || '?' == c || '#' == c || stateOverride) {\n if ('' != buffer) {\n var temp = parseInt(buffer, 10);\n if (temp != relative[this._scheme]) {\n this._port = temp + '';\n }\n buffer = '';\n }\n if (stateOverride) {\n break loop;\n }\n state = 'relative path start';\n continue;\n } else if ('\\t' == c || '\\n' == c || '\\r' == c) {\n err('Invalid code point in port: ' + c);\n } else {\n invalid.call(this);\n }\n break;\n\n case 'relative path start':\n if ('\\\\' == c)\n err(\"'\\\\' not allowed in path.\");\n state = 'relative path';\n if ('/' != c && '\\\\' != c) {\n continue;\n }\n break;\n\n case 'relative path':\n if (EOF == c || '/' == c || '\\\\' == c || (!stateOverride && ('?' == c || '#' == c))) {\n if ('\\\\' == c) {\n err('\\\\ not allowed in relative path.');\n }\n var tmp;\n if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {\n buffer = tmp;\n }\n if ('..' == buffer) {\n this._path.pop();\n if ('/' != c && '\\\\' != c) {\n this._path.push('');\n }\n } else if ('.' == buffer && '/' != c && '\\\\' != c) {\n this._path.push('');\n } else if ('.' != buffer) {\n if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {\n buffer = buffer[0] + ':';\n }\n this._path.push(buffer);\n }\n buffer = '';\n if ('?' == c) {\n this._query = '?';\n state = 'query';\n } else if ('#' == c) {\n this._fragment = '#';\n state = 'fragment';\n }\n } else if ('\\t' != c && '\\n' != c && '\\r' != c) {\n buffer += percentEscape(c);\n }\n break;\n\n case 'query':\n if (!stateOverride && '#' == c) {\n this._fragment = '#';\n state = 'fragment';\n } else if (EOF != c && '\\t' != c && '\\n' != c && '\\r' != c) {\n this._query += percentEscapeQuery(c);\n }\n break;\n\n case 'fragment':\n if (EOF != c && '\\t' != c && '\\n' != c && '\\r' != c) {\n this._fragment += c;\n }\n break;\n }\n\n cursor++;\n }\n }\n\n function clear() {\n this._scheme = '';\n this._schemeData = '';\n this._username = '';\n this._password = null;\n this._host = '';\n this._port = '';\n this._path = [];\n this._query = '';\n this._fragment = '';\n this._isInvalid = false;\n this._isRelative = false;\n }\n\n // Does not process domain names or IP addresses.\n // Does not handle encoding for the query parameter.\n function jURL(url, base /* , encoding */) {\n if (base !== undefined && !(base instanceof jURL))\n base = new jURL(String(base));\n\n this._url = url;\n clear.call(this);\n\n var input = url.replace(/^[ \\t\\r\\n\\f]+|[ \\t\\r\\n\\f]+$/g, '');\n // encoding = encoding || 'utf-8'\n\n parse.call(this, input, null, base);\n }\n\n jURL.prototype = {\n toString: function() {\n return this.href;\n },\n get href() {\n if (this._isInvalid)\n return this._url;\n\n var authority = '';\n if ('' != this._username || null != this._password) {\n authority = this._username +\n (null != this._password ? ':' + this._password : '') + '@';\n }\n\n return this.protocol +\n (this._isRelative ? '//' + authority + this.host : '') +\n this.pathname + this._query + this._fragment;\n },\n set href(href) {\n clear.call(this);\n parse.call(this, href);\n },\n\n get protocol() {\n return this._scheme + ':';\n },\n set protocol(protocol) {\n if (this._isInvalid)\n return;\n parse.call(this, protocol + ':', 'scheme start');\n },\n\n get host() {\n return this._isInvalid ? '' : this._port ?\n this._host + ':' + this._port : this._host;\n },\n set host(host) {\n if (this._isInvalid || !this._isRelative)\n return;\n parse.call(this, host, 'host');\n },\n\n get hostname() {\n return this._host;\n },\n set hostname(hostname) {\n if (this._isInvalid || !this._isRelative)\n return;\n parse.call(this, hostname, 'hostname');\n },\n\n get port() {\n return this._port;\n },\n set port(port) {\n if (this._isInvalid || !this._isRelative)\n return;\n parse.call(this, port, 'port');\n },\n\n get pathname() {\n return this._isInvalid ? '' : this._isRelative ?\n '/' + this._path.join('/') : this._schemeData;\n },\n set pathname(pathname) {\n if (this._isInvalid || !this._isRelative)\n return;\n this._path = [];\n parse.call(this, pathname, 'relative path start');\n },\n\n get search() {\n return this._isInvalid || !this._query || '?' == this._query ?\n '' : this._query;\n },\n set search(search) {\n if (this._isInvalid || !this._isRelative)\n return;\n this._query = '?';\n if ('?' == search[0])\n search = search.slice(1);\n parse.call(this, search, 'query');\n },\n\n get hash() {\n return this._isInvalid || !this._fragment || '#' == this._fragment ?\n '' : this._fragment;\n },\n set hash(hash) {\n if (this._isInvalid)\n return;\n this._fragment = '#';\n if ('#' == hash[0])\n hash = hash.slice(1);\n parse.call(this, hash, 'fragment');\n },\n\n get origin() {\n var host;\n if (this._isInvalid || !this._scheme) {\n return '';\n }\n // javascript: Gecko returns String(\"\"), WebKit/Blink String(\"null\")\n // Gecko throws error for \"data://\"\n // data: Gecko returns \"\", Blink returns \"data://\", WebKit returns \"null\"\n // Gecko returns String(\"\") for file: mailto:\n // WebKit/Blink returns String(\"SCHEME://\") for file: mailto:\n switch (this._scheme) {\n case 'data':\n case 'file':\n case 'javascript':\n case 'mailto':\n return 'null';\n }\n host = this.host;\n if (!host) {\n return '';\n }\n return this._scheme + '://' + host;\n }\n };\n\n // Copy over the static methods\n var OriginalURL = scope.URL;\n if (OriginalURL) {\n jURL.createObjectURL = function(blob) {\n // IE extension allows a second optional options argument.\n // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx\n return OriginalURL.createObjectURL.apply(OriginalURL, arguments);\n };\n jURL.revokeObjectURL = function(url) {\n OriginalURL.revokeObjectURL(url);\n };\n }\n\n return jURL;\n}));\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./libs/url/url.js\n// module id = 15\n// module chunks = 1","/*!\n * @overview es6-promise - a tiny implementation of Promises/A+.\n * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)\n * @license Licensed under MIT license\n * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE\n * @version 4.0.5\n */\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global.ES6Promise = factory());\n}(this, (function () { 'use strict';\n\nfunction objectOrFunction(x) {\n return typeof x === 'function' || typeof x === 'object' && x !== null;\n}\n\nfunction isFunction(x) {\n return typeof x === 'function';\n}\n\nvar _isArray = undefined;\nif (!Array.isArray) {\n _isArray = function (x) {\n return Object.prototype.toString.call(x) === '[object Array]';\n };\n} else {\n _isArray = Array.isArray;\n}\n\nvar isArray = _isArray;\n\nvar len = 0;\nvar vertxNext = undefined;\nvar customSchedulerFn = undefined;\n\nvar asap = function asap(callback, arg) {\n queue[len] = callback;\n queue[len + 1] = arg;\n len += 2;\n if (len === 2) {\n // If len is 2, that means that we need to schedule an async flush.\n // If additional callbacks are queued before the queue is flushed, they\n // will be processed by this flush that we are scheduling.\n if (customSchedulerFn) {\n customSchedulerFn(flush);\n } else {\n scheduleFlush();\n }\n }\n};\n\nfunction setScheduler(scheduleFn) {\n customSchedulerFn = scheduleFn;\n}\n\nfunction setAsap(asapFn) {\n asap = asapFn;\n}\n\nvar browserWindow = typeof window !== 'undefined' ? window : undefined;\nvar browserGlobal = browserWindow || {};\nvar BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\nvar isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';\n\n// test for web worker but not in IE10\nvar isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';\n\n// node\nfunction useNextTick() {\n // node version 0.10.x displays a deprecation warning when nextTick is used recursively\n // see https://github.com/cujojs/when/issues/410 for details\n return function () {\n return process.nextTick(flush);\n };\n}\n\n// vertx\nfunction useVertxTimer() {\n if (typeof vertxNext !== 'undefined') {\n return function () {\n vertxNext(flush);\n };\n }\n\n return useSetTimeout();\n}\n\nfunction useMutationObserver() {\n var iterations = 0;\n var observer = new BrowserMutationObserver(flush);\n var node = document.createTextNode('');\n observer.observe(node, { characterData: true });\n\n return function () {\n node.data = iterations = ++iterations % 2;\n };\n}\n\n// web worker\nfunction useMessageChannel() {\n var channel = new MessageChannel();\n channel.port1.onmessage = flush;\n return function () {\n return channel.port2.postMessage(0);\n };\n}\n\nfunction useSetTimeout() {\n // Store setTimeout reference so es6-promise will be unaffected by\n // other code modifying setTimeout (like sinon.useFakeTimers())\n var globalSetTimeout = setTimeout;\n return function () {\n return globalSetTimeout(flush, 1);\n };\n}\n\nvar queue = new Array(1000);\nfunction flush() {\n for (var i = 0; i < len; i += 2) {\n var callback = queue[i];\n var arg = queue[i + 1];\n\n callback(arg);\n\n queue[i] = undefined;\n queue[i + 1] = undefined;\n }\n\n len = 0;\n}\n\nfunction attemptVertx() {\n try {\n var r = require;\n var vertx = r('vertx');\n vertxNext = vertx.runOnLoop || vertx.runOnContext;\n return useVertxTimer();\n } catch (e) {\n return useSetTimeout();\n }\n}\n\nvar scheduleFlush = undefined;\n// Decide what async method to use to triggering processing of queued callbacks:\nif (isNode) {\n scheduleFlush = useNextTick();\n} else if (BrowserMutationObserver) {\n scheduleFlush = useMutationObserver();\n} else if (isWorker) {\n scheduleFlush = useMessageChannel();\n} else if (browserWindow === undefined && typeof require === 'function') {\n scheduleFlush = attemptVertx();\n} else {\n scheduleFlush = useSetTimeout();\n}\n\nfunction then(onFulfillment, onRejection) {\n var _arguments = arguments;\n\n var parent = this;\n\n var child = new this.constructor(noop);\n\n if (child[PROMISE_ID] === undefined) {\n makePromise(child);\n }\n\n var _state = parent._state;\n\n if (_state) {\n (function () {\n var callback = _arguments[_state - 1];\n asap(function () {\n return invokeCallback(_state, child, callback, parent._result);\n });\n })();\n } else {\n subscribe(parent, child, onFulfillment, onRejection);\n }\n\n return child;\n}\n\n/**\n `Promise.resolve` returns a promise that will become resolved with the\n passed `value`. It is shorthand for the following:\n\n ```javascript\n let promise = new Promise(function(resolve, reject){\n resolve(1);\n });\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = Promise.resolve(1);\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n @method resolve\n @static\n @param {Any} value value that the returned promise will be resolved with\n Useful for tooling.\n @return {Promise} a promise that will become fulfilled with the given\n `value`\n*/\nfunction resolve(object) {\n /*jshint validthis:true */\n var Constructor = this;\n\n if (object && typeof object === 'object' && object.constructor === Constructor) {\n return object;\n }\n\n var promise = new Constructor(noop);\n _resolve(promise, object);\n return promise;\n}\n\nvar PROMISE_ID = Math.random().toString(36).substring(16);\n\nfunction noop() {}\n\nvar PENDING = void 0;\nvar FULFILLED = 1;\nvar REJECTED = 2;\n\nvar GET_THEN_ERROR = new ErrorObject();\n\nfunction selfFulfillment() {\n return new TypeError(\"You cannot resolve a promise with itself\");\n}\n\nfunction cannotReturnOwn() {\n return new TypeError('A promises callback cannot return that same promise.');\n}\n\nfunction getThen(promise) {\n try {\n return promise.then;\n } catch (error) {\n GET_THEN_ERROR.error = error;\n return GET_THEN_ERROR;\n }\n}\n\nfunction tryThen(then, value, fulfillmentHandler, rejectionHandler) {\n try {\n then.call(value, fulfillmentHandler, rejectionHandler);\n } catch (e) {\n return e;\n }\n}\n\nfunction handleForeignThenable(promise, thenable, then) {\n asap(function (promise) {\n var sealed = false;\n var error = tryThen(then, thenable, function (value) {\n if (sealed) {\n return;\n }\n sealed = true;\n if (thenable !== value) {\n _resolve(promise, value);\n } else {\n fulfill(promise, value);\n }\n }, function (reason) {\n if (sealed) {\n return;\n }\n sealed = true;\n\n _reject(promise, reason);\n }, 'Settle: ' + (promise._label || ' unknown promise'));\n\n if (!sealed && error) {\n sealed = true;\n _reject(promise, error);\n }\n }, promise);\n}\n\nfunction handleOwnThenable(promise, thenable) {\n if (thenable._state === FULFILLED) {\n fulfill(promise, thenable._result);\n } else if (thenable._state === REJECTED) {\n _reject(promise, thenable._result);\n } else {\n subscribe(thenable, undefined, function (value) {\n return _resolve(promise, value);\n }, function (reason) {\n return _reject(promise, reason);\n });\n }\n}\n\nfunction handleMaybeThenable(promise, maybeThenable, then$$) {\n if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {\n handleOwnThenable(promise, maybeThenable);\n } else {\n if (then$$ === GET_THEN_ERROR) {\n _reject(promise, GET_THEN_ERROR.error);\n } else if (then$$ === undefined) {\n fulfill(promise, maybeThenable);\n } else if (isFunction(then$$)) {\n handleForeignThenable(promise, maybeThenable, then$$);\n } else {\n fulfill(promise, maybeThenable);\n }\n }\n}\n\nfunction _resolve(promise, value) {\n if (promise === value) {\n _reject(promise, selfFulfillment());\n } else if (objectOrFunction(value)) {\n handleMaybeThenable(promise, value, getThen(value));\n } else {\n fulfill(promise, value);\n }\n}\n\nfunction publishRejection(promise) {\n if (promise._onerror) {\n promise._onerror(promise._result);\n }\n\n publish(promise);\n}\n\nfunction fulfill(promise, value) {\n if (promise._state !== PENDING) {\n return;\n }\n\n promise._result = value;\n promise._state = FULFILLED;\n\n if (promise._subscribers.length !== 0) {\n asap(publish, promise);\n }\n}\n\nfunction _reject(promise, reason) {\n if (promise._state !== PENDING) {\n return;\n }\n promise._state = REJECTED;\n promise._result = reason;\n\n asap(publishRejection, promise);\n}\n\nfunction subscribe(parent, child, onFulfillment, onRejection) {\n var _subscribers = parent._subscribers;\n var length = _subscribers.length;\n\n parent._onerror = null;\n\n _subscribers[length] = child;\n _subscribers[length + FULFILLED] = onFulfillment;\n _subscribers[length + REJECTED] = onRejection;\n\n if (length === 0 && parent._state) {\n asap(publish, parent);\n }\n}\n\nfunction publish(promise) {\n var subscribers = promise._subscribers;\n var settled = promise._state;\n\n if (subscribers.length === 0) {\n return;\n }\n\n var child = undefined,\n callback = undefined,\n detail = promise._result;\n\n for (var i = 0; i < subscribers.length; i += 3) {\n child = subscribers[i];\n callback = subscribers[i + settled];\n\n if (child) {\n invokeCallback(settled, child, callback, detail);\n } else {\n callback(detail);\n }\n }\n\n promise._subscribers.length = 0;\n}\n\nfunction ErrorObject() {\n this.error = null;\n}\n\nvar TRY_CATCH_ERROR = new ErrorObject();\n\nfunction tryCatch(callback, detail) {\n try {\n return callback(detail);\n } catch (e) {\n TRY_CATCH_ERROR.error = e;\n return TRY_CATCH_ERROR;\n }\n}\n\nfunction invokeCallback(settled, promise, callback, detail) {\n var hasCallback = isFunction(callback),\n value = undefined,\n error = undefined,\n succeeded = undefined,\n failed = undefined;\n\n if (hasCallback) {\n value = tryCatch(callback, detail);\n\n if (value === TRY_CATCH_ERROR) {\n failed = true;\n error = value.error;\n value = null;\n } else {\n succeeded = true;\n }\n\n if (promise === value) {\n _reject(promise, cannotReturnOwn());\n return;\n }\n } else {\n value = detail;\n succeeded = true;\n }\n\n if (promise._state !== PENDING) {\n // noop\n } else if (hasCallback && succeeded) {\n _resolve(promise, value);\n } else if (failed) {\n _reject(promise, error);\n } else if (settled === FULFILLED) {\n fulfill(promise, value);\n } else if (settled === REJECTED) {\n _reject(promise, value);\n }\n}\n\nfunction initializePromise(promise, resolver) {\n try {\n resolver(function resolvePromise(value) {\n _resolve(promise, value);\n }, function rejectPromise(reason) {\n _reject(promise, reason);\n });\n } catch (e) {\n _reject(promise, e);\n }\n}\n\nvar id = 0;\nfunction nextId() {\n return id++;\n}\n\nfunction makePromise(promise) {\n promise[PROMISE_ID] = id++;\n promise._state = undefined;\n promise._result = undefined;\n promise._subscribers = [];\n}\n\nfunction Enumerator(Constructor, input) {\n this._instanceConstructor = Constructor;\n this.promise = new Constructor(noop);\n\n if (!this.promise[PROMISE_ID]) {\n makePromise(this.promise);\n }\n\n if (isArray(input)) {\n this._input = input;\n this.length = input.length;\n this._remaining = input.length;\n\n this._result = new Array(this.length);\n\n if (this.length === 0) {\n fulfill(this.promise, this._result);\n } else {\n this.length = this.length || 0;\n this._enumerate();\n if (this._remaining === 0) {\n fulfill(this.promise, this._result);\n }\n }\n } else {\n _reject(this.promise, validationError());\n }\n}\n\nfunction validationError() {\n return new Error('Array Methods must be provided an Array');\n};\n\nEnumerator.prototype._enumerate = function () {\n var length = this.length;\n var _input = this._input;\n\n for (var i = 0; this._state === PENDING && i < length; i++) {\n this._eachEntry(_input[i], i);\n }\n};\n\nEnumerator.prototype._eachEntry = function (entry, i) {\n var c = this._instanceConstructor;\n var resolve$$ = c.resolve;\n\n if (resolve$$ === resolve) {\n var _then = getThen(entry);\n\n if (_then === then && entry._state !== PENDING) {\n this._settledAt(entry._state, i, entry._result);\n } else if (typeof _then !== 'function') {\n this._remaining--;\n this._result[i] = entry;\n } else if (c === Promise) {\n var promise = new c(noop);\n handleMaybeThenable(promise, entry, _then);\n this._willSettleAt(promise, i);\n } else {\n this._willSettleAt(new c(function (resolve$$) {\n return resolve$$(entry);\n }), i);\n }\n } else {\n this._willSettleAt(resolve$$(entry), i);\n }\n};\n\nEnumerator.prototype._settledAt = function (state, i, value) {\n var promise = this.promise;\n\n if (promise._state === PENDING) {\n this._remaining--;\n\n if (state === REJECTED) {\n _reject(promise, value);\n } else {\n this._result[i] = value;\n }\n }\n\n if (this._remaining === 0) {\n fulfill(promise, this._result);\n }\n};\n\nEnumerator.prototype._willSettleAt = function (promise, i) {\n var enumerator = this;\n\n subscribe(promise, undefined, function (value) {\n return enumerator._settledAt(FULFILLED, i, value);\n }, function (reason) {\n return enumerator._settledAt(REJECTED, i, reason);\n });\n};\n\n/**\n `Promise.all` accepts an array of promises, and returns a new promise which\n is fulfilled with an array of fulfillment values for the passed promises, or\n rejected with the reason of the first passed promise to be rejected. It casts all\n elements of the passed iterable to promises as it runs this algorithm.\n\n Example:\n\n ```javascript\n let promise1 = resolve(1);\n let promise2 = resolve(2);\n let promise3 = resolve(3);\n let promises = [ promise1, promise2, promise3 ];\n\n Promise.all(promises).then(function(array){\n // The array here would be [ 1, 2, 3 ];\n });\n ```\n\n If any of the `promises` given to `all` are rejected, the first promise\n that is rejected will be given as an argument to the returned promises's\n rejection handler. For example:\n\n Example:\n\n ```javascript\n let promise1 = resolve(1);\n let promise2 = reject(new Error(\"2\"));\n let promise3 = reject(new Error(\"3\"));\n let promises = [ promise1, promise2, promise3 ];\n\n Promise.all(promises).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(error) {\n // error.message === \"2\"\n });\n ```\n\n @method all\n @static\n @param {Array} entries array of promises\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when all `promises` have been\n fulfilled, or rejected if any of them become rejected.\n @static\n*/\nfunction all(entries) {\n return new Enumerator(this, entries).promise;\n}\n\n/**\n `Promise.race` returns a new promise which is settled in the same way as the\n first passed promise to settle.\n\n Example:\n\n ```javascript\n let promise1 = new Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 2');\n }, 100);\n });\n\n Promise.race([promise1, promise2]).then(function(result){\n // result === 'promise 2' because it was resolved before promise1\n // was resolved.\n });\n ```\n\n `Promise.race` is deterministic in that only the state of the first\n settled promise matters. For example, even if other promises given to the\n `promises` array argument are resolved, but the first settled promise has\n become rejected before the other promises became fulfilled, the returned\n promise will become rejected:\n\n ```javascript\n let promise1 = new Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new Promise(function(resolve, reject){\n setTimeout(function(){\n reject(new Error('promise 2'));\n }, 100);\n });\n\n Promise.race([promise1, promise2]).then(function(result){\n // Code here never runs\n }, function(reason){\n // reason.message === 'promise 2' because promise 2 became rejected before\n // promise 1 became fulfilled\n });\n ```\n\n An example real-world use case is implementing timeouts:\n\n ```javascript\n Promise.race([ajax('foo.json'), timeout(5000)])\n ```\n\n @method race\n @static\n @param {Array} promises array of promises to observe\n Useful for tooling.\n @return {Promise} a promise which settles in the same way as the first passed\n promise to settle.\n*/\nfunction race(entries) {\n /*jshint validthis:true */\n var Constructor = this;\n\n if (!isArray(entries)) {\n return new Constructor(function (_, reject) {\n return reject(new TypeError('You must pass an array to race.'));\n });\n } else {\n return new Constructor(function (resolve, reject) {\n var length = entries.length;\n for (var i = 0; i < length; i++) {\n Constructor.resolve(entries[i]).then(resolve, reject);\n }\n });\n }\n}\n\n/**\n `Promise.reject` returns a promise rejected with the passed `reason`.\n It is shorthand for the following:\n\n ```javascript\n let promise = new Promise(function(resolve, reject){\n reject(new Error('WHOOPS'));\n });\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = Promise.reject(new Error('WHOOPS'));\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n @method reject\n @static\n @param {Any} reason value that the returned promise will be rejected with.\n Useful for tooling.\n @return {Promise} a promise rejected with the given `reason`.\n*/\nfunction reject(reason) {\n /*jshint validthis:true */\n var Constructor = this;\n var promise = new Constructor(noop);\n _reject(promise, reason);\n return promise;\n}\n\nfunction needsResolver() {\n throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n}\n\nfunction needsNew() {\n throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n}\n\n/**\n Promise objects represent the eventual result of an asynchronous operation. The\n primary way of interacting with a promise is through its `then` method, which\n registers callbacks to receive either a promise's eventual value or the reason\n why the promise cannot be fulfilled.\n\n Terminology\n -----------\n\n - `promise` is an object or function with a `then` method whose behavior conforms to this specification.\n - `thenable` is an object or function that defines a `then` method.\n - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).\n - `exception` is a value that is thrown using the throw statement.\n - `reason` is a value that indicates why a promise was rejected.\n - `settled` the final resting state of a promise, fulfilled or rejected.\n\n A promise can be in one of three states: pending, fulfilled, or rejected.\n\n Promises that are fulfilled have a fulfillment value and are in the fulfilled\n state. Promises that are rejected have a rejection reason and are in the\n rejected state. A fulfillment value is never a thenable.\n\n Promises can also be said to *resolve* a value. If this value is also a\n promise, then the original promise's settled state will match the value's\n settled state. So a promise that *resolves* a promise that rejects will\n itself reject, and a promise that *resolves* a promise that fulfills will\n itself fulfill.\n\n\n Basic Usage:\n ------------\n\n ```js\n let promise = new Promise(function(resolve, reject) {\n // on success\n resolve(value);\n\n // on failure\n reject(reason);\n });\n\n promise.then(function(value) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Advanced Usage:\n ---------------\n\n Promises shine when abstracting away asynchronous interactions such as\n `XMLHttpRequest`s.\n\n ```js\n function getJSON(url) {\n return new Promise(function(resolve, reject){\n let xhr = new XMLHttpRequest();\n\n xhr.open('GET', url);\n xhr.onreadystatechange = handler;\n xhr.responseType = 'json';\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send();\n\n function handler() {\n if (this.readyState === this.DONE) {\n if (this.status === 200) {\n resolve(this.response);\n } else {\n reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));\n }\n }\n };\n });\n }\n\n getJSON('/posts.json').then(function(json) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Unlike callbacks, promises are great composable primitives.\n\n ```js\n Promise.all([\n getJSON('/posts'),\n getJSON('/comments')\n ]).then(function(values){\n values[0] // => postsJSON\n values[1] // => commentsJSON\n\n return values;\n });\n ```\n\n @class Promise\n @param {function} resolver\n Useful for tooling.\n @constructor\n*/\nfunction Promise(resolver) {\n this[PROMISE_ID] = nextId();\n this._result = this._state = undefined;\n this._subscribers = [];\n\n if (noop !== resolver) {\n typeof resolver !== 'function' && needsResolver();\n this instanceof Promise ? initializePromise(this, resolver) : needsNew();\n }\n}\n\nPromise.all = all;\nPromise.race = race;\nPromise.resolve = resolve;\nPromise.reject = reject;\nPromise._setScheduler = setScheduler;\nPromise._setAsap = setAsap;\nPromise._asap = asap;\n\nPromise.prototype = {\n constructor: Promise,\n\n /**\n The primary way of interacting with a promise is through its `then` method,\n which registers callbacks to receive either a promise's eventual value or the\n reason why the promise cannot be fulfilled.\n \n ```js\n findUser().then(function(user){\n // user is available\n }, function(reason){\n // user is unavailable, and you are given the reason why\n });\n ```\n \n Chaining\n --------\n \n The return value of `then` is itself a promise. This second, 'downstream'\n promise is resolved with the return value of the first promise's fulfillment\n or rejection handler, or rejected if the handler throws an exception.\n \n ```js\n findUser().then(function (user) {\n return user.name;\n }, function (reason) {\n return 'default name';\n }).then(function (userName) {\n // If `findUser` fulfilled, `userName` will be the user's name, otherwise it\n // will be `'default name'`\n });\n \n findUser().then(function (user) {\n throw new Error('Found user, but still unhappy');\n }, function (reason) {\n throw new Error('`findUser` rejected and we're unhappy');\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.\n // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.\n });\n ```\n If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.\n \n ```js\n findUser().then(function (user) {\n throw new PedagogicalException('Upstream error');\n }).then(function (value) {\n // never reached\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // The `PedgagocialException` is propagated all the way down to here\n });\n ```\n \n Assimilation\n ------------\n \n Sometimes the value you want to propagate to a downstream promise can only be\n retrieved asynchronously. This can be achieved by returning a promise in the\n fulfillment or rejection handler. The downstream promise will then be pending\n until the returned promise is settled. This is called *assimilation*.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // The user's comments are now available\n });\n ```\n \n If the assimliated promise rejects, then the downstream promise will also reject.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // If `findCommentsByAuthor` fulfills, we'll have the value here\n }, function (reason) {\n // If `findCommentsByAuthor` rejects, we'll have the reason here\n });\n ```\n \n Simple Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let result;\n \n try {\n result = findResult();\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n findResult(function(result, err){\n if (err) {\n // failure\n } else {\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findResult().then(function(result){\n // success\n }, function(reason){\n // failure\n });\n ```\n \n Advanced Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let author, books;\n \n try {\n author = findAuthor();\n books = findBooksByAuthor(author);\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n \n function foundBooks(books) {\n \n }\n \n function failure(reason) {\n \n }\n \n findAuthor(function(author, err){\n if (err) {\n failure(err);\n // failure\n } else {\n try {\n findBoooksByAuthor(author, function(books, err) {\n if (err) {\n failure(err);\n } else {\n try {\n foundBooks(books);\n } catch(reason) {\n failure(reason);\n }\n }\n });\n } catch(error) {\n failure(err);\n }\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findAuthor().\n then(findBooksByAuthor).\n then(function(books){\n // found books\n }).catch(function(reason){\n // something went wrong\n });\n ```\n \n @method then\n @param {Function} onFulfilled\n @param {Function} onRejected\n Useful for tooling.\n @return {Promise}\n */\n then: then,\n\n /**\n `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same\n as the catch block of a try/catch statement.\n \n ```js\n function findAuthor(){\n throw new Error('couldn't find that author');\n }\n \n // synchronous\n try {\n findAuthor();\n } catch(reason) {\n // something went wrong\n }\n \n // async with promises\n findAuthor().catch(function(reason){\n // something went wrong\n });\n ```\n \n @method catch\n @param {Function} onRejection\n Useful for tooling.\n @return {Promise}\n */\n 'catch': function _catch(onRejection) {\n return this.then(null, onRejection);\n }\n};\n\nfunction polyfill() {\n var local = undefined;\n\n if (typeof global !== 'undefined') {\n local = global;\n } else if (typeof self !== 'undefined') {\n local = self;\n } else {\n try {\n local = Function('return this')();\n } catch (e) {\n throw new Error('polyfill failed because global object is unavailable in this environment');\n }\n }\n\n var P = local.Promise;\n\n if (P) {\n var promiseToString = null;\n try {\n promiseToString = Object.prototype.toString.call(P.resolve());\n } catch (e) {\n // silently ignored\n }\n\n if (promiseToString === '[object Promise]' && !P.cast) {\n return;\n }\n }\n\n local.Promise = Promise;\n}\n\n// Strange compat..\nPromise.polyfill = polyfill;\nPromise.Promise = Promise;\n\nreturn Promise;\n\n})));\n\nES6Promise.polyfill();\n//# sourceMappingURL=es6-promise.auto.map\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/es6-promise/dist/es6-promise.auto.js\n// module id = 16\n// module chunks = 1","var g;\r\n\r\n// This works in non-strict mode\r\ng = (function() { return this; })();\r\n\r\ntry {\r\n\t// This works if eval is allowed (see CSP)\r\n\tg = g || Function(\"return this\")() || (1,eval)(\"this\");\r\n} catch(e) {\r\n\t// This works if the window reference is available\r\n\tif(typeof window === \"object\")\r\n\t\tg = window;\r\n}\r\n\r\n// g can still be undefined, but nothing to do about it...\r\n// We return undefined, instead of nothing here, so it's\r\n// easier to handle this case. if(!global) { ...}\r\n\r\nmodule.exports = g;\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// (webpack)/buildin/global.js\n// module id = 4\n// module chunks = 0 1","/* (ignored) */\n\n\n//////////////////\n// WEBPACK FOOTER\n// vertx (ignored)\n// module id = 49\n// module chunks = 1","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/process/browser.js\n// module id = 5\n// module chunks = 0 1"],"sourceRoot":""}
\ No newline at end of file
diff --git a/dist/polyfills.min.js b/dist/polyfills.min.js
deleted file mode 100644
index 4cf4a2e..0000000
--- a/dist/polyfills.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ePub=e():t.ePub=e()}(this,function(){return function(t){function e(n){if(i[n])return i[n].exports;var r=i[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var i={};return e.m=t,e.c=i,e.i=function(t){return t},e.d=function(t,e,i){Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var i=t&&t.__esModule?function(){return t["default"]}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/dist/",e(e.s=51)}({15:function(t,e,i){"use strict";var n,r,s;!function(i,o){r=[],n=o,s="function"==typeof n?n.apply(e,r):n,!(void 0!==s&&(t.exports=s))}(this,function(t){function e(t){return void 0!==f[t]}function i(){a.call(this),this._isInvalid=!0}function n(t){return""==t&&i.call(this),t.toLowerCase()}function r(t){var e=t.charCodeAt(0);return e>32&&e<127&&[34,35,60,62,63,96].indexOf(e)==-1?t:encodeURIComponent(t)}function s(t){var e=t.charCodeAt(0);return e>32&&e<127&&[34,35,60,62,96].indexOf(e)==-1?t:encodeURIComponent(t)}function o(t,o,a){function c(t){y.push(t)}var h=o||"scheme start",u=0,l="",m=!1,b=!1,y=[];t:for(;(t[u-1]!=p||0==u)&&!this._isInvalid;){var g=t[u];switch(h){case"scheme start":if(!g||!v.test(g)){if(o){c("Invalid scheme.");break t}l="",h="no scheme";continue}l+=g.toLowerCase(),h="scheme";break;case"scheme":if(g&&d.test(g))l+=g.toLowerCase();else{if(":"!=g){if(o){if(p==g)break t;c("Code point not allowed in scheme: "+g);break t}l="",u=0,h="no scheme";continue}if(this._scheme=l,l="",o)break t;e(this._scheme)&&(this._isRelative=!0),h="file"==this._scheme?"relative":this._isRelative&&a&&a._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==g?(this._query="?",h="query"):"#"==g?(this._fragment="#",h="fragment"):p!=g&&"\t"!=g&&"\n"!=g&&"\r"!=g&&(this._schemeData+=r(g));break;case"no scheme":if(a&&e(a._scheme)){h="relative";continue}c("Missing scheme."),i.call(this);break;case"relative or authority":if("/"!=g||"/"!=t[u+1]){c("Expected /, got: "+g),h="relative";continue}h="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=a._scheme),p==g){this._host=a._host,this._port=a._port,this._path=a._path.slice(),this._query=a._query,this._username=a._username,this._password=a._password;break t}if("/"==g||"\\"==g)"\\"==g&&c("\\ is an invalid code point."),h="relative slash";else if("?"==g)this._host=a._host,this._port=a._port,this._path=a._path.slice(),this._query="?",this._username=a._username,this._password=a._password,h="query";else{if("#"!=g){var w=t[u+1],j=t[u+2];("file"!=this._scheme||!v.test(g)||":"!=w&&"|"!=w||p!=j&&"/"!=j&&"\\"!=j&&"?"!=j&&"#"!=j)&&(this._host=a._host,this._port=a._port,this._username=a._username,this._password=a._password,this._path=a._path.slice(),this._path.pop()),h="relative path";continue}this._host=a._host,this._port=a._port,this._path=a._path.slice(),this._query=a._query,this._fragment="#",this._username=a._username,this._password=a._password,h="fragment"}break;case"relative slash":if("/"!=g&&"\\"!=g){"file"!=this._scheme&&(this._host=a._host,this._port=a._port,this._username=a._username,this._password=a._password),h="relative path";continue}"\\"==g&&c("\\ is an invalid code point."),h="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=g){c("Expected '/', got: "+g),h="authority ignore slashes";continue}h="authority second slash";break;case"authority second slash":if(h="authority ignore slashes","/"!=g){c("Expected '/', got: "+g);continue}break;case"authority ignore slashes":if("/"!=g&&"\\"!=g){h="authority";continue}c("Expected authority, got: "+g);break;case"authority":if("@"==g){m&&(c("@ already seen."),l+="%40"),m=!0;for(var O=0;O1)for(var i=1;i {
+ var err = new Error("Cannot load book at "+ url );
+ console.error(err);
+ this.emit("openFailed", err);
+ console.log(error);
+ });
+ }
};
- this.loaded = {
- manifest: this.loading.manifest.promise,
- spine: this.loading.spine.promise,
- metadata: this.loading.metadata.promise,
- cover: this.loading.cover.promise,
- navigation: this.loading.navigation.promise,
- pageList: this.loading.pageList.promise,
- resources: this.loading.resources.promise
+ /**
+ * Open a epub or url
+ * @param {string} input URL, Path or ArrayBuffer
+ * @param {string} [what] to force opening
+ * @returns {Promise} of when the book has been loaded
+ * @example book.open("/path/to/book.epub")
+ */
+ open(input, what) {
+ var opening;
+ var type = what || this.determineType(input);
+
+ if (type === "binary") {
+ this.archived = true;
+ this.url = new Url("/", "");
+ opening = this.openEpub(input);
+ } else if (type === "epub") {
+ this.archived = true;
+ this.url = new Url("/", "");
+ opening = this.request(input, 'binary')
+ .then(this.openEpub.bind(this));
+ } else if(type == "opf") {
+ this.url = new Url(input);
+ opening = this.openPackaging(this.url.Path.toString());
+ } else {
+ this.url = new Url(input);
+ opening = this.openContainer(CONTAINER_PATH)
+ .then(this.openPackaging.bind(this));
+ }
+
+ return opening;
+ }
+
+ /**
+ * Open an archived epub
+ * @private
+ * @param {binary} data
+ * @param {[string]} encoding
+ * @return {Promise}
+ */
+ openEpub(data, encoding) {
+ return this.unarchive(data, encoding || this.settings.encoding)
+ .then(() => {
+ return this.openContainer(CONTAINER_PATH);
+ })
+ .then((packagePath) => {
+ return this.openPackaging(packagePath);
+ });
+ }
+
+ /**
+ * Open the epub container
+ * @private
+ * @param {string} url
+ * @return {string} packagePath
+ */
+ openContainer(url) {
+ return this.load(url)
+ .then((xml) => {
+ this.container = new Container(xml);
+ return this.resolve(this.container.packagePath);
+ });
+ }
+
+ /**
+ * Open the Open Packaging Format Xml
+ * @private
+ * @param {string} url
+ * @return {Promise}
+ */
+ openPackaging(url) {
+ var packageUrl;
+ this.path = new Path(url);
+ return this.load(url)
+ .then((xml) => {
+ this.packaging = new Packaging(xml);
+ return this.unpack(this.packaging);
+ });
+ }
+
+ /**
+ * Load a resource from the Book
+ * @param {string} path path to the resource to load
+ * @return {Promise} returns a promise with the requested resource
+ */
+ load(path) {
+ var resolved;
+
+ if(this.archived) {
+ resolved = this.resolve(path);
+ return this.archive.request(resolved);
+ } else {
+ resolved = this.resolve(path);
+ return this.request(resolved, null, this.settings.requestCredentials, this.settings.requestHeaders);
+ }
+ }
+
+ /**
+ * Resolve a path to it's absolute position in the Book
+ * @param {string} path
+ * @param {[boolean]} absolute force resolving the full URL
+ * @return {string} the resolved path string
+ */
+ resolve(path, absolute) {
+ var resolved = path;
+ var isAbsolute = (path.indexOf('://') > -1);
+
+ if (isAbsolute) {
+ return path;
+ }
+
+ if (this.path) {
+ resolved = this.path.resolve(path);
+ }
+
+ if(absolute != false && this.url) {
+ resolved = this.url.resolve(resolved);
+ }
+
+ return resolved;
+ }
+
+ /**
+ * Determine the type of they input passed to open
+ * @private
+ * @param {string} input
+ * @return {string} binary | directory | epub | opf
+ */
+ determineType(input) {
+ var url;
+ var path;
+ var extension;
+
+ if (typeof(input) != "string") {
+ return "binary";
+ }
+
+ url = new Url(input);
+ path = url.path();
+ extension = path.extension;
+
+ if (!extension) {
+ return "directory";
+ }
+
+ if(extension === "epub"){
+ return "epub";
+ }
+
+ if(extension === "opf"){
+ return "opf";
+ }
};
- // this.ready = RSVP.hash(this.loaded);
+
/**
- * @property {promise} ready returns after the book is loaded and parsed
+ * unpack the contents of the Books packageXml
* @private
+ * @param {document} packageXml XML Document
*/
- this.ready = Promise.all([this.loaded.manifest,
- this.loaded.spine,
- this.loaded.metadata,
- this.loaded.cover,
- this.loaded.navigation,
- this.loaded.resources ]);
+ unpack(opf) {
+ this.package = opf;
+
+ this.spine.unpack(this.package, this.resolve.bind(this));
+
+ this.resources = new Resources(this.package.manifest, {
+ archive: this.archive,
+ resolver: this.resolve.bind(this),
+ replacements: this.settings.replacements
+ });
+
+ this.loadNavigation(this.package).then(() => {
+ this.toc = this.navigation.toc;
+ this.loading.navigation.resolve(this.navigation);
+ });
+
+ this.cover = this.resolve(this.package.coverPath);
+
+ // Resolve promises
+ this.loading.manifest.resolve(this.package.manifest);
+ this.loading.metadata.resolve(this.package.metadata);
+ this.loading.spine.resolve(this.spine);
+ this.loading.cover.resolve(this.cover);
+ this.loading.resources.resolve(this.resources);
+ this.loading.pageList.resolve(this.pageList);
- // Queue for methods used before opening
- this.isRendered = false;
- // this._q = core.queue(this);
+ this.isOpen = true;
- /**
- * @property {method} request
- * @private
- */
- this.request = this.settings.requestMethod || request;
-
- /**
- * @property {Spine} spine
- */
- this.spine = new Spine();
-
- /**
- * @property {Locations} locations
- */
- this.locations = new Locations(this.spine, this.load.bind(this));
-
- /**
- * @property {Navigation} navigation
- */
- this.navigation = undefined;
-
- /**
- * @property {PageList} pagelist
- */
- this.pageList = new PageList();
-
- /**
- * @property {Url} url
- * @private
- */
- this.url = undefined;
-
- /**
- * @property {Path} path
- * @private
- */
- this.path = undefined;
-
- /**
- * @property {boolean} archived
- * @private
- */
- this.archived = false;
-
- if(url) {
- this.open(url).catch(function (error) {
- var err = new Error("Cannot load book at "+ url );
- console.error(err);
- this.emit("openFailed", err);
- console.log(error);
- }.bind(this));
- }
-};
-
-/**
- * Open a epub or url
- * @param {string} input URL, Path or ArrayBuffer
- * @param {string} [what] to force opening
- * @returns {Promise} of when the book has been loaded
- * @example book.open("/path/to/book.epub")
- */
-Book.prototype.open = function(input, what){
- var opening;
- var type = what || this.determineType(input);
-
- if (type === "binary") {
- this.archived = true;
- this.url = new Url("/", "");
- opening = this.openEpub(input);
- } else if (type === "epub") {
- this.archived = true;
- this.url = new Url("/", "");
- opening = this.request(input, 'binary')
- .then(this.openEpub.bind(this));
- } else if(type == "opf") {
- this.url = new Url(input);
- opening = this.openPackaging(this.url.Path.toString());
- } else {
- this.url = new Url(input);
- opening = this.openContainer(CONTAINER_PATH)
- .then(this.openPackaging.bind(this));
- }
-
- return opening;
-};
-
-/**
- * Open an archived epub
- * @private
- * @param {binary} data
- * @param {[string]} encoding
- * @return {Promise}
- */
-Book.prototype.openEpub = function(data, encoding){
- return this.unarchive(data, encoding || this.settings.encoding)
- .then(function() {
- return this.openContainer(CONTAINER_PATH);
- }.bind(this))
- .then(function(packagePath) {
- return this.openPackaging(packagePath);
- }.bind(this));
-};
-
-/**
- * Open the epub container
- * @private
- * @param {string} url
- * @return {string} packagePath
- */
-Book.prototype.openContainer = function(url){
- return this.load(url)
- .then(function(xml) {
- this.container = new Container(xml);
- return this.resolve(this.container.packagePath);
- }.bind(this));
-};
-
-/**
- * Open the Open Packaging Format Xml
- * @private
- * @param {string} url
- * @return {Promise}
- */
-Book.prototype.openPackaging = function(url){
- var packageUrl;
- this.path = new Path(url);
- return this.load(url)
- .then(function(xml) {
- this.packaging = new Packaging(xml);
- return this.unpack(this.packaging);
- }.bind(this));
-};
-
-/**
- * Load a resource from the Book
- * @param {string} path path to the resource to load
- * @return {Promise} returns a promise with the requested resource
- */
-Book.prototype.load = function (path) {
- var resolved;
-
- if(this.archived) {
- resolved = this.resolve(path);
- return this.archive.request(resolved);
- } else {
- resolved = this.resolve(path);
- return this.request(resolved, null, this.settings.requestCredentials, this.settings.requestHeaders);
- }
-};
-
-/**
- * Resolve a path to it's absolute position in the Book
- * @param {string} path
- * @param {[boolean]} absolute force resolving the full URL
- * @return {string} the resolved path string
- */
-Book.prototype.resolve = function (path, absolute) {
- var resolved = path;
- var isAbsolute = (path.indexOf('://') > -1);
-
- if (isAbsolute) {
- return path;
- }
-
- if (this.path) {
- resolved = this.path.resolve(path);
- }
-
- if(absolute != false && this.url) {
- resolved = this.url.resolve(resolved);
- }
-
- return resolved;
-}
-
-/**
- * Determine the type of they input passed to open
- * @private
- * @param {string} input
- * @return {string} binary | directory | epub | opf
- */
-Book.prototype.determineType = function(input) {
- var url;
- var path;
- var extension;
-
- if (typeof(input) != "string") {
- return "binary";
- }
-
- url = new Url(input);
- path = url.path();
- extension = path.extension;
-
- if (!extension) {
- return "directory";
- }
-
- if(extension === "epub"){
- return "epub";
- }
-
- if(extension === "opf"){
- return "opf";
- }
-};
-
-
-/**
- * unpack the contents of the Books packageXml
- * @private
- * @param {document} packageXml XML Document
- */
-Book.prototype.unpack = function(opf){
- this.package = opf;
-
- this.spine.unpack(this.package, this.resolve.bind(this));
-
- this.resources = new Resources(this.package.manifest, {
- archive: this.archive,
- resolver: this.resolve.bind(this),
- replacements: this.settings.replacements
- });
-
- this.loadNavigation(this.package).then(function(){
- this.toc = this.navigation.toc;
- this.loading.navigation.resolve(this.navigation);
- }.bind(this));
-
- this.cover = this.resolve(this.package.coverPath);
-
- // Resolve promises
- this.loading.manifest.resolve(this.package.manifest);
- this.loading.metadata.resolve(this.package.metadata);
- this.loading.spine.resolve(this.spine);
- this.loading.cover.resolve(this.cover);
- this.loading.resources.resolve(this.resources);
- this.loading.pageList.resolve(this.pageList);
-
-
- this.isOpen = true;
-
- if(this.archived) {
- this.replacements().then(function() {
+ if(this.archived) {
+ this.replacements().then(() => {
+ this.opening.resolve(this);
+ });
+ } else {
+ // Resolve book opened promise
this.opening.resolve(this);
- }.bind(this));
- } else {
- // Resolve book opened promise
- this.opening.resolve(this);
+ }
+
}
-};
+ /**
+ * Load Navigation and PageList from package
+ * @private
+ * @param {document} opf XML Document
+ */
+ loadNavigation(opf) {
+ var navPath = opf.navPath || opf.ncxPath;
-/**
- * Load Navigation and PageList from package
- * @private
- * @param {document} opf XML Document
- */
-Book.prototype.loadNavigation = function(opf){
- var navPath = opf.navPath || opf.ncxPath;
+ if (!navPath) {
+ return;
+ }
- if (!navPath) {
- return;
+ return this.load(navPath, 'xml')
+ .then((xml) => {
+ this.navigation = new Navigation(xml);
+ this.pageList = new PageList(xml);
+ return this.navigation;
+ });
}
- return this.load(navPath, 'xml')
- .then(function(xml) {
- this.navigation = new Navigation(xml);
- this.pageList = new PageList(xml);
- return this.navigation;
- }.bind(this));
-};
+ /**
+ * Alias for book.spine.get
+ * @param {string} target
+ */
+ section(target) {
+ return this.spine.get(target);
+ }
-/**
- * Alias for book.spine.get
- * @param {string} target
- */
-Book.prototype.section = function(target) {
- return this.spine.get(target);
-};
+ /**
+ * Sugar to render a book
+ * @param {element} element element to add the views to
+ * @param {[object]} options
+ * @return {Rendition}
+ */
+ renderTo(element, options) {
+ // var renderMethod = (options && options.method) ?
+ // options.method :
+ // "single";
-/**
- * Sugar to render a book
- * @param {element} element element to add the views to
- * @param {[object]} options
- * @return {Rendition}
- */
-Book.prototype.renderTo = function(element, options) {
- // var renderMethod = (options && options.method) ?
- // options.method :
- // "single";
+ this.rendition = new Rendition(this, options);
+ this.rendition.attachTo(element);
- this.rendition = new Rendition(this, options);
- this.rendition.attachTo(element);
+ return this.rendition;
+ };
- return this.rendition;
-};
+ /**
+ * Set if request should use withCredentials
+ * @param {boolean} credentials
+ */
+ setRequestCredentials(credentials) {
+ this.settings.requestCredentials = credentials;
+ };
-/**
- * Set if request should use withCredentials
- * @param {boolean} credentials
- */
-Book.prototype.setRequestCredentials = function(credentials) {
- this.settings.requestCredentials = credentials;
-};
+ /**
+ * Set headers request should use
+ * @param {object} headers
+ */
+ setRequestHeaders(headers) {
+ this.settings.requestHeaders = headers;
+ };
-/**
- * Set headers request should use
- * @param {object} headers
- */
-Book.prototype.setRequestHeaders = function(headers) {
- this.settings.requestHeaders = headers;
-};
+ /**
+ * Unarchive a zipped epub
+ * @private
+ * @param {binary} input epub data
+ * @param {[string]} encoding
+ * @return {Archive}
+ */
+ unarchive(input, encoding) {
+ this.archive = new Archive();
+ return this.archive.open(input, encoding);
+ }
-/**
- * Unarchive a zipped epub
- * @private
- * @param {binary} input epub data
- * @param {[string]} encoding
- * @return {Archive}
- */
-Book.prototype.unarchive = function(input, encoding){
- this.archive = new Archive();
- return this.archive.open(input, encoding);
-};
-
-/**
- * Get the cover url
- * @return {string} coverUrl
- */
-Book.prototype.coverUrl = function(){
- var retrieved = this.loaded.cover.
- then(function(url) {
- if(this.archived) {
- // return this.archive.createUrl(this.cover);
- return this.resources.get(this.cover);
- }else{
- return this.cover;
- }
- }.bind(this));
+ /**
+ * Get the cover url
+ * @return {string} coverUrl
+ */
+ coverUrl() {
+ var retrieved = this.loaded.cover.
+ then((url) => {
+ if(this.archived) {
+ // return this.archive.createUrl(this.cover);
+ return this.resources.get(this.cover);
+ }else{
+ return this.cover;
+ }
+ });
- return retrieved;
-};
+ return retrieved;
+ }
-/**
- * load replacement urls
- * @private
- * @return {Promise} completed loading urls
- */
-Book.prototype.replacements = function(){
- this.spine.hooks.serialize.register(function(output, section) {
- section.output = this.resources.substitute(output, section.url);
- }.bind(this));
+ /**
+ * load replacement urls
+ * @private
+ * @return {Promise} completed loading urls
+ */
+ replacements() {
+ this.spine.hooks.serialize.register((output, section) => {
+ section.output = this.resources.substitute(output, section.url);
+ });
- return this.resources.replacements().
- then(function() {
- return this.resources.replaceCss();
- }.bind(this));
-};
+ return this.resources.replacements().
+ then(() => {
+ return this.resources.replaceCss();
+ });
+ }
-/**
- * Find a DOM Range for a given CFI Range
- * @param {EpubCFI} cfiRange a epub cfi range
- * @return {Range}
- */
-Book.prototype.range = function(cfiRange) {
- var cfi = new EpubCFI(cfiRange);
- var item = this.spine.get(cfi.spinePos);
+ /**
+ * Find a DOM Range for a given CFI Range
+ * @param {EpubCFI} cfiRange a epub cfi range
+ * @return {Range}
+ */
+ range(cfiRange) {
+ var cfi = new EpubCFI(cfiRange);
+ var item = this.spine.get(cfi.spinePos);
- return item.load().then(function (contents) {
- var range = cfi.toRange(item.document);
- return range;
- })
-};
+ return item.load().then(function (contents) {
+ var range = cfi.toRange(item.document);
+ return range;
+ })
+ }
-/**
- * Generates the Book Key using the identifer in the manifest or other string provided
- * @param {[string]} identifier to use instead of metadata identifier
- * @return {string} key
- */
-Book.prototype.key = function(identifier){
- var ident = identifier || this.package.metadata.identifier || this.url.filename;
- return "epubjs:" + (EPUBJS_VERSION || ePub.VERSION) + ":" + ident;
-};
+ /**
+ * Generates the Book Key using the identifer in the manifest or other string provided
+ * @param {[string]} identifier to use instead of metadata identifier
+ * @return {string} key
+ */
+ key(identifier) {
+ var ident = identifier || this.package.metadata.identifier || this.url.filename;
+ return "epubjs:" + (EPUBJS_VERSION || ePub.VERSION) + ":" + ident;
+ }
+
+}
//-- Enable binding events to book
EventEmitter(Book.prototype);
-module.exports = Book;
+export default Book;
diff --git a/src/container.js b/src/container.js
index db70622..df656e1 100644
--- a/src/container.js
+++ b/src/container.js
@@ -1,41 +1,43 @@
-var path = require('path');
-var core = require('./core');
-var EpubCFI = require('./epubcfi');
+import path from 'path-webpack';
+import {qs} from './utils/core';
+import EpubCFI from './epubcfi';
/**
* Handles Parsing and Accessing an Epub Container
* @class
* @param {[document]} containerDocument xml document
*/
-function Container(containerDocument) {
- if (containerDocument) {
- this.parse(containerDocument);
- }
-};
-
-/**
- * Parse the Container XML
- * @param {document} containerDocument
- */
-Container.prototype.parse = function(containerDocument){
- //--
- var rootfile, fullpath, folder, encoding;
-
- if(!containerDocument) {
- console.error("Container File Not Found");
- return;
+class Container {
+ constructor(containerDocument) {
+ if (containerDocument) {
+ this.parse(containerDocument);
}
+ };
- rootfile = core.qs(containerDocument, "rootfile");
+ /**
+ * Parse the Container XML
+ * @param {document} containerDocument
+ */
+ parse(containerDocument){
+ //--
+ var rootfile, fullpath, folder, encoding;
- if(!rootfile) {
- console.error("No RootFile Found");
- return;
- }
+ if(!containerDocument) {
+ console.error("Container File Not Found");
+ return;
+ }
- this.packagePath = rootfile.getAttribute('full-path');
- this.directory = path.dirname(this.packagePath);
- this.encoding = containerDocument.xmlEncoding;
-};
+ rootfile = qs(containerDocument, "rootfile");
-module.exports = Container;
+ if(!rootfile) {
+ console.error("No RootFile Found");
+ return;
+ }
+
+ this.packagePath = rootfile.getAttribute('full-path');
+ this.directory = path.dirname(this.packagePath);
+ this.encoding = containerDocument.xmlEncoding;
+ };
+}
+
+export default Container;
diff --git a/src/contents.js b/src/contents.js
index 4955877..4afc277 100644
--- a/src/contents.js
+++ b/src/contents.js
@@ -1,711 +1,713 @@
-var EventEmitter = require('event-emitter');
-var core = require('./core');
-var EpubCFI = require('./epubcfi');
-var Mapping = require('./mapping');
-
-
-function Contents(doc, content, cfiBase) {
- // Blank Cfi for Parsing
- this.epubcfi = new EpubCFI();
-
- this.document = doc;
- this.documentElement = this.document.documentElement;
- this.content = content || this.document.body;
- this.window = this.document.defaultView;
- // Dom events to listen for
- this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
-
- this._size = {
- width: 0,
- height: 0
- }
-
- this.cfiBase = cfiBase || "";
-
- this.listeners();
-};
-
-Contents.prototype.width = function(w) {
- // var frame = this.documentElement;
- var frame = this.content;
-
- if (w && core.isNumber(w)) {
- w = w + "px";
- }
-
- if (w) {
- frame.style.width = w;
- // this.content.style.width = w;
- }
-
- return this.window.getComputedStyle(frame)['width'];
-
-
-};
-
-Contents.prototype.height = function(h) {
- // var frame = this.documentElement;
- var frame = this.content;
-
- if (h && core.isNumber(h)) {
- h = h + "px";
- }
-
- if (h) {
- frame.style.height = h;
- // this.content.style.height = h;
- }
-
- return this.window.getComputedStyle(frame)['height'];
-
-};
-
-Contents.prototype.contentWidth = function(w) {
-
- var content = this.content || this.document.body;
-
- if (w && core.isNumber(w)) {
- w = w + "px";
- }
-
- if (w) {
- content.style.width = w;
- }
-
- return this.window.getComputedStyle(content)['width'];
-
-
-};
-
-Contents.prototype.contentHeight = function(h) {
-
- var content = this.content || this.document.body;
-
- if (h && core.isNumber(h)) {
- h = h + "px";
- }
-
- if (h) {
- content.style.height = h;
- }
-
- return this.window.getComputedStyle(content)['height'];
-
-};
-
-Contents.prototype.textWidth = function() {
- var width;
- var range = this.document.createRange();
- var content = this.content || this.document.body;
-
- // Select the contents of frame
- range.selectNodeContents(content);
-
- // get the width of the text content
- width = range.getBoundingClientRect().width;
-
- return width;
-
-};
-
-Contents.prototype.textHeight = function() {
- var height;
- var range = this.document.createRange();
- var content = this.content || this.document.body;
-
- range.selectNodeContents(content);
-
- height = range.getBoundingClientRect().height;
-
- return height;
-};
-
-Contents.prototype.scrollWidth = function() {
- var width = this.documentElement.scrollWidth;
-
- return width;
-};
-
-Contents.prototype.scrollHeight = function() {
- var height = this.documentElement.scrollHeight;
-
- return height;
-};
-
-Contents.prototype.overflow = function(overflow) {
-
- if (overflow) {
- this.documentElement.style.overflow = overflow;
- }
-
- return this.window.getComputedStyle(this.documentElement)['overflow'];
-};
-
-Contents.prototype.overflowX = function(overflow) {
-
- if (overflow) {
- this.documentElement.style.overflowX = overflow;
- }
-
- return this.window.getComputedStyle(this.documentElement)['overflowX'];
-};
-
-Contents.prototype.overflowY = function(overflow) {
-
- if (overflow) {
- this.documentElement.style.overflowY = overflow;
- }
-
- return this.window.getComputedStyle(this.documentElement)['overflowY'];
-};
-
-Contents.prototype.css = function(property, value) {
- var content = this.content || this.document.body;
-
- if (value) {
- content.style[property] = value;
- }
-
- return this.window.getComputedStyle(content)[property];
-};
-
-Contents.prototype.viewport = function(options) {
- var width, height, scale, scalable;
- var $viewport = this.document.querySelector("meta[name='viewport']");
- var newContent = '';
-
- /*
- * check for the viewport size
- *
- */
- if($viewport && $viewport.hasAttribute("content")) {
- content = $viewport.getAttribute("content");
- contents = content.split(/\s*,\s*/);
- if(contents[0]){
- width = contents[0].replace("width=", '').trim();
- }
- if(contents[1]){
- height = contents[1].replace("height=", '').trim();
- }
- if(contents[2]){
- scale = contents[2].replace("initial-scale=", '').trim();
- }
- if(contents[3]){
- scalable = contents[3].replace("user-scalable=", '').trim();
- }
- }
-
- if (options) {
-
- newContent += "width=" + (options.width || width);
- newContent += ", height=" + (options.height || height);
- if (options.scale || scale) {
- newContent += ", initial-scale=" + (options.scale || scale);
- }
- if (options.scalable || scalable) {
- newContent += ", user-scalable=" + (options.scalable || scalable);
- }
-
- if (!$viewport) {
- $viewport = this.document.createElement("meta");
- $viewport.setAttribute("name", "viewport");
- this.document.querySelector('head').appendChild($viewport);
- }
-
- $viewport.setAttribute("content", newContent);
- }
-
-
- return {
- width: parseInt(width),
- height: parseInt(height)
- };
-};
-
-
-// Contents.prototype.layout = function(layoutFunc) {
-//
-// this.iframe.style.display = "inline-block";
-//
-// // Reset Body Styles
-// this.content.style.margin = "0";
-// //this.document.body.style.display = "inline-block";
-// //this.document.documentElement.style.width = "auto";
-//
-// if(layoutFunc){
-// layoutFunc(this);
-// }
-//
-// this.onLayout(this);
-//
-// };
-//
-// Contents.prototype.onLayout = function(view) {
-// // stub
-// };
-
-Contents.prototype.expand = function() {
- this.emit("expand");
-};
-
-Contents.prototype.listeners = function() {
-
- this.imageLoadListeners();
-
- this.mediaQueryListeners();
-
- // this.fontLoadListeners();
-
- this.addEventListeners();
-
- this.addSelectionListeners();
-
- this.resizeListeners();
-
-};
-
-Contents.prototype.removeListeners = function() {
-
- this.removeEventListeners();
-
- this.removeSelectionListeners();
-};
-
-Contents.prototype.resizeListeners = function() {
- var width, height;
- // Test size again
- clearTimeout(this.expanding);
-
- width = this.scrollWidth();
- height = this.scrollHeight();
-
- if (width != this._size.width || height != this._size.height) {
+import EventEmitter from 'event-emitter';
+import {isNumber, prefixed} from './utils/core';
+import EpubCFI from './epubcfi';
+import Mapping from './mapping';
+
+
+class Contents {
+ constructor(doc, content, cfiBase) {
+ // Blank Cfi for Parsing
+ this.epubcfi = new EpubCFI();
+
+ this.document = doc;
+ this.documentElement = this.document.documentElement;
+ this.content = content || this.document.body;
+ this.window = this.document.defaultView;
+ // Dom events to listen for
+ this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
this._size = {
- width: width,
- height: height
+ width: 0,
+ height: 0
}
- this.emit("resize", this._size);
- }
+ this.cfiBase = cfiBase || "";
- this.expanding = setTimeout(this.resizeListeners.bind(this), 350);
-};
+ this.listeners();
+ };
-//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js
-Contents.prototype.mediaQueryListeners = function() {
- var sheets = this.document.styleSheets;
- var mediaChangeHandler = function(m){
- if(m.matches && !this._expanding) {
- setTimeout(this.expand.bind(this), 1);
- // this.expand();
+ width(w) {
+ // var frame = this.documentElement;
+ var frame = this.content;
+
+ if (w && isNumber(w)) {
+ w = w + "px";
+ }
+
+ if (w) {
+ frame.style.width = w;
+ // this.content.style.width = w;
+ }
+
+ return this.window.getComputedStyle(frame)['width'];
+
+
+ };
+
+ height(h) {
+ // var frame = this.documentElement;
+ var frame = this.content;
+
+ if (h && isNumber(h)) {
+ h = h + "px";
+ }
+
+ if (h) {
+ frame.style.height = h;
+ // this.content.style.height = h;
+ }
+
+ return this.window.getComputedStyle(frame)['height'];
+
+ };
+
+ contentWidth(w) {
+
+ var content = this.content || this.document.body;
+
+ if (w && isNumber(w)) {
+ w = w + "px";
+ }
+
+ if (w) {
+ content.style.width = w;
+ }
+
+ return this.window.getComputedStyle(content)['width'];
+
+
+ };
+
+ contentHeight(h) {
+
+ var content = this.content || this.document.body;
+
+ if (h && isNumber(h)) {
+ h = h + "px";
+ }
+
+ if (h) {
+ content.style.height = h;
+ }
+
+ return this.window.getComputedStyle(content)['height'];
+
+ };
+
+ textWidth() {
+ var width;
+ var range = this.document.createRange();
+ var content = this.content || this.document.body;
+
+ // Select the contents of frame
+ range.selectNodeContents(content);
+
+ // get the width of the text content
+ width = range.getBoundingClientRect().width;
+
+ return width;
+
+ };
+
+ textHeight() {
+ var height;
+ var range = this.document.createRange();
+ var content = this.content || this.document.body;
+
+ range.selectNodeContents(content);
+
+ height = range.getBoundingClientRect().height;
+
+ return height;
+ };
+
+ scrollWidth() {
+ var width = this.documentElement.scrollWidth;
+
+ return width;
+ };
+
+ scrollHeight() {
+ var height = this.documentElement.scrollHeight;
+
+ return height;
+ };
+
+ overflow(overflow) {
+
+ if (overflow) {
+ this.documentElement.style.overflow = overflow;
+ }
+
+ return this.window.getComputedStyle(this.documentElement)['overflow'];
+ };
+
+ overflowX(overflow) {
+
+ if (overflow) {
+ this.documentElement.style.overflowX = overflow;
+ }
+
+ return this.window.getComputedStyle(this.documentElement)['overflowX'];
+ };
+
+ overflowY(overflow) {
+
+ if (overflow) {
+ this.documentElement.style.overflowY = overflow;
+ }
+
+ return this.window.getComputedStyle(this.documentElement)['overflowY'];
+ };
+
+ css(property, value) {
+ var content = this.content || this.document.body;
+
+ if (value) {
+ content.style[property] = value;
+ }
+
+ return this.window.getComputedStyle(content)[property];
+ };
+
+ viewport(options) {
+ var width, height, scale, scalable;
+ var $viewport = this.document.querySelector("meta[name='viewport']");
+ var newContent = '';
+
+ /*
+ * check for the viewport size
+ *
+ */
+ if($viewport && $viewport.hasAttribute("content")) {
+ content = $viewport.getAttribute("content");
+ contents = content.split(/\s*,\s*/);
+ if(contents[0]){
+ width = contents[0].replace("width=", '').trim();
}
- }.bind(this);
-
- for (var i = 0; i < sheets.length; i += 1) {
- var rules;
- // Firefox errors if we access cssRules cross-domain
- try {
- rules = sheets[i].cssRules;
- } catch (e) {
- return;
- }
- if(!rules) return; // Stylesheets changed
- for (var j = 0; j < rules.length; j += 1) {
- //if (rules[j].constructor === CSSMediaRule) {
- if(rules[j].media){
- var mql = this.window.matchMedia(rules[j].media.mediaText);
- mql.addListener(mediaChangeHandler);
- //mql.onchange = mediaChangeHandler;
- }
- }
- }
-};
-
-Contents.prototype.observe = function(target) {
- var renderer = this;
-
- // create an observer instance
- var observer = new MutationObserver(function(mutations) {
- if(renderer._expanding) {
- renderer.expand();
- }
- // mutations.forEach(function(mutation) {
- // console.log(mutation);
- // });
- });
-
- // configuration of the observer:
- var config = { attributes: true, childList: true, characterData: true, subtree: true };
-
- // pass in the target node, as well as the observer options
- observer.observe(target, config);
-
- return observer;
-};
-
-Contents.prototype.imageLoadListeners = function(target) {
- var images = this.document.querySelectorAll("img");
- var img;
- for (var i = 0; i < images.length; i++) {
- img = images[i];
-
- if (typeof img.naturalWidth !== "undefined" &&
- img.naturalWidth === 0) {
- img.onload = this.expand.bind(this);
- }
- }
-};
-
-Contents.prototype.fontLoadListeners = function(target) {
- if (!this.document || !this.document.fonts) {
- return;
- }
-
- this.document.fonts.ready.then(function () {
- this.expand();
- }.bind(this));
-
-};
-
-Contents.prototype.root = function() {
- if(!this.document) return null;
- return this.document.documentElement;
-};
-
-Contents.prototype.locationOf = function(target, ignoreClass) {
- var position;
- var targetPos = {"left": 0, "top": 0};
-
- if(!this.document) return;
-
- if(this.epubcfi.isCfiString(target)) {
- range = new EpubCFI(target).toRange(this.document, ignoreClass);
-
- if(range) {
- if (range.startContainer.nodeType === Node.ELEMENT_NODE) {
- position = range.startContainer.getBoundingClientRect();
- targetPos.left = position.left;
- targetPos.top = position.top;
- } else {
- // Webkit does not handle collapsed range bounds correctly
- // https://bugs.webkit.org/show_bug.cgi?id=138949
- if (range.collapsed) {
- position = range.getClientRects()[0];
- } else {
- position = range.getBoundingClientRect();
- }
- targetPos.left = position.left;
- targetPos.top = position.top;
+ if(contents[1]){
+ height = contents[1].replace("height=", '').trim();
+ }
+ if(contents[2]){
+ scale = contents[2].replace("initial-scale=", '').trim();
+ }
+ if(contents[3]){
+ scalable = contents[3].replace("user-scalable=", '').trim();
}
}
- } else if(typeof target === "string" &&
- target.indexOf("#") > -1) {
+ if (options) {
- id = target.substring(target.indexOf("#")+1);
- el = this.document.getElementById(id);
+ newContent += "width=" + (options.width || width);
+ newContent += ", height=" + (options.height || height);
+ if (options.scale || scale) {
+ newContent += ", initial-scale=" + (options.scale || scale);
+ }
+ if (options.scalable || scalable) {
+ newContent += ", user-scalable=" + (options.scalable || scalable);
+ }
- if(el) {
- position = el.getBoundingClientRect();
- targetPos.left = position.left;
- targetPos.top = position.top;
+ if (!$viewport) {
+ $viewport = this.document.createElement("meta");
+ $viewport.setAttribute("name", "viewport");
+ this.document.querySelector('head').appendChild($viewport);
+ }
+
+ $viewport.setAttribute("content", newContent);
}
- }
- return targetPos;
-};
-Contents.prototype.addStylesheet = function(src) {
- return new Promise(function(resolve, reject){
- var $stylesheet;
- var ready = false;
+ return {
+ width: parseInt(width),
+ height: parseInt(height)
+ };
+ };
- if(!this.document) {
- resolve(false);
+
+ // layout(layoutFunc) {
+ //
+ // this.iframe.style.display = "inline-block";
+ //
+ // // Reset Body Styles
+ // this.content.style.margin = "0";
+ // //this.document.body.style.display = "inline-block";
+ // //this.document.documentElement.style.width = "auto";
+ //
+ // if(layoutFunc){
+ // layoutFunc(this);
+ // }
+ //
+ // this.onLayout(this);
+ //
+ // };
+ //
+ // onLayout(view) {
+ // // stub
+ // };
+
+ expand() {
+ this.emit("expand");
+ };
+
+ listeners() {
+
+ this.imageLoadListeners();
+
+ this.mediaQueryListeners();
+
+ // this.fontLoadListeners();
+
+ this.addEventListeners();
+
+ this.addSelectionListeners();
+
+ this.resizeListeners();
+
+ };
+
+ removeListeners() {
+
+ this.removeEventListeners();
+
+ this.removeSelectionListeners();
+ };
+
+ resizeListeners() {
+ var width, height;
+ // Test size again
+ clearTimeout(this.expanding);
+
+ width = this.scrollWidth();
+ height = this.scrollHeight();
+
+ if (width != this._size.width || height != this._size.height) {
+
+ this._size = {
+ width: width,
+ height: height
+ }
+
+ this.emit("resize", this._size);
+ }
+
+ this.expanding = setTimeout(this.resizeListeners.bind(this), 350);
+ };
+
+ //https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js
+ mediaQueryListeners() {
+ var sheets = this.document.styleSheets;
+ var mediaChangeHandler = function(m){
+ if(m.matches && !this._expanding) {
+ setTimeout(this.expand.bind(this), 1);
+ // this.expand();
+ }
+ }.bind(this);
+
+ for (var i = 0; i < sheets.length; i += 1) {
+ var rules;
+ // Firefox errors if we access cssRules cross-domain
+ try {
+ rules = sheets[i].cssRules;
+ } catch (e) {
+ return;
+ }
+ if(!rules) return; // Stylesheets changed
+ for (var j = 0; j < rules.length; j += 1) {
+ //if (rules[j].constructor === CSSMediaRule) {
+ if(rules[j].media){
+ var mql = this.window.matchMedia(rules[j].media.mediaText);
+ mql.addListener(mediaChangeHandler);
+ //mql.onchange = mediaChangeHandler;
+ }
+ }
+ }
+ };
+
+ observe(target) {
+ var renderer = this;
+
+ // create an observer instance
+ var observer = new MutationObserver(function(mutations) {
+ if(renderer._expanding) {
+ renderer.expand();
+ }
+ // mutations.forEach(function(mutation) {
+ // console.log(mutation);
+ // });
+ });
+
+ // configuration of the observer:
+ var config = { attributes: true, childList: true, characterData: true, subtree: true };
+
+ // pass in the target node, as well as the observer options
+ observer.observe(target, config);
+
+ return observer;
+ };
+
+ imageLoadListeners(target) {
+ var images = this.document.querySelectorAll("img");
+ var img;
+ for (var i = 0; i < images.length; i++) {
+ img = images[i];
+
+ if (typeof img.naturalWidth !== "undefined" &&
+ img.naturalWidth === 0) {
+ img.onload = this.expand.bind(this);
+ }
+ }
+ };
+
+ fontLoadListeners(target) {
+ if (!this.document || !this.document.fonts) {
return;
}
+ this.document.fonts.ready.then(function () {
+ this.expand();
+ }.bind(this));
+
+ };
+
+ root() {
+ if(!this.document) return null;
+ return this.document.documentElement;
+ };
+
+ locationOf(target, ignoreClass) {
+ var position;
+ var targetPos = {"left": 0, "top": 0};
+
+ if(!this.document) return;
+
+ if(this.epubcfi.isCfiString(target)) {
+ range = new EpubCFI(target).toRange(this.document, ignoreClass);
+
+ if(range) {
+ if (range.startContainer.nodeType === Node.ELEMENT_NODE) {
+ position = range.startContainer.getBoundingClientRect();
+ targetPos.left = position.left;
+ targetPos.top = position.top;
+ } else {
+ // Webkit does not handle collapsed range bounds correctly
+ // https://bugs.webkit.org/show_bug.cgi?id=138949
+ if (range.collapsed) {
+ position = range.getClientRects()[0];
+ } else {
+ position = range.getBoundingClientRect();
+ }
+ targetPos.left = position.left;
+ targetPos.top = position.top;
+ }
+ }
+
+ } else if(typeof target === "string" &&
+ target.indexOf("#") > -1) {
+
+ id = target.substring(target.indexOf("#")+1);
+ el = this.document.getElementById(id);
+
+ if(el) {
+ position = el.getBoundingClientRect();
+ targetPos.left = position.left;
+ targetPos.top = position.top;
+ }
+ }
+
+ return targetPos;
+ };
+
+ addStylesheet(src) {
+ return new Promise(function(resolve, reject){
+ var $stylesheet;
+ var ready = false;
+
+ if(!this.document) {
+ resolve(false);
+ return;
+ }
+
+ // Check if link already exists
+ $stylesheet = this.document.querySelector('link[href="'+src+'"]');
+ if ($stylesheet) {
+ resolve(true);
+ return; // already present
+ }
+
+ $stylesheet = this.document.createElement('link');
+ $stylesheet.type = 'text/css';
+ $stylesheet.rel = "stylesheet";
+ $stylesheet.href = src;
+ $stylesheet.onload = $stylesheet.onreadystatechange = function() {
+ if ( !ready && (!this.readyState || this.readyState == 'complete') ) {
+ ready = true;
+ // Let apply
+ setTimeout(function(){
+ resolve(true);
+ }, 1);
+ }
+ };
+
+ this.document.head.appendChild($stylesheet);
+
+ }.bind(this));
+ };
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
+ addStylesheetRules(rules) {
+ var styleEl;
+ var styleSheet;
+ var key = "epubjs-inserted-css";
+
+ if(!this.document) return;
+
// Check if link already exists
- $stylesheet = this.document.querySelector('link[href="'+src+'"]');
- if ($stylesheet) {
- resolve(true);
- return; // already present
+ styleEl = this.document.getElementById("#"+key);
+ if (!styleEl) {
+ styleEl = this.document.createElement('style');
+ styleEl.id = key;
}
- $stylesheet = this.document.createElement('link');
- $stylesheet.type = 'text/css';
- $stylesheet.rel = "stylesheet";
- $stylesheet.href = src;
- $stylesheet.onload = $stylesheet.onreadystatechange = function() {
- if ( !ready && (!this.readyState || this.readyState == 'complete') ) {
- ready = true;
- // Let apply
- setTimeout(function(){
- resolve(true);
- }, 1);
+ // Append style element to head
+ this.document.head.appendChild(styleEl);
+
+ // Grab style sheet
+ styleSheet = styleEl.sheet;
+
+ for (var i = 0, rl = rules.length; i < rl; i++) {
+ 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 (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
+ rule = rule[1];
+ j = 0;
}
- };
- this.document.head.appendChild($stylesheet);
+ for (var pl = rule.length; j < pl; j++) {
+ var prop = rule[j];
+ propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
+ }
- }.bind(this));
-};
-
-// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
-Contents.prototype.addStylesheetRules = function(rules) {
- var styleEl;
- var styleSheet;
- var key = "epubjs-inserted-css";
-
- if(!this.document) return;
-
- // Check if link already exists
- styleEl = this.document.getElementById("#"+key);
- if (!styleEl) {
- styleEl = this.document.createElement('style');
- styleEl.id = key;
- }
-
- // Append style element to head
- this.document.head.appendChild(styleEl);
-
- // Grab style sheet
- styleSheet = styleEl.sheet;
-
- for (var i = 0, rl = rules.length; i < rl; i++) {
- 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 (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
- rule = rule[1];
- j = 0;
+ // Insert CSS Rule
+ styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);
}
+ };
- for (var pl = rule.length; j < pl; j++) {
- var prop = rule[j];
- propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
- }
+ addScript(src) {
- // Insert CSS Rule
- styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);
- }
-};
+ return new Promise(function(resolve, reject){
+ var $script;
+ var ready = false;
-Contents.prototype.addScript = function(src) {
+ if(!this.document) {
+ resolve(false);
+ return;
+ }
- return new Promise(function(resolve, reject){
- var $script;
- var ready = false;
+ $script = this.document.createElement('script');
+ $script.type = 'text/javascript';
+ $script.async = true;
+ $script.src = src;
+ $script.onload = $script.onreadystatechange = function() {
+ if ( !ready && (!this.readyState || this.readyState == 'complete') ) {
+ ready = true;
+ setTimeout(function(){
+ resolve(true);
+ }, 1);
+ }
+ };
+ this.document.head.appendChild($script);
+
+ }.bind(this));
+ };
+
+ addClass(className) {
+ var content;
+
+ if(!this.document) return;
+
+ content = this.content || this.document.body;
+
+ content.classList.add(className);
+
+ };
+
+ removeClass(className) {
+ var content;
+
+ if(!this.document) return;
+
+ content = this.content || this.document.body;
+
+ content.classList.remove(className);
+
+ };
+
+ addEventListeners(){
if(!this.document) {
- resolve(false);
return;
}
+ this.listenedEvents.forEach(function(eventName){
+ this.document.addEventListener(eventName, this.triggerEvent.bind(this), false);
+ }, this);
- $script = this.document.createElement('script');
- $script.type = 'text/javascript';
- $script.async = true;
- $script.src = src;
- $script.onload = $script.onreadystatechange = function() {
- if ( !ready && (!this.readyState || this.readyState == 'complete') ) {
- ready = true;
- setTimeout(function(){
- resolve(true);
- }, 1);
- }
- };
+ };
- this.document.head.appendChild($script);
-
- }.bind(this));
-};
-
-Contents.prototype.addClass = function(className) {
- var content;
-
- if(!this.document) return;
-
- content = this.content || this.document.body;
-
- content.classList.add(className);
-
-};
-
-Contents.prototype.removeClass = function(className) {
- var content;
-
- if(!this.document) return;
-
- content = this.content || this.document.body;
-
- content.classList.remove(className);
-
-};
-
-Contents.prototype.addEventListeners = function(){
- if(!this.document) {
- return;
- }
- this.listenedEvents.forEach(function(eventName){
- this.document.addEventListener(eventName, this.triggerEvent.bind(this), false);
- }, this);
-
-};
-
-Contents.prototype.removeEventListeners = function(){
- if(!this.document) {
- return;
- }
- this.listenedEvents.forEach(function(eventName){
- this.document.removeEventListener(eventName, this.triggerEvent, false);
- }, this);
-
-};
-
-// Pass browser events
-Contents.prototype.triggerEvent = function(e){
- this.emit(e.type, e);
-};
-
-Contents.prototype.addSelectionListeners = function(){
- if(!this.document) {
- return;
- }
- this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false);
-};
-
-Contents.prototype.removeSelectionListeners = function(){
- if(!this.document) {
- return;
- }
- this.document.removeEventListener("selectionchange", this.onSelectionChange, false);
-};
-
-Contents.prototype.onSelectionChange = function(e){
- if (this.selectionEndTimeout) {
- clearTimeout(this.selectionEndTimeout);
- }
- this.selectionEndTimeout = setTimeout(function() {
- var selection = this.window.getSelection();
- this.triggerSelectedEvent(selection);
- }.bind(this), 500);
-};
-
-Contents.prototype.triggerSelectedEvent = function(selection){
- var range, cfirange;
-
- if (selection && selection.rangeCount > 0) {
- range = selection.getRangeAt(0);
- if(!range.collapsed) {
- // cfirange = this.section.cfiFromRange(range);
- cfirange = new EpubCFI(range, this.cfiBase).toString();
- this.emit("selected", cfirange);
- this.emit("selectedRange", range);
+ removeEventListeners(){
+ if(!this.document) {
+ return;
}
- }
-};
+ this.listenedEvents.forEach(function(eventName){
+ this.document.removeEventListener(eventName, this.triggerEvent, false);
+ }, this);
-Contents.prototype.range = function(_cfi, ignoreClass){
- var cfi = new EpubCFI(_cfi);
- return cfi.toRange(this.document, ignoreClass);
-};
+ };
-Contents.prototype.map = function(layout){
- var map = new Mapping(layout);
- return map.section();
-};
+ // Pass browser events
+ triggerEvent(e){
+ this.emit(e.type, e);
+ };
-Contents.prototype.size = function(width, height){
+ addSelectionListeners(){
+ if(!this.document) {
+ return;
+ }
+ this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false);
+ };
+
+ removeSelectionListeners(){
+ if(!this.document) {
+ return;
+ }
+ this.document.removeEventListener("selectionchange", this.onSelectionChange, false);
+ };
+
+ onSelectionChange(e){
+ if (this.selectionEndTimeout) {
+ clearTimeout(this.selectionEndTimeout);
+ }
+ this.selectionEndTimeout = setTimeout(function() {
+ var selection = this.window.getSelection();
+ this.triggerSelectedEvent(selection);
+ }.bind(this), 500);
+ };
+
+ triggerSelectedEvent(selection){
+ var range, cfirange;
+
+ if (selection && selection.rangeCount > 0) {
+ range = selection.getRangeAt(0);
+ if(!range.collapsed) {
+ // cfirange = this.section.cfiFromRange(range);
+ cfirange = new EpubCFI(range, this.cfiBase).toString();
+ this.emit("selected", cfirange);
+ this.emit("selectedRange", range);
+ }
+ }
+ };
+
+ range(_cfi, ignoreClass){
+ var cfi = new EpubCFI(_cfi);
+ return cfi.toRange(this.document, ignoreClass);
+ };
+
+ map(layout){
+ var map = new Mapping(layout);
+ return map.section();
+ };
+
+ size(width, height){
+
+ if (width >= 0) {
+ this.width(width);
+ }
+
+ if (height >= 0) {
+ this.height(height);
+ }
+
+ this.css("margin", "0");
+ this.css("boxSizing", "border-box");
+
+ };
+
+ columns(width, height, columnWidth, gap){
+ var COLUMN_AXIS = prefixed('columnAxis');
+ var COLUMN_GAP = prefixed('columnGap');
+ var COLUMN_WIDTH = prefixed('columnWidth');
+ var COLUMN_FILL = prefixed('columnFill');
+ var textWidth;
- if (width >= 0) {
this.width(width);
- }
-
- if (height >= 0) {
this.height(height);
- }
- this.css("margin", "0");
- this.css("boxSizing", "border-box");
+ // Deal with Mobile trying to scale to viewport
+ this.viewport({ width: width, height: height, scale: 1.0 });
-};
+ // this.overflowY("hidden");
+ this.css("overflowY", "hidden");
+ this.css("margin", "0");
+ this.css("boxSizing", "border-box");
+ this.css("maxWidth", "inherit");
-Contents.prototype.columns = function(width, height, columnWidth, gap){
- var COLUMN_AXIS = core.prefixed('columnAxis');
- var COLUMN_GAP = core.prefixed('columnGap');
- var COLUMN_WIDTH = core.prefixed('columnWidth');
- var COLUMN_FILL = core.prefixed('columnFill');
- var textWidth;
+ this.css(COLUMN_AXIS, "horizontal");
+ this.css(COLUMN_FILL, "auto");
- this.width(width);
- this.height(height);
+ this.css(COLUMN_GAP, gap+"px");
+ this.css(COLUMN_WIDTH, columnWidth+"px");
+ };
- // Deal with Mobile trying to scale to viewport
- this.viewport({ width: width, height: height, scale: 1.0 });
+ scaler(scale, offsetX, offsetY){
+ var scale = "scale(" + scale + ")";
+ var translate = '';
+ // this.css("position", "absolute"));
+ this.css("transformOrigin", "top left");
- // this.overflowY("hidden");
- this.css("overflowY", "hidden");
- this.css("margin", "0");
- this.css("boxSizing", "border-box");
- this.css("maxWidth", "inherit");
+ if (offsetX >= 0 || offsetY >= 0) {
+ translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )";
+ }
- this.css(COLUMN_AXIS, "horizontal");
- this.css(COLUMN_FILL, "auto");
+ this.css("transform", scale + translate);
+ };
- this.css(COLUMN_GAP, gap+"px");
- this.css(COLUMN_WIDTH, columnWidth+"px");
-};
+ fit(width, height){
+ var viewport = this.viewport();
+ var widthScale = width / viewport.width;
+ var heightScale = height / viewport.height;
+ var scale = widthScale < heightScale ? widthScale : heightScale;
-Contents.prototype.scale = function(scale, offsetX, offsetY){
- var scale = "scale(" + scale + ")";
- var translate = '';
- // this.css("position", "absolute"));
- this.css("transformOrigin", "top left");
+ var offsetY = (height - (viewport.height * scale)) / 2;
- if (offsetX >= 0 || offsetY >= 0) {
- translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )";
- }
+ this.width(width);
+ this.height(height);
+ this.overflow("hidden");
- this.css("transform", scale + translate);
-};
+ // Deal with Mobile trying to scale to viewport
+ this.viewport({ scale: 1.0 });
-Contents.prototype.fit = function(width, height){
- var viewport = this.viewport();
- var widthScale = width / viewport.width;
- var heightScale = height / viewport.height;
- var scale = widthScale < heightScale ? widthScale : heightScale;
+ // Scale to the correct size
+ this.scaler(scale, 0, offsetY);
- var offsetY = (height - (viewport.height * scale)) / 2;
+ this.css("backgroundColor", "transparent");
+ };
- this.width(width);
- this.height(height);
- this.overflow("hidden");
+ mapPage(cfiBase, start, end) {
+ var mapping = new Mapping();
- // Deal with Mobile trying to scale to viewport
- this.viewport({ scale: 1.0 });
+ return mapping.page(this, cfiBase, start, end);
+ };
- // Scale to the correct size
- this.scale(scale, 0, offsetY);
+ destroy() {
+ // Stop observing
+ if(this.observer) {
+ this.observer.disconnect();
+ }
- this.css("backgroundColor", "transparent");
-};
+ this.removeListeners();
-Contents.prototype.mapPage = function(cfiBase, start, end) {
- var mapping = new Mapping();
-
- return mapping.page(this, cfiBase, start, end);
-};
-
-Contents.prototype.destroy = function() {
- // Stop observing
- if(this.observer) {
- this.observer.disconnect();
- }
-
- this.removeListeners();
-
-};
+ };
+}
EventEmitter(Contents.prototype);
-module.exports = Contents;
+export default Contents;
diff --git a/src/epub.js b/src/epub.js
index 4426b6e..b6620c9 100644
--- a/src/epub.js
+++ b/src/epub.js
@@ -1,7 +1,7 @@
-var Book = require('./book');
-var EpubCFI = require('./epubcfi');
-var Rendition = require('./rendition');
-var Contents = require('./contents');
+import Book from './book';
+import EpubCFI from './epubcfi';
+import Rendition from './rendition';
+import Contents from './contents';
/**
* Creates a new Book
@@ -51,4 +51,4 @@ ePub.register.view("iframe", require('./managers/views/iframe'));
ePub.register.manager("default", require('./managers/default'));
ePub.register.manager("continuous", require('./managers/continuous'));
-module.exports = ePub;
+export default ePub;
diff --git a/src/epubcfi.js b/src/epubcfi.js
index 4760f01..cfcf449 100644
--- a/src/epubcfi.js
+++ b/src/epubcfi.js
@@ -1,4 +1,4 @@
-var core = require('./core');
+import {extend, type, findChildren} from './utils/core';
/**
EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html
@@ -19,945 +19,947 @@ var TEXT_NODE = 3;
var COMMENT_NODE = 8;
var DOCUMENT_NODE = 9;
-function EpubCFI(cfiFrom, base, ignoreClass){
- var type;
+class EpubCFI {
+ constructor(cfiFrom, base, ignoreClass){
+ var type;
- this.str = '';
+ this.str = '';
- this.base = {};
- this.spinePos = 0; // For compatibility
+ this.base = {};
+ this.spinePos = 0; // For compatibility
- this.range = false; // true || false;
+ this.range = false; // true || false;
- this.path = {};
- this.start = null;
- this.end = null;
+ this.path = {};
+ this.start = null;
+ this.end = null;
- // Allow instantiation without the 'new' keyword
- if (!(this instanceof EpubCFI)) {
- return new EpubCFI(cfiFrom, base, ignoreClass);
- }
-
- if(typeof base === 'string') {
- this.base = this.parseComponent(base);
- } else if(typeof base === 'object' && base.steps) {
- this.base = base;
- }
-
- type = this.checkType(cfiFrom);
-
-
- if(type === 'string') {
- this.str = cfiFrom;
- return core.extend(this, this.parse(cfiFrom));
- } else if (type === 'range') {
- return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass));
- } else if (type === 'node') {
- return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass));
- } else if (type === 'EpubCFI' && cfiFrom.path) {
- return cfiFrom;
- } else if (!cfiFrom) {
- return this;
- } else {
- throw new TypeError('not a valid argument for EpubCFI');
- }
-
-};
-
-EpubCFI.prototype.checkType = function(cfi) {
-
- if (this.isCfiString(cfi)) {
- return 'string';
- // Is a range object
- } else if (typeof cfi === 'object' && (core.type(cfi) === "Range" || typeof(cfi.startContainer) != "undefined")){
- return 'range';
- } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function'
- return 'node';
- } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){
- return 'EpubCFI';
- } else {
- return false;
- }
-};
-
-EpubCFI.prototype.parse = function(cfiStr) {
- var cfi = {
- spinePos: -1,
- range: false,
- base: {},
- path: {},
- start: null,
- end: null
- };
- var baseComponent, pathComponent, range;
-
- if(typeof cfiStr !== "string") {
- return {spinePos: -1};
- }
-
- if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") {
- // Remove intial epubcfi( and ending )
- cfiStr = cfiStr.slice(8, cfiStr.length-1);
- }
-
- baseComponent = this.getChapterComponent(cfiStr);
-
- // Make sure this is a valid cfi or return
- if(!baseComponent) {
- return {spinePos: -1};
- }
-
- cfi.base = this.parseComponent(baseComponent);
-
- pathComponent = this.getPathComponent(cfiStr);
- cfi.path = this.parseComponent(pathComponent);
-
- range = this.getRange(cfiStr);
-
- if(range) {
- cfi.range = true;
- cfi.start = this.parseComponent(range[0]);
- cfi.end = this.parseComponent(range[1]);
- }
-
- // Get spine node position
- // cfi.spineSegment = cfi.base.steps[1];
-
- // Chapter segment is always the second step
- cfi.spinePos = cfi.base.steps[1].index;
-
- return cfi;
-};
-
-EpubCFI.prototype.parseComponent = function(componentStr){
- var component = {
- steps: [],
- terminal: {
- offset: null,
- assertion: null
- }
- };
- var parts = componentStr.split(':');
- var steps = parts[0].split('/');
- var terminal;
-
- if(parts.length > 1) {
- terminal = parts[1];
- component.terminal = this.parseTerminal(terminal);
- }
-
- if (steps[0] === '') {
- steps.shift(); // Ignore the first slash
- }
-
- component.steps = steps.map(function(step){
- return this.parseStep(step);
- }.bind(this));
-
- return component;
-};
-
-EpubCFI.prototype.parseStep = function(stepStr){
- var type, num, index, has_brackets, id;
-
- has_brackets = stepStr.match(/\[(.*)\]/);
- if(has_brackets && has_brackets[1]){
- id = has_brackets[1];
- }
-
- //-- Check if step is a text node or element
- num = parseInt(stepStr);
-
- if(isNaN(num)) {
- return;
- }
-
- if(num % 2 === 0) { // Even = is an element
- type = "element";
- index = num / 2 - 1;
- } else {
- type = "text";
- index = (num - 1 ) / 2;
- }
-
- return {
- "type" : type,
- 'index' : index,
- 'id' : id || null
- };
-};
-
-EpubCFI.prototype.parseTerminal = function(termialStr){
- var characterOffset, textLocationAssertion;
- var assertion = termialStr.match(/\[(.*)\]/);
-
- if(assertion && assertion[1]){
- characterOffset = parseInt(termialStr.split('[')[0]) || null;
- textLocationAssertion = assertion[1];
- } else {
- characterOffset = parseInt(termialStr) || null;
- }
-
- return {
- 'offset': characterOffset,
- 'assertion': textLocationAssertion
- };
-
-};
-
-EpubCFI.prototype.getChapterComponent = function(cfiStr) {
-
- var indirection = cfiStr.split("!");
-
- return indirection[0];
-};
-
-EpubCFI.prototype.getPathComponent = function(cfiStr) {
-
- var indirection = cfiStr.split("!");
-
- if(indirection[1]) {
- ranges = indirection[1].split(',');
- return ranges[0];
- }
-
-};
-
-EpubCFI.prototype.getRange = function(cfiStr) {
-
- var ranges = cfiStr.split(",");
-
- if(ranges.length === 3){
- return [
- ranges[1],
- ranges[2]
- ];
- }
-
- return false;
-};
-
-EpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) {
- var splitStr = cfiStr.split(":");
- return splitStr[1] || '';
-};
-
-EpubCFI.prototype.joinSteps = function(steps) {
- if(!steps) {
- return "";
- }
-
- return steps.map(function(part){
- var segment = '';
-
- if(part.type === 'element') {
- segment += (part.index + 1) * 2;
+ // Allow instantiation without the 'new' keyword
+ if (!(this instanceof EpubCFI)) {
+ return new EpubCFI(cfiFrom, base, ignoreClass);
}
- if(part.type === 'text') {
- segment += 1 + (2 * part.index); // TODO: double check that this is odd
+ if(typeof base === 'string') {
+ this.base = this.parseComponent(base);
+ } else if(typeof base === 'object' && base.steps) {
+ this.base = base;
}
- if(part.id) {
- segment += "[" + part.id + "]";
- }
+ type = this.checkType(cfiFrom);
- return segment;
- }).join('/');
-
-};
-
-EpubCFI.prototype.segmentString = function(segment) {
- var segmentString = '/';
-
- segmentString += this.joinSteps(segment.steps);
-
- if(segment.terminal && segment.terminal.offset != null){
- segmentString += ':' + segment.terminal.offset;
- }
-
- if(segment.terminal && segment.terminal.assertion != null){
- segmentString += '[' + segment.terminal.assertion + ']';
- }
-
- return segmentString;
-};
-
-EpubCFI.prototype.toString = function() {
- var cfiString = 'epubcfi(';
-
- cfiString += this.segmentString(this.base);
-
- cfiString += '!';
- cfiString += this.segmentString(this.path);
-
- // Add Range, if present
- if(this.start) {
- cfiString += ',';
- cfiString += this.segmentString(this.start);
- }
-
- if(this.end) {
- cfiString += ',';
- cfiString += this.segmentString(this.end);
- }
-
- cfiString += ")";
-
- return cfiString;
-};
-
-EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
- var stepsA, stepsB;
- var terminalA, terminalB;
-
- if(typeof cfiOne === 'string') {
- cfiOne = new EpubCFI(cfiOne);
- }
- if(typeof cfiTwo === 'string') {
- cfiTwo = new EpubCFI(cfiTwo);
- }
- // Compare Spine Positions
- if(cfiOne.spinePos > cfiTwo.spinePos) {
- return 1;
- }
- if(cfiOne.spinePos < cfiTwo.spinePos) {
- return -1;
- }
-
- if (cfiOne.range) {
- stepsA = cfiOne.path.steps.concat(cfiOne.start.steps);
- terminalA = cfiOne.start.terminal;
- } else {
- stepsA = cfiOne.path.steps;
- terminalA = cfiOne.path.terminal;
- }
-
- if (cfiTwo.range) {
- stepsB = cfiTwo.path.steps.concat(cfiTwo.start.steps);
- terminalB = cfiTwo.start.terminal;
- } else {
- stepsB = cfiTwo.path.steps;
- terminalB = cfiTwo.path.terminal;
- }
-
- // Compare Each Step in the First item
- for (var i = 0; i < stepsA.length; i++) {
- if(!stepsA[i]) {
- return -1;
- }
- if(!stepsB[i]) {
- return 1;
- }
- if(stepsA[i].index > stepsB[i].index) {
- return 1;
- }
- if(stepsA[i].index < stepsB[i].index) {
- return -1;
- }
- // Otherwise continue checking
- }
-
- // All steps in First equal to Second and First is Less Specific
- if(stepsA.length < stepsB.length) {
- return 1;
- }
-
- // Compare the charecter offset of the text node
- if(terminalA.offset > terminalB.offset) {
- return 1;
- }
- if(terminalA.offset < terminalB.offset) {
- return -1;
- }
-
- // CFI's are equal
- return 0;
-};
-
-EpubCFI.prototype.step = function(node) {
- var nodeType = (node.nodeType === TEXT_NODE) ? 'text' : 'element';
-
- return {
- 'id' : node.id,
- 'tagName' : node.tagName,
- 'type' : nodeType,
- 'index' : this.position(node)
- };
-};
-
-EpubCFI.prototype.filteredStep = function(node, ignoreClass) {
- var filteredNode = this.filter(node, ignoreClass);
- var nodeType;
-
- // Node filtered, so ignore
- if (!filteredNode) {
- return;
- }
-
- // Otherwise add the filter node in
- nodeType = (filteredNode.nodeType === TEXT_NODE) ? 'text' : 'element';
-
- return {
- 'id' : filteredNode.id,
- 'tagName' : filteredNode.tagName,
- 'type' : nodeType,
- 'index' : this.filteredPosition(filteredNode, ignoreClass)
- };
-};
-
-EpubCFI.prototype.pathTo = function(node, offset, ignoreClass) {
- var segment = {
- steps: [],
- terminal: {
- offset: null,
- assertion: null
- }
- };
- var currentNode = node;
- var step;
-
- while(currentNode && currentNode.parentNode &&
- currentNode.parentNode.nodeType != DOCUMENT_NODE) {
-
- if (ignoreClass) {
- step = this.filteredStep(currentNode, ignoreClass);
+ if(type === 'string') {
+ this.str = cfiFrom;
+ return extend(this, this.parse(cfiFrom));
+ } else if (type === 'range') {
+ return extend(this, this.fromRange(cfiFrom, this.base, ignoreClass));
+ } else if (type === 'node') {
+ return extend(this, this.fromNode(cfiFrom, this.base, ignoreClass));
+ } else if (type === 'EpubCFI' && cfiFrom.path) {
+ return cfiFrom;
+ } else if (!cfiFrom) {
+ return this;
} else {
- step = this.step(currentNode);
+ throw new TypeError('not a valid argument for EpubCFI');
}
- if (step) {
- segment.steps.unshift(step);
+ };
+
+ checkType(cfi) {
+
+ if (this.isCfiString(cfi)) {
+ return 'string';
+ // Is a range object
+ } else if (typeof cfi === 'object' && (type(cfi) === "Range" || typeof(cfi.startContainer) != "undefined")){
+ return 'range';
+ } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function'
+ return 'node';
+ } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){
+ return 'EpubCFI';
+ } else {
+ return false;
+ }
+ };
+
+ parse(cfiStr) {
+ var cfi = {
+ spinePos: -1,
+ range: false,
+ base: {},
+ path: {},
+ start: null,
+ end: null
+ };
+ var baseComponent, pathComponent, range;
+
+ if(typeof cfiStr !== "string") {
+ return {spinePos: -1};
}
- currentNode = currentNode.parentNode;
-
- }
-
- if (offset != null && offset >= 0) {
-
- segment.terminal.offset = offset;
-
- // Make sure we are getting to a textNode if there is an offset
- if(segment.steps[segment.steps.length-1].type != "text") {
- segment.steps.push({
- 'type' : "text",
- 'index' : 0
- });
+ if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") {
+ // Remove intial epubcfi( and ending )
+ cfiStr = cfiStr.slice(8, cfiStr.length-1);
}
- }
+ baseComponent = this.getChapterComponent(cfiStr);
+ // Make sure this is a valid cfi or return
+ if(!baseComponent) {
+ return {spinePos: -1};
+ }
- return segment;
-}
+ cfi.base = this.parseComponent(baseComponent);
-EpubCFI.prototype.equalStep = function(stepA, stepB) {
- if (!stepA || !stepB) {
- return false;
- }
+ pathComponent = this.getPathComponent(cfiStr);
+ cfi.path = this.parseComponent(pathComponent);
- if(stepA.index === stepB.index &&
- stepA.id === stepB.id &&
- stepA.type === stepB.type) {
- return true;
- }
+ range = this.getRange(cfiStr);
- return false;
-};
+ if(range) {
+ cfi.range = true;
+ cfi.start = this.parseComponent(range[0]);
+ cfi.end = this.parseComponent(range[1]);
+ }
-EpubCFI.prototype.fromRange = function(range, base, ignoreClass) {
- var cfi = {
- range: false,
- base: {},
- path: {},
- start: null,
- end: null
- };
+ // Get spine node position
+ // cfi.spineSegment = cfi.base.steps[1];
- var start = range.startContainer;
- var end = range.endContainer;
-
- var startOffset = range.startOffset;
- var endOffset = range.endOffset;
-
- var needsIgnoring = false;
-
- if (ignoreClass) {
- // Tell pathTo if / what to ignore
- needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null);
- }
-
-
- if (typeof base === 'string') {
- cfi.base = this.parseComponent(base);
+ // Chapter segment is always the second step
cfi.spinePos = cfi.base.steps[1].index;
- } else if (typeof base === 'object') {
- cfi.base = base;
- }
- if (range.collapsed) {
- if (needsIgnoring) {
- startOffset = this.patchOffset(start, startOffset, ignoreClass);
- }
- cfi.path = this.pathTo(start, startOffset, ignoreClass);
- } else {
- cfi.range = true;
+ return cfi;
+ };
- if (needsIgnoring) {
- startOffset = this.patchOffset(start, startOffset, ignoreClass);
- }
-
- cfi.start = this.pathTo(start, startOffset, ignoreClass);
- if (needsIgnoring) {
- endOffset = this.patchOffset(end, endOffset, ignoreClass);
- }
-
- cfi.end = this.pathTo(end, endOffset, ignoreClass);
-
- // Create a new empty path
- cfi.path = {
+ parseComponent(componentStr){
+ var component = {
steps: [],
- terminal: null
- };
-
- // Push steps that are shared between start and end to the common path
- var len = cfi.start.steps.length;
- var i;
-
- for (i = 0; i < len; i++) {
- if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) {
- if(i === len-1) {
- // Last step is equal, check terminals
- if(cfi.start.terminal === cfi.end.terminal) {
- // CFI's are equal
- cfi.path.steps.push(cfi.start.steps[i]);
- // Not a range
- cfi.range = false;
- }
- } else {
- cfi.path.steps.push(cfi.start.steps[i]);
- }
-
- } else {
- break;
+ terminal: {
+ offset: null,
+ assertion: null
}
};
+ var parts = componentStr.split(':');
+ var steps = parts[0].split('/');
+ var terminal;
- cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length);
- cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length);
-
- // TODO: Add Sanity check to make sure that the end if greater than the start
- }
-
- return cfi;
-}
-
-EpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) {
- var cfi = {
- range: false,
- base: {},
- path: {},
- start: null,
- end: null
- };
-
- var needsIgnoring = false;
-
- if (ignoreClass) {
- // Tell pathTo if / what to ignore
- needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null);
- }
-
- if (typeof base === 'string') {
- cfi.base = this.parseComponent(base);
- cfi.spinePos = cfi.base.steps[1].index;
- } else if (typeof base === 'object') {
- cfi.base = base;
- }
-
- cfi.path = this.pathTo(anchor, null, ignoreClass);
-
- return cfi;
-};
-
-EpubCFI.prototype.filter = function(anchor, ignoreClass) {
- var needsIgnoring;
- var sibling; // to join with
- var parent, prevSibling, nextSibling;
- var isText = false;
-
- if (anchor.nodeType === TEXT_NODE) {
- isText = true;
- parent = anchor.parentNode;
- needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
- } else {
- isText = false;
- needsIgnoring = anchor.classList.contains(ignoreClass);
- }
-
- if (needsIgnoring && isText) {
- previousSibling = parent.previousSibling;
- nextSibling = parent.nextSibling;
-
- // If the sibling is a text node, join the nodes
- if (previousSibling && previousSibling.nodeType === TEXT_NODE) {
- sibling = previousSibling;
- } else if (nextSibling && nextSibling.nodeType === TEXT_NODE) {
- sibling = nextSibling;
+ if(parts.length > 1) {
+ terminal = parts[1];
+ component.terminal = this.parseTerminal(terminal);
}
- if (sibling) {
- return sibling;
+ if (steps[0] === '') {
+ steps.shift(); // Ignore the first slash
+ }
+
+ component.steps = steps.map(function(step){
+ return this.parseStep(step);
+ }.bind(this));
+
+ return component;
+ };
+
+ parseStep(stepStr){
+ var type, num, index, has_brackets, id;
+
+ has_brackets = stepStr.match(/\[(.*)\]/);
+ if(has_brackets && has_brackets[1]){
+ id = has_brackets[1];
+ }
+
+ //-- Check if step is a text node or element
+ num = parseInt(stepStr);
+
+ if(isNaN(num)) {
+ return;
+ }
+
+ if(num % 2 === 0) { // Even = is an element
+ type = "element";
+ index = num / 2 - 1;
} else {
- // Parent will be ignored on next step
+ type = "text";
+ index = (num - 1 ) / 2;
+ }
+
+ return {
+ "type" : type,
+ 'index' : index,
+ 'id' : id || null
+ };
+ };
+
+ parseTerminal(termialStr){
+ var characterOffset, textLocationAssertion;
+ var assertion = termialStr.match(/\[(.*)\]/);
+
+ if(assertion && assertion[1]){
+ characterOffset = parseInt(termialStr.split('[')[0]) || null;
+ textLocationAssertion = assertion[1];
+ } else {
+ characterOffset = parseInt(termialStr) || null;
+ }
+
+ return {
+ 'offset': characterOffset,
+ 'assertion': textLocationAssertion
+ };
+
+ };
+
+ getChapterComponent(cfiStr) {
+
+ var indirection = cfiStr.split("!");
+
+ return indirection[0];
+ };
+
+ getPathComponent(cfiStr) {
+
+ var indirection = cfiStr.split("!");
+
+ if(indirection[1]) {
+ let ranges = indirection[1].split(',');
+ return ranges[0];
+ }
+
+ };
+
+ getRange(cfiStr) {
+
+ var ranges = cfiStr.split(",");
+
+ if(ranges.length === 3){
+ return [
+ ranges[1],
+ ranges[2]
+ ];
+ }
+
+ return false;
+ };
+
+ getCharecterOffsetComponent(cfiStr) {
+ var splitStr = cfiStr.split(":");
+ return splitStr[1] || '';
+ };
+
+ joinSteps(steps) {
+ if(!steps) {
+ return "";
+ }
+
+ return steps.map(function(part){
+ var segment = '';
+
+ if(part.type === 'element') {
+ segment += (part.index + 1) * 2;
+ }
+
+ if(part.type === 'text') {
+ segment += 1 + (2 * part.index); // TODO: double check that this is odd
+ }
+
+ if(part.id) {
+ segment += "[" + part.id + "]";
+ }
+
+ return segment;
+
+ }).join('/');
+
+ };
+
+ segmentString(segment) {
+ var segmentString = '/';
+
+ segmentString += this.joinSteps(segment.steps);
+
+ if(segment.terminal && segment.terminal.offset != null){
+ segmentString += ':' + segment.terminal.offset;
+ }
+
+ if(segment.terminal && segment.terminal.assertion != null){
+ segmentString += '[' + segment.terminal.assertion + ']';
+ }
+
+ return segmentString;
+ };
+
+ toString() {
+ var cfiString = 'epubcfi(';
+
+ cfiString += this.segmentString(this.base);
+
+ cfiString += '!';
+ cfiString += this.segmentString(this.path);
+
+ // Add Range, if present
+ if(this.start) {
+ cfiString += ',';
+ cfiString += this.segmentString(this.start);
+ }
+
+ if(this.end) {
+ cfiString += ',';
+ cfiString += this.segmentString(this.end);
+ }
+
+ cfiString += ")";
+
+ return cfiString;
+ };
+
+ compare(cfiOne, cfiTwo) {
+ var stepsA, stepsB;
+ var terminalA, terminalB;
+
+ if(typeof cfiOne === 'string') {
+ cfiOne = new EpubCFI(cfiOne);
+ }
+ if(typeof cfiTwo === 'string') {
+ cfiTwo = new EpubCFI(cfiTwo);
+ }
+ // Compare Spine Positions
+ if(cfiOne.spinePos > cfiTwo.spinePos) {
+ return 1;
+ }
+ if(cfiOne.spinePos < cfiTwo.spinePos) {
+ return -1;
+ }
+
+ if (cfiOne.range) {
+ stepsA = cfiOne.path.steps.concat(cfiOne.start.steps);
+ terminalA = cfiOne.start.terminal;
+ } else {
+ stepsA = cfiOne.path.steps;
+ terminalA = cfiOne.path.terminal;
+ }
+
+ if (cfiTwo.range) {
+ stepsB = cfiTwo.path.steps.concat(cfiTwo.start.steps);
+ terminalB = cfiTwo.start.terminal;
+ } else {
+ stepsB = cfiTwo.path.steps;
+ terminalB = cfiTwo.path.terminal;
+ }
+
+ // Compare Each Step in the First item
+ for (var i = 0; i < stepsA.length; i++) {
+ if(!stepsA[i]) {
+ return -1;
+ }
+ if(!stepsB[i]) {
+ return 1;
+ }
+ if(stepsA[i].index > stepsB[i].index) {
+ return 1;
+ }
+ if(stepsA[i].index < stepsB[i].index) {
+ return -1;
+ }
+ // Otherwise continue checking
+ }
+
+ // All steps in First equal to Second and First is Less Specific
+ if(stepsA.length < stepsB.length) {
+ return 1;
+ }
+
+ // Compare the charecter offset of the text node
+ if(terminalA.offset > terminalB.offset) {
+ return 1;
+ }
+ if(terminalA.offset < terminalB.offset) {
+ return -1;
+ }
+
+ // CFI's are equal
+ return 0;
+ };
+
+ step(node) {
+ var nodeType = (node.nodeType === TEXT_NODE) ? 'text' : 'element';
+
+ return {
+ 'id' : node.id,
+ 'tagName' : node.tagName,
+ 'type' : nodeType,
+ 'index' : this.position(node)
+ };
+ };
+
+ filteredStep(node, ignoreClass) {
+ var filteredNode = this.filter(node, ignoreClass);
+ var nodeType;
+
+ // Node filtered, so ignore
+ if (!filteredNode) {
+ return;
+ }
+
+ // Otherwise add the filter node in
+ nodeType = (filteredNode.nodeType === TEXT_NODE) ? 'text' : 'element';
+
+ return {
+ 'id' : filteredNode.id,
+ 'tagName' : filteredNode.tagName,
+ 'type' : nodeType,
+ 'index' : this.filteredPosition(filteredNode, ignoreClass)
+ };
+ };
+
+ pathTo(node, offset, ignoreClass) {
+ var segment = {
+ steps: [],
+ terminal: {
+ offset: null,
+ assertion: null
+ }
+ };
+ var currentNode = node;
+ var step;
+
+ while(currentNode && currentNode.parentNode &&
+ currentNode.parentNode.nodeType != DOCUMENT_NODE) {
+
+ if (ignoreClass) {
+ step = this.filteredStep(currentNode, ignoreClass);
+ } else {
+ step = this.step(currentNode);
+ }
+
+ if (step) {
+ segment.steps.unshift(step);
+ }
+
+ currentNode = currentNode.parentNode;
+
+ }
+
+ if (offset != null && offset >= 0) {
+
+ segment.terminal.offset = offset;
+
+ // Make sure we are getting to a textNode if there is an offset
+ if(segment.steps[segment.steps.length-1].type != "text") {
+ segment.steps.push({
+ 'type' : "text",
+ 'index' : 0
+ });
+ }
+
+ }
+
+
+ return segment;
+ }
+
+ equalStep(stepA, stepB) {
+ if (!stepA || !stepB) {
+ return false;
+ }
+
+ if(stepA.index === stepB.index &&
+ stepA.id === stepB.id &&
+ stepA.type === stepB.type) {
+ return true;
+ }
+
+ return false;
+ };
+
+ fromRange(range, base, ignoreClass) {
+ var cfi = {
+ range: false,
+ base: {},
+ path: {},
+ start: null,
+ end: null
+ };
+
+ var start = range.startContainer;
+ var end = range.endContainer;
+
+ var startOffset = range.startOffset;
+ var endOffset = range.endOffset;
+
+ var needsIgnoring = false;
+
+ if (ignoreClass) {
+ // Tell pathTo if / what to ignore
+ needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null);
+ }
+
+
+ if (typeof base === 'string') {
+ cfi.base = this.parseComponent(base);
+ cfi.spinePos = cfi.base.steps[1].index;
+ } else if (typeof base === 'object') {
+ cfi.base = base;
+ }
+
+ if (range.collapsed) {
+ if (needsIgnoring) {
+ startOffset = this.patchOffset(start, startOffset, ignoreClass);
+ }
+ cfi.path = this.pathTo(start, startOffset, ignoreClass);
+ } else {
+ cfi.range = true;
+
+ if (needsIgnoring) {
+ startOffset = this.patchOffset(start, startOffset, ignoreClass);
+ }
+
+ cfi.start = this.pathTo(start, startOffset, ignoreClass);
+ if (needsIgnoring) {
+ endOffset = this.patchOffset(end, endOffset, ignoreClass);
+ }
+
+ cfi.end = this.pathTo(end, endOffset, ignoreClass);
+
+ // Create a new empty path
+ cfi.path = {
+ steps: [],
+ terminal: null
+ };
+
+ // Push steps that are shared between start and end to the common path
+ var len = cfi.start.steps.length;
+ var i;
+
+ for (i = 0; i < len; i++) {
+ if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) {
+ if(i === len-1) {
+ // Last step is equal, check terminals
+ if(cfi.start.terminal === cfi.end.terminal) {
+ // CFI's are equal
+ cfi.path.steps.push(cfi.start.steps[i]);
+ // Not a range
+ cfi.range = false;
+ }
+ } else {
+ cfi.path.steps.push(cfi.start.steps[i]);
+ }
+
+ } else {
+ break;
+ }
+ };
+
+ cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length);
+ cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length);
+
+ // TODO: Add Sanity check to make sure that the end if greater than the start
+ }
+
+ return cfi;
+ }
+
+ fromNode(anchor, base, ignoreClass) {
+ var cfi = {
+ range: false,
+ base: {},
+ path: {},
+ start: null,
+ end: null
+ };
+
+ var needsIgnoring = false;
+
+ if (ignoreClass) {
+ // Tell pathTo if / what to ignore
+ needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null);
+ }
+
+ if (typeof base === 'string') {
+ cfi.base = this.parseComponent(base);
+ cfi.spinePos = cfi.base.steps[1].index;
+ } else if (typeof base === 'object') {
+ cfi.base = base;
+ }
+
+ cfi.path = this.pathTo(anchor, null, ignoreClass);
+
+ return cfi;
+ };
+
+ filter(anchor, ignoreClass) {
+ var needsIgnoring;
+ var sibling; // to join with
+ var parent, previousSibling, nextSibling;
+ var isText = false;
+
+ if (anchor.nodeType === TEXT_NODE) {
+ isText = true;
+ parent = anchor.parentNode;
+ needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
+ } else {
+ isText = false;
+ needsIgnoring = anchor.classList.contains(ignoreClass);
+ }
+
+ if (needsIgnoring && isText) {
+ previousSibling = parent.previousSibling;
+ nextSibling = parent.nextSibling;
+
+ // If the sibling is a text node, join the nodes
+ if (previousSibling && previousSibling.nodeType === TEXT_NODE) {
+ sibling = previousSibling;
+ } else if (nextSibling && nextSibling.nodeType === TEXT_NODE) {
+ sibling = nextSibling;
+ }
+
+ if (sibling) {
+ return sibling;
+ } else {
+ // Parent will be ignored on next step
+ return anchor;
+ }
+
+ } else if (needsIgnoring && !isText) {
+ // Otherwise just skip the element node
+ return false;
+ } else {
+ // No need to filter
return anchor;
}
- } else if (needsIgnoring && !isText) {
- // Otherwise just skip the element node
- return false;
- } else {
- // No need to filter
- return anchor;
- }
-
-};
-
-EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {
- var needsIgnoring;
- var sibling;
-
- if (anchor.nodeType != TEXT_NODE) {
- console.error("Anchor must be a text node");
- return;
- }
-
- var curr = anchor;
- var totalOffset = offset;
-
- // If the parent is a ignored node, get offset from it's start
- if (anchor.parentNode.classList.contains(ignoreClass)) {
- curr = anchor.parentNode;
- }
-
- while (curr.previousSibling) {
- if(curr.previousSibling.nodeType === ELEMENT_NODE) {
- // Originally a text node, so join
- if(curr.previousSibling.classList.contains(ignoreClass)){
- totalOffset += curr.previousSibling.textContent.length;
- } else {
- break; // Normal node, dont join
- }
- } else {
- // If the previous sibling is a text node, join the nodes
- totalOffset += curr.previousSibling.textContent.length;
- }
-
- curr = curr.previousSibling;
- }
-
- return totalOffset;
-
-};
-
-EpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) {
- var output = {};
- var prevIndex = -1;
- var i, len = children.length;
- var currNodeType;
- var prevNodeType;
-
- for (i = 0; i < len; i++) {
-
- currNodeType = children[i].nodeType;
-
- // Check if needs ignoring
- if (currNodeType === ELEMENT_NODE &&
- children[i].classList.contains(ignoreClass)) {
- currNodeType = TEXT_NODE;
- }
-
- if (i > 0 &&
- currNodeType === TEXT_NODE &&
- prevNodeType === TEXT_NODE) {
- // join text nodes
- output[i] = prevIndex;
- } else if (nodeType === currNodeType){
- prevIndex = prevIndex + 1;
- output[i] = prevIndex;
- }
-
- prevNodeType = currNodeType;
-
- }
-
- return output;
-};
-
-EpubCFI.prototype.position = function(anchor) {
- var children, index, map;
- var childNodes, node;
- if (anchor.nodeType === ELEMENT_NODE) {
- children = anchor.parentNode.children;
- if (!children) {
- children = core.children(anchor.parentNode);
- }
- index = Array.prototype.indexOf.call(children, anchor);
- } else {
- children = this.textNodes(anchor.parentNode);
- index = children.indexOf(anchor);
- }
-
- return index;
-};
-
-EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {
- var children, index, map;
-
- if (anchor.nodeType === ELEMENT_NODE) {
- children = anchor.parentNode.children;
- map = this.normalizedMap(children, ELEMENT_NODE, ignoreClass);
- } else {
- children = anchor.parentNode.childNodes;
- // Inside an ignored node
- if(anchor.parentNode.classList.contains(ignoreClass)) {
- anchor = anchor.parentNode;
- children = anchor.parentNode.childNodes;
- }
- map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
- }
-
-
- index = Array.prototype.indexOf.call(children, anchor);
-
- return map[index];
-};
-
-EpubCFI.prototype.stepsToXpath = function(steps) {
- var xpath = [".", "*"];
-
- steps.forEach(function(step){
- var position = step.index + 1;
-
- if(step.id){
- xpath.push("*[position()=" + position + " and @id='" + step.id + "']");
- } else if(step.type === "text") {
- xpath.push("text()[" + position + "]");
- } else {
- xpath.push("*[" + position + "]");
- }
- });
-
- return xpath.join("/");
-};
-
-
-/*
-
-To get the last step if needed:
-
-// Get the terminal step
-lastStep = steps[steps.length-1];
-// Get the query string
-query = this.stepsToQuery(steps);
-// Find the containing element
-startContainerParent = doc.querySelector(query);
-// Find the text node within that element
-if(startContainerParent && lastStep.type == "text") {
- container = startContainerParent.childNodes[lastStep.index];
-}
-*/
-EpubCFI.prototype.stepsToQuerySelector = function(steps) {
- var query = ["html"];
-
- steps.forEach(function(step){
- var position = step.index + 1;
-
- if(step.id){
- query.push("#" + step.id);
- } else if(step.type === "text") {
- // unsupported in querySelector
- // query.push("text()[" + position + "]");
- } else {
- query.push("*:nth-child(" + position + ")");
- }
- });
-
- return query.join(">");
-
-};
-
-EpubCFI.prototype.textNodes = function(container, ignoreClass) {
- return Array.prototype.slice.call(container.childNodes).
- filter(function (node) {
- if (node.nodeType === TEXT_NODE) {
- return true;
- } else if (ignoreClass && node.classList.contains(ignoreClass)) {
- return true;
- }
- return false;
- });
-};
-
-EpubCFI.prototype.walkToNode = function(steps, _doc, ignoreClass) {
- var doc = _doc || document;
- var container = doc.documentElement;
- var step;
- var len = steps.length;
- var i;
-
- for (i = 0; i < len; i++) {
- step = steps[i];
-
- if(step.type === "element") {
- container = container.children[step.index];
- } else if(step.type === "text"){
- container = this.textNodes(container, ignoreClass)[step.index];
- }
-
};
- return container;
-};
+ patchOffset(anchor, offset, ignoreClass) {
+ var needsIgnoring;
+ var sibling;
-EpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) {
- var doc = _doc || document;
- var container;
- var xpath;
+ if (anchor.nodeType != TEXT_NODE) {
+ console.error("Anchor must be a text node");
+ return;
+ }
- if(!ignoreClass && typeof doc.evaluate != 'undefined') {
- xpath = this.stepsToXpath(steps);
- container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
- } else if(ignoreClass) {
- container = this.walkToNode(steps, doc, ignoreClass);
- } else {
- container = this.walkToNode(steps, doc);
- }
+ var curr = anchor;
+ var totalOffset = offset;
- return container;
-};
+ // If the parent is a ignored node, get offset from it's start
+ if (anchor.parentNode.classList.contains(ignoreClass)) {
+ curr = anchor.parentNode;
+ }
-EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {
- var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);
- var children = container.childNodes;
- var map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
- var i;
- var child;
- var len;
- var childIndex;
- var lastStepIndex = steps[steps.length-1].index;
-
- for (var childIndex in map) {
- if (!map.hasOwnProperty(childIndex)) return;
-
- if(map[childIndex] === lastStepIndex) {
- child = children[childIndex];
- len = child.textContent.length;
- if(offset > len) {
- offset = offset - len;
- } else {
- if (child.nodeType === ELEMENT_NODE) {
- container = child.childNodes[0];
+ while (curr.previousSibling) {
+ if(curr.previousSibling.nodeType === ELEMENT_NODE) {
+ // Originally a text node, so join
+ if(curr.previousSibling.classList.contains(ignoreClass)){
+ totalOffset += curr.previousSibling.textContent.length;
} else {
- container = child;
+ break; // Normal node, dont join
}
- break;
+ } else {
+ // If the previous sibling is a text node, join the nodes
+ totalOffset += curr.previousSibling.textContent.length;
}
- }
- }
- return {
- container: container,
- offset: offset
+ curr = curr.previousSibling;
+ }
+
+ return totalOffset;
+
};
-};
+ normalizedMap(children, nodeType, ignoreClass) {
+ var output = {};
+ var prevIndex = -1;
+ var i, len = children.length;
+ var currNodeType;
+ var prevNodeType;
-EpubCFI.prototype.toRange = function(_doc, ignoreClass) {
- var doc = _doc || document;
- var range = doc.createRange();
- var start, end, startContainer, endContainer;
- var cfi = this;
- var startSteps, endSteps;
- var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false;
- var missed;
+ for (i = 0; i < len; i++) {
- if (cfi.range) {
- start = cfi.start;
- startSteps = cfi.path.steps.concat(start.steps);
- startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null);
- end = cfi.end;
- endSteps = cfi.path.steps.concat(end.steps);
- endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null);
- } else {
- start = cfi.path;
- startSteps = cfi.path.steps;
- startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null);
- }
+ currNodeType = children[i].nodeType;
- if(startContainer) {
- try {
-
- if(start.terminal.offset != null) {
- range.setStart(startContainer, start.terminal.offset);
- } else {
- range.setStart(startContainer, 0);
+ // Check if needs ignoring
+ if (currNodeType === ELEMENT_NODE &&
+ children[i].classList.contains(ignoreClass)) {
+ currNodeType = TEXT_NODE;
}
- } catch (e) {
- missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null);
- range.setStart(missed.container, missed.offset);
- }
- } else {
- // No start found
- return null;
- }
-
- if (endContainer) {
- try {
-
- if(end.terminal.offset != null) {
- range.setEnd(endContainer, end.terminal.offset);
- } else {
- range.setEnd(endContainer, 0);
+ if (i > 0 &&
+ currNodeType === TEXT_NODE &&
+ prevNodeType === TEXT_NODE) {
+ // join text nodes
+ output[i] = prevIndex;
+ } else if (nodeType === currNodeType){
+ prevIndex = prevIndex + 1;
+ output[i] = prevIndex;
}
- } catch (e) {
- missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null);
- range.setEnd(missed.container, missed.offset);
+ prevNodeType = currNodeType;
+
}
+
+ return output;
+ };
+
+ position(anchor) {
+ var children, index, map;
+ var childNodes, node;
+ if (anchor.nodeType === ELEMENT_NODE) {
+ children = anchor.parentNode.children;
+ if (!children) {
+ children = findChildren(anchor.parentNode);
+ }
+ index = Array.prototype.indexOf.call(children, anchor);
+ } else {
+ children = this.textNodes(anchor.parentNode);
+ index = children.indexOf(anchor);
+ }
+
+ return index;
+ };
+
+ filteredPosition(anchor, ignoreClass) {
+ var children, index, map;
+
+ if (anchor.nodeType === ELEMENT_NODE) {
+ children = anchor.parentNode.children;
+ map = this.normalizedMap(children, ELEMENT_NODE, ignoreClass);
+ } else {
+ children = anchor.parentNode.childNodes;
+ // Inside an ignored node
+ if(anchor.parentNode.classList.contains(ignoreClass)) {
+ anchor = anchor.parentNode;
+ children = anchor.parentNode.childNodes;
+ }
+ map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
+ }
+
+
+ index = Array.prototype.indexOf.call(children, anchor);
+
+ return map[index];
+ };
+
+ stepsToXpath(steps) {
+ var xpath = [".", "*"];
+
+ steps.forEach(function(step){
+ var position = step.index + 1;
+
+ if(step.id){
+ xpath.push("*[position()=" + position + " and @id='" + step.id + "']");
+ } else if(step.type === "text") {
+ xpath.push("text()[" + position + "]");
+ } else {
+ xpath.push("*[" + position + "]");
+ }
+ });
+
+ return xpath.join("/");
+ };
+
+
+ /*
+
+ To get the last step if needed:
+
+ // Get the terminal step
+ lastStep = steps[steps.length-1];
+ // Get the query string
+ query = this.stepsToQuery(steps);
+ // Find the containing element
+ startContainerParent = doc.querySelector(query);
+ // Find the text node within that element
+ if(startContainerParent && lastStep.type == "text") {
+ container = startContainerParent.childNodes[lastStep.index];
}
+ */
+ stepsToQuerySelector(steps) {
+ var query = ["html"];
+
+ steps.forEach(function(step){
+ var position = step.index + 1;
+
+ if(step.id){
+ query.push("#" + step.id);
+ } else if(step.type === "text") {
+ // unsupported in querySelector
+ // query.push("text()[" + position + "]");
+ } else {
+ query.push("*:nth-child(" + position + ")");
+ }
+ });
+
+ return query.join(">");
+
+ };
+
+ textNodes(container, ignoreClass) {
+ return Array.prototype.slice.call(container.childNodes).
+ filter(function (node) {
+ if (node.nodeType === TEXT_NODE) {
+ return true;
+ } else if (ignoreClass && node.classList.contains(ignoreClass)) {
+ return true;
+ }
+ return false;
+ });
+ };
+
+ walkToNode(steps, _doc, ignoreClass) {
+ var doc = _doc || document;
+ var container = doc.documentElement;
+ var step;
+ var len = steps.length;
+ var i;
+
+ for (i = 0; i < len; i++) {
+ step = steps[i];
+
+ if(step.type === "element") {
+ container = container.children[step.index];
+ } else if(step.type === "text"){
+ container = this.textNodes(container, ignoreClass)[step.index];
+ }
+
+ };
+
+ return container;
+ };
+
+ findNode(steps, _doc, ignoreClass) {
+ var doc = _doc || document;
+ var container;
+ var xpath;
+
+ if(!ignoreClass && typeof doc.evaluate != 'undefined') {
+ xpath = this.stepsToXpath(steps);
+ container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+ } else if(ignoreClass) {
+ container = this.walkToNode(steps, doc, ignoreClass);
+ } else {
+ container = this.walkToNode(steps, doc);
+ }
+
+ return container;
+ };
+
+ fixMiss(steps, offset, _doc, ignoreClass) {
+ var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);
+ var children = container.childNodes;
+ var map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
+ var i;
+ var child;
+ var len;
+ var childIndex;
+ var lastStepIndex = steps[steps.length-1].index;
+
+ for (var childIndex in map) {
+ if (!map.hasOwnProperty(childIndex)) return;
+
+ if(map[childIndex] === lastStepIndex) {
+ child = children[childIndex];
+ len = child.textContent.length;
+ if(offset > len) {
+ offset = offset - len;
+ } else {
+ if (child.nodeType === ELEMENT_NODE) {
+ container = child.childNodes[0];
+ } else {
+ container = child;
+ }
+ break;
+ }
+ }
+ }
+
+ return {
+ container: container,
+ offset: offset
+ };
+
+ };
+
+ toRange(_doc, ignoreClass) {
+ var doc = _doc || document;
+ var range = doc.createRange();
+ var start, end, startContainer, endContainer;
+ var cfi = this;
+ var startSteps, endSteps;
+ var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false;
+ var missed;
+
+ if (cfi.range) {
+ start = cfi.start;
+ startSteps = cfi.path.steps.concat(start.steps);
+ startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null);
+ end = cfi.end;
+ endSteps = cfi.path.steps.concat(end.steps);
+ endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null);
+ } else {
+ start = cfi.path;
+ startSteps = cfi.path.steps;
+ startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null);
+ }
+
+ if(startContainer) {
+ try {
+
+ if(start.terminal.offset != null) {
+ range.setStart(startContainer, start.terminal.offset);
+ } else {
+ range.setStart(startContainer, 0);
+ }
+
+ } catch (e) {
+ missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null);
+ range.setStart(missed.container, missed.offset);
+ }
+ } else {
+ // No start found
+ return null;
+ }
+
+ if (endContainer) {
+ try {
+
+ if(end.terminal.offset != null) {
+ range.setEnd(endContainer, end.terminal.offset);
+ } else {
+ range.setEnd(endContainer, 0);
+ }
+
+ } catch (e) {
+ missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null);
+ range.setEnd(missed.container, missed.offset);
+ }
+ }
- // doc.defaultView.getSelection().addRange(range);
- return range;
-};
+ // doc.defaultView.getSelection().addRange(range);
+ return range;
+ };
-// is a cfi string, should be wrapped with "epubcfi()"
-EpubCFI.prototype.isCfiString = function(str) {
- if(typeof str === 'string' &&
- str.indexOf("epubcfi(") === 0 &&
- str[str.length-1] === ")") {
- return true;
- }
+ // is a cfi string, should be wrapped with "epubcfi()"
+ isCfiString(str) {
+ if(typeof str === 'string' &&
+ str.indexOf("epubcfi(") === 0 &&
+ str[str.length-1] === ")") {
+ return true;
+ }
- return false;
-};
+ return false;
+ };
-EpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) {
- var pos = parseInt(_pos),
- spineNodeIndex = _spineNodeIndex + 1,
- cfi = '/'+spineNodeIndex+'/';
+ generateChapterComponent(_spineNodeIndex, _pos, id) {
+ var pos = parseInt(_pos),
+ spineNodeIndex = _spineNodeIndex + 1,
+ cfi = '/'+spineNodeIndex+'/';
- cfi += (pos + 1) * 2;
+ cfi += (pos + 1) * 2;
- if(id) {
- cfi += "[" + id + "]";
- }
+ if(id) {
+ cfi += "[" + id + "]";
+ }
- return cfi;
-};
+ return cfi;
+ };
+}
-module.exports = EpubCFI;
+export default EpubCFI;
diff --git a/src/hook.js b/src/hook.js
index 27e774d..45c21c8 100644
--- a/src/hook.js
+++ b/src/hook.js
@@ -5,58 +5,59 @@
* @param {any} context scope of this
* @example this.content = new EPUBJS.Hook(this);
*/
-function Hook(context){
- this.context = context || this;
- this.hooks = [];
-};
+class Hook {
+ constructor(context){
+ this.context = context || this;
+ this.hooks = [];
+ };
-/**
- * Adds a function to be run before a hook completes
- * @example this.content.register(function(){...});
- */
-Hook.prototype.register = function(){
- for(var i = 0; i < arguments.length; ++i) {
- if (typeof arguments[i] === "function") {
- this.hooks.push(arguments[i]);
- } else {
- // unpack array
- for(var j = 0; j < arguments[i].length; ++j) {
- this.hooks.push(arguments[i][j]);
+ /**
+ * Adds a function to be run before a hook completes
+ * @example this.content.register(function(){...});
+ */
+ register(){
+ for(var i = 0; i < arguments.length; ++i) {
+ if (typeof arguments[i] === "function") {
+ this.hooks.push(arguments[i]);
+ } else {
+ // unpack array
+ for(var j = 0; j < arguments[i].length; ++j) {
+ this.hooks.push(arguments[i][j]);
+ }
}
}
- }
-};
+ };
-/**
- * Triggers a hook to run all functions
- * @example this.content.trigger(args).then(function(){...});
- */
-Hook.prototype.trigger = function(){
- var args = arguments;
- var context = this.context;
- var promises = [];
+ /**
+ * Triggers a hook to run all functions
+ * @example this.content.trigger(args).then(function(){...});
+ */
+ trigger(){
+ var args = arguments;
+ var context = this.context;
+ var promises = [];
- this.hooks.forEach(function(task, i) {
- var executing = task.apply(context, args);
+ this.hooks.forEach(function(task, i) {
+ var executing = task.apply(context, args);
- if(executing && typeof executing["then"] === "function") {
- // Task is a function that returns a promise
- promises.push(executing);
- }
- // Otherwise Task resolves immediately, continue
- });
+ if(executing && typeof executing["then"] === "function") {
+ // Task is a function that returns a promise
+ promises.push(executing);
+ }
+ // Otherwise Task resolves immediately, continue
+ });
- return Promise.all(promises);
-};
+ return Promise.all(promises);
+ };
-// Adds a function to be run before a hook completes
-Hook.prototype.list = function(){
- return this.hooks;
-};
+ // Adds a function to be run before a hook completes
+ list(){
+ return this.hooks;
+ };
-Hook.prototype.clear = function(){
- return this.hooks = [];
-};
-
-module.exports = Hook;
+ clear(){
+ return this.hooks = [];
+ };
+}
+export default Hook;
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..0341291
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,15 @@
+import Book from './book';
+import EpubCFI from './epubcfi';
+import Rendition from './rendition';
+import Contents from './contents';
+import Layout from './layout';
+import ePub from './epub';
+
+export default ePub;
+export {
+ Book,
+ EpubCFI,
+ Rendition,
+ Contents,
+ Layout
+};
diff --git a/src/layout.js b/src/layout.js
index 9f35846..eadbe27 100644
--- a/src/layout.js
+++ b/src/layout.js
@@ -1,4 +1,4 @@
-var core = require('./core');
+import core from './utils/core';
/**
* Figures out the CSS to apply for a layout
@@ -9,146 +9,148 @@ var core = require('./core');
* @param {[int=800]} settings.minSpreadWidth
* @param {[boolean=false]} settings.evenSpreads
*/
-function Layout(settings){
- this.name = settings.layout || "reflowable";
- this._spread = (settings.spread === "none") ? false : true;
- this._minSpreadWidth = settings.minSpreadWidth || 800;
- this._evenSpreads = settings.evenSpreads || false;
+class Layout {
+ constructor(settings) {
+ this.name = settings.layout || "reflowable";
+ this._spread = (settings.spread === "none") ? false : true;
+ this._minSpreadWidth = settings.minSpreadWidth || 800;
+ this._evenSpreads = settings.evenSpreads || false;
- if (settings.flow === "scrolled-continuous" ||
- settings.flow === "scrolled-doc") {
- this._flow = "scrolled";
- } else {
- this._flow = "paginated";
- }
+ if (settings.flow === "scrolled-continuous" ||
+ settings.flow === "scrolled-doc") {
+ this._flow = "scrolled";
+ } else {
+ this._flow = "paginated";
+ }
- this.width = 0;
- this.height = 0;
- this.spreadWidth = 0;
- this.delta = 0;
+ this.width = 0;
+ this.height = 0;
+ this.spreadWidth = 0;
+ this.delta = 0;
- this.columnWidth = 0;
- this.gap = 0;
- this.divisor = 1;
-};
-
-/**
- * Switch the flow between paginated and scrolled
- * @param {string} flow paginated | scrolled
- */
-Layout.prototype.flow = function(flow) {
- this._flow = (flow === "paginated") ? "paginated" : "scrolled";
-}
-
-/**
- * Switch between using spreads or not, and set the
- * width at which they switch to single.
- * @param {string} spread true | false
- * @param {boolean} min integer in pixels
- */
-Layout.prototype.spread = function(spread, min) {
-
- this._spread = (spread === "none") ? false : true;
-
- if (min >= 0) {
- this._minSpreadWidth = min;
- }
-}
-
-/**
- * Calculate the dimensions of the pagination
- * @param {number} _width [description]
- * @param {number} _height [description]
- * @param {number} _gap [description]
- */
-Layout.prototype.calculate = function(_width, _height, _gap){
-
- var divisor = 1;
- var gap = _gap || 0;
-
- //-- Check the width and create even width columns
- var fullWidth = Math.floor(_width);
- var width = _width;
-
- var section = Math.floor(width / 8);
-
- var colWidth;
- var spreadWidth;
- var delta;
-
- if (this._spread && width >= this._minSpreadWidth) {
- divisor = 2;
- } else {
- divisor = 1;
- }
-
- if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) {
- gap = ((section % 2 === 0) ? section : section - 1);
- }
-
- if (this.name === "pre-paginated" ) {
- gap = 0;
- }
-
- //-- Double Page
- if(divisor > 1) {
- colWidth = (width - gap) / divisor;
- } else {
- colWidth = width;
- }
-
- if (this.name === "pre-paginated" && divisor > 1) {
- width = colWidth;
- }
-
- spreadWidth = colWidth * divisor;
-
- delta = (colWidth + gap) * divisor;
-
- this.width = width;
- this.height = _height;
- this.spreadWidth = spreadWidth;
- this.delta = delta;
-
- this.columnWidth = colWidth;
- this.gap = gap;
- this.divisor = divisor;
-};
-
-/**
- * Apply Css to a Document
- * @param {Contents} contents
- * @return {[Promise]}
- */
-Layout.prototype.format = function(contents){
- var formating;
-
- if (this.name === "pre-paginated") {
- formating = contents.fit(this.columnWidth, this.height);
- } else if (this._flow === "paginated") {
- formating = contents.columns(this.width, this.height, this.columnWidth, this.gap);
- } else { // scrolled
- formating = contents.size(this.width, null);
- }
-
- return formating; // might be a promise in some View Managers
-};
-
-/**
- * Count number of pages
- * @param {number} totalWidth
- * @return {number} spreads
- * @return {number} pages
- */
-Layout.prototype.count = function(totalWidth) {
- // var totalWidth = contents.scrollWidth();
- var spreads = Math.ceil( totalWidth / this.spreadWidth);
-
- return {
- spreads : spreads,
- pages : spreads * this.divisor
+ this.columnWidth = 0;
+ this.gap = 0;
+ this.divisor = 1;
};
-};
-module.exports = Layout;
+ /**
+ * Switch the flow between paginated and scrolled
+ * @param {string} flow paginated | scrolled
+ */
+ flow(flow) {
+ this._flow = (flow === "paginated") ? "paginated" : "scrolled";
+ }
+
+ /**
+ * Switch between using spreads or not, and set the
+ * width at which they switch to single.
+ * @param {string} spread true | false
+ * @param {boolean} min integer in pixels
+ */
+ spread(spread, min) {
+
+ this._spread = (spread === "none") ? false : true;
+
+ if (min >= 0) {
+ this._minSpreadWidth = min;
+ }
+ }
+
+ /**
+ * Calculate the dimensions of the pagination
+ * @param {number} _width [description]
+ * @param {number} _height [description]
+ * @param {number} _gap [description]
+ */
+ calculate(_width, _height, _gap){
+
+ var divisor = 1;
+ var gap = _gap || 0;
+
+ //-- Check the width and create even width columns
+ var fullWidth = Math.floor(_width);
+ var width = _width;
+
+ var section = Math.floor(width / 8);
+
+ var colWidth;
+ var spreadWidth;
+ var delta;
+
+ if (this._spread && width >= this._minSpreadWidth) {
+ divisor = 2;
+ } else {
+ divisor = 1;
+ }
+
+ if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) {
+ gap = ((section % 2 === 0) ? section : section - 1);
+ }
+
+ if (this.name === "pre-paginated" ) {
+ gap = 0;
+ }
+
+ //-- Double Page
+ if(divisor > 1) {
+ colWidth = (width - gap) / divisor;
+ } else {
+ colWidth = width;
+ }
+
+ if (this.name === "pre-paginated" && divisor > 1) {
+ width = colWidth;
+ }
+
+ spreadWidth = colWidth * divisor;
+
+ delta = (colWidth + gap) * divisor;
+
+ this.width = width;
+ this.height = _height;
+ this.spreadWidth = spreadWidth;
+ this.delta = delta;
+
+ this.columnWidth = colWidth;
+ this.gap = gap;
+ this.divisor = divisor;
+ };
+
+ /**
+ * Apply Css to a Document
+ * @param {Contents} contents
+ * @return {[Promise]}
+ */
+ format(contents){
+ var formating;
+
+ if (this.name === "pre-paginated") {
+ formating = contents.fit(this.columnWidth, this.height);
+ } else if (this._flow === "paginated") {
+ formating = contents.columns(this.width, this.height, this.columnWidth, this.gap);
+ } else { // scrolled
+ formating = contents.size(this.width, null);
+ }
+
+ return formating; // might be a promise in some View Managers
+ };
+
+ /**
+ * Count number of pages
+ * @param {number} totalWidth
+ * @return {number} spreads
+ * @return {number} pages
+ */
+ count(totalWidth) {
+ // var totalWidth = contents.scrollWidth();
+ var spreads = Math.ceil( totalWidth / this.spreadWidth);
+
+ return {
+ spreads : spreads,
+ pages : spreads * this.divisor
+ };
+ };
+}
+
+export default Layout;
diff --git a/src/locations.js b/src/locations.js
index a8c366b..2fe69bf 100644
--- a/src/locations.js
+++ b/src/locations.js
@@ -1,257 +1,258 @@
-var core = require('./core');
-var Queue = require('./queue');
-var EpubCFI = require('./epubcfi');
-var EventEmitter = require('event-emitter');
+import {qs, sprint, locationOf} from './utils/core';
+import Queue from './queue';
+import EpubCFI from './epubcfi';
+import EventEmitter from 'event-emitter';
/**
* Find Locations for a Book
* @param {Spine} spine
* @param {request} request
*/
-function Locations(spine, request) {
- this.spine = spine;
- this.request = request;
+class Locations {
+ constructor(spine, request) {
+ this.spine = spine;
+ this.request = request;
- this.q = new Queue(this);
- this.epubcfi = new EpubCFI();
+ this.q = new Queue(this);
+ this.epubcfi = new EpubCFI();
- this._locations = [];
- this.total = 0;
+ this._locations = [];
+ this.total = 0;
- this.break = 150;
+ this.break = 150;
- this._current = 0;
+ this._current = 0;
-};
-
-/**
- * Load all of sections in the book to generate locations
- * @param {int} chars how many chars to split on
- * @return {object} locations
- */
-Locations.prototype.generate = function(chars) {
-
- if (chars) {
- this.break = chars;
- }
-
- this.q.pause();
-
- this.spine.each(function(section) {
-
- this.q.enqueue(this.process.bind(this), section);
-
- }.bind(this));
-
- return this.q.run().then(function() {
- this.total = this._locations.length-1;
-
- if (this._currentCfi) {
- this.currentLocation = this._currentCfi;
- }
-
- return this._locations;
- // console.log(this.percentage(this.book.rendition.location.start), this.percentage(this.book.rendition.location.end));
- }.bind(this));
-
-};
-
-Locations.prototype.createRange = function () {
- return {
- startContainer: undefined,
- startOffset: undefined,
- endContainer: undefined,
- endOffset: undefined
- }
-};
-
-Locations.prototype.process = function(section) {
-
- return section.load(this.request)
- .then(function(contents) {
- var locations = this.parse(contents, section.cfiBase);
- this._locations = this._locations.concat(locations);
- }.bind(this));
-
-};
-
-Locations.prototype.parse = function(contents, cfiBase, chars) {
- var locations = [];
- var range;
- var doc = contents.ownerDocument;
- var body = core.qs(doc, 'body');
- var counter = 0;
- var prev;
- var _break = chars || this.break;
- var parser = function(node) {
- var len = node.length;
- var dist;
- var pos = 0;
-
- if (node.textContent.trim().length === 0) {
- return false; // continue
- }
-
- // Start range
- if (counter == 0) {
- range = this.createRange();
- range.startContainer = node;
- range.startOffset = 0;
- }
-
- dist = _break - counter;
-
- // Node is smaller than a break,
- // skip over it
- if(dist > len){
- counter += len;
- pos = len;
- }
-
- while (pos < len) {
- // counter = this.break;
- pos += dist;
- // Gone over
- if(pos >= len){
- // Continue counter for next node
- counter = len - (pos - _break);
- // At End
- } else {
- // End the previous range
- range.endContainer = node;
- range.endOffset = pos;
- // cfi = section.cfiFromRange(range);
- cfi = new EpubCFI(range, cfiBase).toString();
- locations.push(cfi);
- counter = 0;
-
- // Start new range
- pos += 1;
- range = this.createRange();
- range.startContainer = node;
- range.startOffset = pos;
-
- dist = _break;
- }
- }
- prev = node;
};
- core.sprint(body, parser.bind(this));
+ /**
+ * Load all of sections in the book to generate locations
+ * @param {int} chars how many chars to split on
+ * @return {object} locations
+ */
+ generate(chars) {
- // Close remaining
- if (range && range.startContainer && prev) {
- range.endContainer = prev;
- range.endOffset = prev.length;
- // cfi = section.cfiFromRange(range);
- cfi = new EpubCFI(range, cfiBase).toString();
- locations.push(cfi);
- counter = 0;
- }
+ if (chars) {
+ this.break = chars;
+ }
- return locations;
-};
+ this.q.pause();
-Locations.prototype.locationFromCfi = function(cfi){
- // Check if the location has not been set yet
- if(this._locations.length === 0) {
- return -1;
- }
- return core.locationOf(cfi.start, this._locations, this.epubcfi.compare);
-};
+ this.spine.each(function(section) {
-Locations.prototype.percentageFromCfi = function(cfi) {
- if(this._locations.length === 0) {
- return null;
- }
- // Find closest cfi
- var loc = this.locationFromCfi(cfi);
- // Get percentage in total
- return this.percentageFromLocation(loc);
-};
+ this.q.enqueue(this.process.bind(this), section);
-Locations.prototype.percentageFromLocation = function(loc) {
- if (!loc || !this.total) {
- return 0;
- }
- return (loc / this.total);
-};
+ }.bind(this));
-Locations.prototype.cfiFromLocation = function(loc){
- var cfi = -1;
- // check that pg is an int
- if(typeof loc != "number"){
- loc = parseInt(pg);
- }
+ return this.q.run().then(function() {
+ this.total = this._locations.length-1;
- if(loc >= 0 && loc < this._locations.length) {
- cfi = this._locations[loc];
- }
+ if (this._currentCfi) {
+ this.currentLocation = this._currentCfi;
+ }
- return cfi;
-};
+ return this._locations;
+ // console.log(this.percentage(this.book.rendition.location.start), this.percentage(this.book.rendition.location.end));
+ }.bind(this));
-Locations.prototype.cfiFromPercentage = function(value){
- var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1
- var loc = Math.ceil(this.total * percentage);
+ };
- return this.cfiFromLocation(loc);
-};
+ createRange () {
+ return {
+ startContainer: undefined,
+ startOffset: undefined,
+ endContainer: undefined,
+ endOffset: undefined
+ }
+ };
-Locations.prototype.load = function(locations){
- this._locations = JSON.parse(locations);
- this.total = this._locations.length-1;
- return this._locations;
-};
+ process(section) {
-Locations.prototype.save = function(json){
- return JSON.stringify(this._locations);
-};
+ return section.load(this.request)
+ .then(function(contents) {
+ var locations = this.parse(contents, section.cfiBase);
+ this._locations = this._locations.concat(locations);
+ }.bind(this));
-Locations.prototype.getCurrent = function(json){
- return this._current;
-};
+ };
-Locations.prototype.setCurrent = function(curr){
- var loc;
+ parse(contents, cfiBase, chars) {
+ var locations = [];
+ var range;
+ var doc = contents.ownerDocument;
+ var body = qs(doc, 'body');
+ var counter = 0;
+ var prev;
+ var _break = chars || this.break;
+ var parser = function(node) {
+ var len = node.length;
+ var dist;
+ var pos = 0;
- if(typeof curr == "string"){
- this._currentCfi = curr;
- } else if (typeof curr == "number") {
- this._current = curr;
- } else {
- return;
- }
+ if (node.textContent.trim().length === 0) {
+ return false; // continue
+ }
- if(this._locations.length === 0) {
- return;
- }
+ // Start range
+ if (counter == 0) {
+ range = this.createRange();
+ range.startContainer = node;
+ range.startOffset = 0;
+ }
- if(typeof curr == "string"){
- loc = this.locationFromCfi(curr);
- this._current = loc;
- } else {
- loc = curr;
- }
+ dist = _break - counter;
- this.emit("changed", {
- percentage: this.percentageFromLocation(loc)
- });
-};
+ // Node is smaller than a break,
+ // skip over it
+ if(dist > len){
+ counter += len;
+ pos = len;
+ }
-Object.defineProperty(Locations.prototype, 'currentLocation', {
- get: function () {
+ while (pos < len) {
+ // counter = this.break;
+ pos += dist;
+ // Gone over
+ if(pos >= len){
+ // Continue counter for next node
+ counter = len - (pos - _break);
+ // At End
+ } else {
+ // End the previous range
+ range.endContainer = node;
+ range.endOffset = pos;
+ // cfi = section.cfiFromRange(range);
+ let cfi = new EpubCFI(range, cfiBase).toString();
+ locations.push(cfi);
+ counter = 0;
+
+ // Start new range
+ pos += 1;
+ range = this.createRange();
+ range.startContainer = node;
+ range.startOffset = pos;
+
+ dist = _break;
+ }
+ }
+ prev = node;
+ };
+
+ sprint(body, parser.bind(this));
+
+ // Close remaining
+ if (range && range.startContainer && prev) {
+ range.endContainer = prev;
+ range.endOffset = prev.length;
+ // cfi = section.cfiFromRange(range);
+ let cfi = new EpubCFI(range, cfiBase).toString();
+ locations.push(cfi);
+ counter = 0;
+ }
+
+ return locations;
+ };
+
+ locationFromCfi(cfi){
+ // Check if the location has not been set yet
+ if(this._locations.length === 0) {
+ return -1;
+ }
+ return locationOf(cfi.start, this._locations, this.epubcfi.compare);
+ };
+
+ percentageFromCfi(cfi) {
+ if(this._locations.length === 0) {
+ return null;
+ }
+ // Find closest cfi
+ var loc = this.locationFromCfi(cfi);
+ // Get percentage in total
+ return this.percentageFromLocation(loc);
+ };
+
+ percentageFromLocation(loc) {
+ if (!loc || !this.total) {
+ return 0;
+ }
+ return (loc / this.total);
+ };
+
+ cfiFromLocation(loc){
+ var cfi = -1;
+ // check that pg is an int
+ if(typeof loc != "number"){
+ loc = parseInt(pg);
+ }
+
+ if(loc >= 0 && loc < this._locations.length) {
+ cfi = this._locations[loc];
+ }
+
+ return cfi;
+ };
+
+ cfiFromPercentage(value){
+ var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1
+ var loc = Math.ceil(this.total * percentage);
+
+ return this.cfiFromLocation(loc);
+ };
+
+ load(locations){
+ this._locations = JSON.parse(locations);
+ this.total = this._locations.length-1;
+ return this._locations;
+ };
+
+ save(json){
+ return JSON.stringify(this._locations);
+ };
+
+ getCurrent(json){
return this._current;
- },
- set: function (curr) {
+ };
+
+ setCurrent(curr){
+ var loc;
+
+ if(typeof curr == "string"){
+ this._currentCfi = curr;
+ } else if (typeof curr == "number") {
+ this._current = curr;
+ } else {
+ return;
+ }
+
+ if(this._locations.length === 0) {
+ return;
+ }
+
+ if(typeof curr == "string"){
+ loc = this.locationFromCfi(curr);
+ this._current = loc;
+ } else {
+ loc = curr;
+ }
+
+ this.emit("changed", {
+ percentage: this.percentageFromLocation(loc)
+ });
+ };
+
+ get currentLocation() {
+ return this._current;
+ }
+
+ set currentLocation(curr) {
this.setCurrent(curr);
}
-});
-Locations.prototype.length = function () {
- return this._locations.length;
-};
+ length () {
+ return this._locations.length;
+ };
+}
EventEmitter(Locations.prototype);
-module.exports = Locations;
+export default Locations;
diff --git a/src/managers/continuous/index.js b/src/managers/continuous/index.js
index 90fd670..53b8992 100644
--- a/src/managers/continuous/index.js
+++ b/src/managers/continuous/index.js
@@ -1,679 +1,680 @@
-var core = require('../../core');
-var DefaultViewManager = require('../default');
+import {extend, defer, requestAnimationFrame} from '../../utils/core';
+import DefaultViewManager from '../default';
-function ContinuousViewManager(options) {
+class ContinuousViewManager extends DefaultViewManager {
+ constructor(options) {
+ super(options)
+ // DefaultViewManager.apply(this, arguments); // call super constructor.
- DefaultViewManager.apply(this, arguments); // call super constructor.
+ this.name = "continuous";
- this.name = "continuous";
+ this.settings = extend(this.settings || {}, {
+ infinite: true,
+ overflow: "auto",
+ axis: "vertical",
+ offset: 500,
+ offsetDelta: 250,
+ width: undefined,
+ height: undefined
+ });
- this.settings = core.extend(this.settings || {}, {
- infinite: true,
- overflow: "auto",
- axis: "vertical",
- offset: 500,
- offsetDelta: 250,
- width: undefined,
- height: undefined
- });
+ extend(this.settings, options.settings || {});
- core.extend(this.settings, options.settings || {});
+ // Gap can be 0, byt defaults doesn't handle that
+ if (options.settings.gap != "undefined" && options.settings.gap === 0) {
+ this.settings.gap = options.settings.gap;
+ }
- // Gap can be 0, byt defaults doesn't handle that
- if (options.settings.gap != "undefined" && options.settings.gap === 0) {
- this.settings.gap = options.settings.gap;
- }
+ // this.viewSettings.axis = this.settings.axis;
+ this.viewSettings = {
+ ignoreClass: this.settings.ignoreClass,
+ axis: this.settings.axis,
+ layout: this.layout,
+ width: 0,
+ height: 0
+ };
- // this.viewSettings.axis = this.settings.axis;
- this.viewSettings = {
- ignoreClass: this.settings.ignoreClass,
- axis: this.settings.axis,
- layout: this.layout,
- width: 0,
- height: 0
+ this.scrollTop = 0;
+ this.scrollLeft = 0;
};
- this.scrollTop = 0;
- this.scrollLeft = 0;
-};
+ display(section, target){
+ return DefaultViewManager.prototype.display.call(this, section, target)
+ .then(function () {
+ return this.fill();
+ }.bind(this));
+ };
-// subclass extends superclass
-ContinuousViewManager.prototype = Object.create(DefaultViewManager.prototype);
-ContinuousViewManager.prototype.constructor = ContinuousViewManager;
+ fill(_full){
+ var full = _full || new defer();
-ContinuousViewManager.prototype.display = function(section, target){
- return DefaultViewManager.prototype.display.call(this, section, target)
- .then(function () {
- return this.fill();
- }.bind(this));
-};
-
-ContinuousViewManager.prototype.fill = function(_full){
- var full = _full || new core.defer();
-
- this.check().then(function(result) {
- if (result) {
- this.fill(full);
- } else {
- full.resolve();
- }
- }.bind(this));
-
- return full.promise;
-}
-
-ContinuousViewManager.prototype.moveTo = function(offset){
- // var bounds = this.stage.bounds();
- // var dist = Math.floor(offset.top / bounds.height) * bounds.height;
- var distX = 0,
- distY = 0;
-
- var offsetX = 0,
- offsetY = 0;
-
- if(this.settings.axis === "vertical") {
- distY = offset.top;
- offsetY = offset.top+this.settings.offset;
- } else {
- distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;
- offsetX = distX+this.settings.offset;
- }
-
- return this.check(offsetX, offsetY)
- .then(function(){
- this.scrollBy(distX, distY);
- }.bind(this));
-};
-
-/*
-ContinuousViewManager.prototype.afterDisplayed = function(currView){
- var next = currView.section.next();
- var prev = currView.section.prev();
- var index = this.views.indexOf(currView);
- var prevView, nextView;
-
- if(index + 1 === this.views.length && next) {
- nextView = this.createView(next);
- this.q.enqueue(this.append.bind(this), nextView);
- }
-
- if(index === 0 && prev) {
- prevView = this.createView(prev, this.viewSettings);
- this.q.enqueue(this.prepend.bind(this), prevView);
- }
-
- // this.removeShownListeners(currView);
- // currView.onShown = this.afterDisplayed.bind(this);
- this.emit("added", currView.section);
-
-};
-*/
-
-ContinuousViewManager.prototype.resize = function(width, height){
-
- // Clear the queue
- this.q.clear();
-
- this._stageSize = this.stage.size(width, height);
- this._bounds = this.bounds();
-
- // Update for new views
- this.viewSettings.width = this._stageSize.width;
- this.viewSettings.height = this._stageSize.height;
-
- // Update for existing views
- this.views.each(function(view) {
- view.size(this._stageSize.width, this._stageSize.height);
- }.bind(this));
-
- this.updateLayout();
-
- // if(this.location) {
- // this.rendition.display(this.location.start);
- // }
-
- this.emit("resized", {
- width: this.stage.width,
- height: this.stage.height
- });
-
-};
-
-ContinuousViewManager.prototype.onResized = function(e) {
-
- // this.views.clear();
-
- clearTimeout(this.resizeTimeout);
- this.resizeTimeout = setTimeout(function(){
- this.resize();
- }.bind(this), 150);
-};
-
-ContinuousViewManager.prototype.afterResized = function(view){
- this.emit("resize", view.section);
-};
-
-// Remove Previous Listeners if present
-ContinuousViewManager.prototype.removeShownListeners = function(view){
-
- // view.off("shown", this.afterDisplayed);
- // view.off("shown", this.afterDisplayedAbove);
- view.onDisplayed = function(){};
-
-};
-
-
-// ContinuousViewManager.prototype.append = function(section){
-// return this.q.enqueue(function() {
-//
-// this._append(section);
-//
-//
-// }.bind(this));
-// };
-//
-// ContinuousViewManager.prototype.prepend = function(section){
-// return this.q.enqueue(function() {
-//
-// this._prepend(section);
-//
-// }.bind(this));
-//
-// };
-
-ContinuousViewManager.prototype.append = function(section){
- var view = this.createView(section);
- this.views.append(view);
- return view;
-};
-
-ContinuousViewManager.prototype.prepend = function(section){
- var view = this.createView(section);
-
- view.on("resized", this.counter.bind(this));
-
- this.views.prepend(view);
- return view;
-};
-
-ContinuousViewManager.prototype.counter = function(bounds){
-
- if(this.settings.axis === "vertical") {
- this.scrollBy(0, bounds.heightDelta, true);
- } else {
- this.scrollBy(bounds.widthDelta, 0, true);
- }
-
-};
-
-ContinuousViewManager.prototype.update = function(_offset){
- var container = this.bounds();
- var views = this.views.all();
- var viewsLength = views.length;
- var visible = [];
- var offset = typeof _offset != "undefined" ? _offset : (this.settings.offset || 0);
- var isVisible;
- var view;
-
- var updating = new core.defer();
- var promises = [];
-
- for (var i = 0; i < viewsLength; i++) {
- view = views[i];
-
- isVisible = this.isVisible(view, offset, offset, container);
-
- if(isVisible === true) {
- if (!view.displayed) {
- promises.push(view.display(this.request).then(function (view) {
- view.show();
- }));
+ this.check().then(function(result) {
+ if (result) {
+ this.fill(full);
+ } else {
+ full.resolve();
}
- visible.push(view);
- } else {
- this.q.enqueue(view.destroy.bind(view));
-
- clearTimeout(this.trimTimeout);
- this.trimTimeout = setTimeout(function(){
- this.q.enqueue(this.trim.bind(this));
- }.bind(this), 250);
- }
+ }.bind(this));
+ return full.promise;
}
- if(promises.length){
- return Promise.all(promises);
- } else {
- updating.resolve();
- return updating.promise;
- }
+ moveTo(offset){
+ // var bounds = this.stage.bounds();
+ // var dist = Math.floor(offset.top / bounds.height) * bounds.height;
+ var distX = 0,
+ distY = 0;
-};
-
-ContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){
- var last, first, next, prev;
-
- var checking = new core.defer();
- var newViews = [];
-
- var horizontal = (this.settings.axis === "horizontal");
- var delta = this.settings.offset || 0;
-
- if (_offsetLeft && horizontal) {
- delta = _offsetLeft;
- }
-
- if (_offsetTop && !horizontal) {
- delta = _offsetTop;
- }
-
- var bounds = this._bounds; // bounds saved this until resize
-
- var offset = horizontal ? this.scrollLeft : this.scrollTop;
- var visibleLength = horizontal ? bounds.width : bounds.height;
- var contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight;
-
- if (offset + visibleLength + delta >= contentLength) {
- last = this.views.last();
- next = last && last.section.next();
- if(next) {
- newViews.push(this.append(next));
- }
- }
-
- if (offset - delta < 0 ) {
- first = this.views.first();
- prev = first && first.section.prev();
- if(prev) {
- newViews.push(this.prepend(prev));
- }
- }
-
- if(newViews.length){
- // Promise.all(promises)
- // .then(function() {
- // Check to see if anything new is on screen after rendering
- return this.q.enqueue(function(){
- return this.update(delta);
- }.bind(this));
-
-
- // }.bind(this));
-
- } else {
- checking.resolve(false);
- return checking.promise;
- }
-
-
-};
-
-ContinuousViewManager.prototype.trim = function(){
- var task = new core.defer();
- var displayed = this.views.displayed();
- var first = displayed[0];
- var last = displayed[displayed.length-1];
- var firstIndex = this.views.indexOf(first);
- var lastIndex = this.views.indexOf(last);
- var above = this.views.slice(0, firstIndex);
- var below = this.views.slice(lastIndex+1);
-
- // Erase all but last above
- for (var i = 0; i < above.length-1; i++) {
- this.erase(above[i], above);
- }
-
- // Erase all except first below
- for (var j = 1; j < below.length; j++) {
- this.erase(below[j]);
- }
-
- task.resolve();
- return task.promise;
-};
-
-ContinuousViewManager.prototype.erase = function(view, above){ //Trim
-
- var prevTop;
- var prevLeft;
-
- if(this.settings.height) {
- prevTop = this.container.scrollTop;
- prevLeft = this.container.scrollLeft;
- } else {
- prevTop = window.scrollY;
- prevLeft = window.scrollX;
- }
-
- var bounds = view.bounds();
-
- this.views.remove(view);
-
- if(above) {
+ var offsetX = 0,
+ offsetY = 0;
if(this.settings.axis === "vertical") {
- this.scrollTo(0, prevTop - bounds.height, true);
+ distY = offset.top;
+ offsetY = offset.top+this.settings.offset;
} else {
- this.scrollTo(prevLeft - bounds.width, 0, true);
+ distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;
+ offsetX = distX+this.settings.offset;
}
- }
-};
+ return this.check(offsetX, offsetY)
+ .then(function(){
+ this.scrollBy(distX, distY);
+ }.bind(this));
+ };
-ContinuousViewManager.prototype.addEventListeners = function(stage){
+ /*
+ afterDisplayed(currView){
+ var next = currView.section.next();
+ var prev = currView.section.prev();
+ var index = this.views.indexOf(currView);
+ var prevView, nextView;
- window.addEventListener('unload', function(e){
- this.ignore = true;
- // this.scrollTo(0,0);
- this.destroy();
- }.bind(this));
+ if(index + 1 === this.views.length && next) {
+ nextView = this.createView(next);
+ this.q.enqueue(this.append.bind(this), nextView);
+ }
- this.addScrollListeners();
-};
+ if(index === 0 && prev) {
+ prevView = this.createView(prev, this.viewSettings);
+ this.q.enqueue(this.prepend.bind(this), prevView);
+ }
-ContinuousViewManager.prototype.addScrollListeners = function() {
- var scroller;
+ // this.removeShownListeners(currView);
+ // currView.onShown = this.afterDisplayed.bind(this);
+ this.emit("added", currView.section);
- this.tick = core.requestAnimationFrame;
+ };
+ */
- if(this.settings.height) {
- this.prevScrollTop = this.container.scrollTop;
- this.prevScrollLeft = this.container.scrollLeft;
- } else {
- this.prevScrollTop = window.scrollY;
- this.prevScrollLeft = window.scrollX;
- }
+ resize(width, height){
- this.scrollDeltaVert = 0;
- this.scrollDeltaHorz = 0;
+ // Clear the queue
+ this.q.clear();
- if(this.settings.height) {
- scroller = this.container;
- this.scrollTop = this.container.scrollTop;
- this.scrollLeft = this.container.scrollLeft;
- } else {
- scroller = window;
- this.scrollTop = window.scrollY;
- this.scrollLeft = window.scrollX;
- }
+ this._stageSize = this.stage.size(width, height);
+ this._bounds = this.bounds();
- scroller.addEventListener("scroll", this.onScroll.bind(this));
+ // Update for new views
+ this.viewSettings.width = this._stageSize.width;
+ this.viewSettings.height = this._stageSize.height;
- // this.tick.call(window, this.onScroll.bind(this));
+ // Update for existing views
+ this.views.each(function(view) {
+ view.size(this._stageSize.width, this._stageSize.height);
+ }.bind(this));
- this.scrolled = false;
+ this.updateLayout();
-};
+ // if(this.location) {
+ // this.rendition.display(this.location.start);
+ // }
-ContinuousViewManager.prototype.onScroll = function(){
+ this.emit("resized", {
+ width: this.stage.width,
+ height: this.stage.height
+ });
- // if(!this.ignore) {
+ };
+
+ onResized(e) {
+
+ // this.views.clear();
+
+ clearTimeout(this.resizeTimeout);
+ this.resizeTimeout = setTimeout(function(){
+ this.resize();
+ }.bind(this), 150);
+ };
+
+ afterResized(view){
+ this.emit("resize", view.section);
+ };
+
+ // Remove Previous Listeners if present
+ removeShownListeners(view){
+
+ // view.off("shown", this.afterDisplayed);
+ // view.off("shown", this.afterDisplayedAbove);
+ view.onDisplayed = function(){};
+
+ };
+
+
+ // append(section){
+ // return this.q.enqueue(function() {
+ //
+ // this._append(section);
+ //
+ //
+ // }.bind(this));
+ // };
+ //
+ // prepend(section){
+ // return this.q.enqueue(function() {
+ //
+ // this._prepend(section);
+ //
+ // }.bind(this));
+ //
+ // };
+
+ append(section){
+ var view = this.createView(section);
+ this.views.append(view);
+ return view;
+ };
+
+ prepend(section){
+ var view = this.createView(section);
+
+ view.on("resized", this.counter.bind(this));
+
+ this.views.prepend(view);
+ return view;
+ };
+
+ counter(bounds){
+
+ if(this.settings.axis === "vertical") {
+ this.scrollBy(0, bounds.heightDelta, true);
+ } else {
+ this.scrollBy(bounds.widthDelta, 0, true);
+ }
+
+ };
+
+ update(_offset){
+ var container = this.bounds();
+ var views = this.views.all();
+ var viewsLength = views.length;
+ var visible = [];
+ var offset = typeof _offset != "undefined" ? _offset : (this.settings.offset || 0);
+ var isVisible;
+ var view;
+
+ var updating = new defer();
+ var promises = [];
+
+ for (var i = 0; i < viewsLength; i++) {
+ view = views[i];
+
+ isVisible = this.isVisible(view, offset, offset, container);
+
+ if(isVisible === true) {
+ if (!view.displayed) {
+ promises.push(view.display(this.request).then(function (view) {
+ view.show();
+ }));
+ }
+ visible.push(view);
+ } else {
+ this.q.enqueue(view.destroy.bind(view));
+
+ clearTimeout(this.trimTimeout);
+ this.trimTimeout = setTimeout(function(){
+ this.q.enqueue(this.trim.bind(this));
+ }.bind(this), 250);
+ }
+
+ }
+
+ if(promises.length){
+ return Promise.all(promises);
+ } else {
+ updating.resolve();
+ return updating.promise;
+ }
+
+ };
+
+ check(_offsetLeft, _offsetTop){
+ var last, first, next, prev;
+
+ var checking = new defer();
+ var newViews = [];
+
+ var horizontal = (this.settings.axis === "horizontal");
+ var delta = this.settings.offset || 0;
+
+ if (_offsetLeft && horizontal) {
+ delta = _offsetLeft;
+ }
+
+ if (_offsetTop && !horizontal) {
+ delta = _offsetTop;
+ }
+
+ var bounds = this._bounds; // bounds saved this until resize
+
+ var offset = horizontal ? this.scrollLeft : this.scrollTop;
+ var visibleLength = horizontal ? bounds.width : bounds.height;
+ var contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight;
+
+ if (offset + visibleLength + delta >= contentLength) {
+ last = this.views.last();
+ next = last && last.section.next();
+ if(next) {
+ newViews.push(this.append(next));
+ }
+ }
+
+ if (offset - delta < 0 ) {
+ first = this.views.first();
+ prev = first && first.section.prev();
+ if(prev) {
+ newViews.push(this.prepend(prev));
+ }
+ }
+
+ if(newViews.length){
+ // Promise.all(promises)
+ // .then(function() {
+ // Check to see if anything new is on screen after rendering
+ return this.q.enqueue(function(){
+ return this.update(delta);
+ }.bind(this));
+
+
+ // }.bind(this));
+
+ } else {
+ checking.resolve(false);
+ return checking.promise;
+ }
+
+
+ };
+
+ trim(){
+ var task = new defer();
+ var displayed = this.views.displayed();
+ var first = displayed[0];
+ var last = displayed[displayed.length-1];
+ var firstIndex = this.views.indexOf(first);
+ var lastIndex = this.views.indexOf(last);
+ var above = this.views.slice(0, firstIndex);
+ var below = this.views.slice(lastIndex+1);
+
+ // Erase all but last above
+ for (var i = 0; i < above.length-1; i++) {
+ this.erase(above[i], above);
+ }
+
+ // Erase all except first below
+ for (var j = 1; j < below.length; j++) {
+ this.erase(below[j]);
+ }
+
+ task.resolve();
+ return task.promise;
+ };
+
+ erase(view, above){ //Trim
+
+ var prevTop;
+ var prevLeft;
if(this.settings.height) {
- scrollTop = this.container.scrollTop;
- scrollLeft = this.container.scrollLeft;
+ prevTop = this.container.scrollTop;
+ prevLeft = this.container.scrollLeft;
} else {
- scrollTop = window.scrollY;
- scrollLeft = window.scrollX;
+ prevTop = window.scrollY;
+ prevLeft = window.scrollX;
}
- this.scrollTop = scrollTop;
- this.scrollLeft = scrollLeft;
+ var bounds = view.bounds();
- if(!this.ignore) {
+ this.views.remove(view);
- if((this.scrollDeltaVert === 0 &&
- this.scrollDeltaHorz === 0) ||
- this.scrollDeltaVert > this.settings.offsetDelta ||
- this.scrollDeltaHorz > this.settings.offsetDelta) {
-
- this.q.enqueue(function() {
- this.check();
- }.bind(this));
- // this.check();
-
- this.scrollDeltaVert = 0;
- this.scrollDeltaHorz = 0;
-
- this.emit("scroll", {
- top: scrollTop,
- left: scrollLeft
- });
-
- clearTimeout(this.afterScrolled);
- this.afterScrolled = setTimeout(function () {
- this.emit("scrolled", {
- top: this.scrollTop,
- left: this.scrollLeft
- });
- }.bind(this));
+ if(above) {
+ if(this.settings.axis === "vertical") {
+ this.scrollTo(0, prevTop - bounds.height, true);
+ } else {
+ this.scrollTo(prevLeft - bounds.width, 0, true);
}
-
- } else {
- this.ignore = false;
}
- this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop);
- this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft);
+ };
- this.prevScrollTop = scrollTop;
- this.prevScrollLeft = scrollLeft;
+ addEventListeners(stage){
- clearTimeout(this.scrollTimeout);
- this.scrollTimeout = setTimeout(function(){
- this.scrollDeltaVert = 0;
- this.scrollDeltaHorz = 0;
- }.bind(this), 150);
+ window.addEventListener('unload', function(e){
+ this.ignore = true;
+ // this.scrollTo(0,0);
+ this.destroy();
+ }.bind(this));
+ this.addScrollListeners();
+ };
+
+ addScrollListeners() {
+ var scroller;
+
+ this.tick = requestAnimationFrame;
+
+ if(this.settings.height) {
+ this.prevScrollTop = this.container.scrollTop;
+ this.prevScrollLeft = this.container.scrollLeft;
+ } else {
+ this.prevScrollTop = window.scrollY;
+ this.prevScrollLeft = window.scrollX;
+ }
+
+ this.scrollDeltaVert = 0;
+ this.scrollDeltaHorz = 0;
+
+ if(this.settings.height) {
+ scroller = this.container;
+ this.scrollTop = this.container.scrollTop;
+ this.scrollLeft = this.container.scrollLeft;
+ } else {
+ scroller = window;
+ this.scrollTop = window.scrollY;
+ this.scrollLeft = window.scrollX;
+ }
+
+ scroller.addEventListener("scroll", this.onScroll.bind(this));
+
+ // this.tick.call(window, this.onScroll.bind(this));
this.scrolled = false;
- // }
- // this.tick.call(window, this.onScroll.bind(this));
+ };
-};
+ onScroll(){
+ let scrollTop;
+ let scrollLeft;
+ // if(!this.ignore) {
-// ContinuousViewManager.prototype.resizeView = function(view) {
-//
-// if(this.settings.axis === "horizontal") {
-// view.lock("height", this.stage.width, this.stage.height);
-// } else {
-// view.lock("width", this.stage.width, this.stage.height);
-// }
-//
-// };
+ if(this.settings.height) {
+ scrollTop = this.container.scrollTop;
+ scrollLeft = this.container.scrollLeft;
+ } else {
+ scrollTop = window.scrollY;
+ scrollLeft = window.scrollX;
+ }
-ContinuousViewManager.prototype.currentLocation = function(){
+ this.scrollTop = scrollTop;
+ this.scrollLeft = scrollLeft;
- if (this.settings.axis === "vertical") {
- this.location = this.scrolledLocation();
- } else {
- this.location = this.paginatedLocation();
- }
+ if(!this.ignore) {
- return this.location;
-};
+ if((this.scrollDeltaVert === 0 &&
+ this.scrollDeltaHorz === 0) ||
+ this.scrollDeltaVert > this.settings.offsetDelta ||
+ this.scrollDeltaHorz > this.settings.offsetDelta) {
-ContinuousViewManager.prototype.scrolledLocation = function(){
+ this.q.enqueue(function() {
+ this.check();
+ }.bind(this));
+ // this.check();
- var visible = this.visible();
- var startPage, endPage;
+ this.scrollDeltaVert = 0;
+ this.scrollDeltaHorz = 0;
- var container = this.container.getBoundingClientRect();
+ this.emit("scroll", {
+ top: scrollTop,
+ left: scrollLeft
+ });
- if(visible.length === 1) {
- return this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
- }
+ clearTimeout(this.afterScrolled);
+ this.afterScrolled = setTimeout(function () {
+ this.emit("scrolled", {
+ top: this.scrollTop,
+ left: this.scrollLeft
+ });
+ }.bind(this));
- if(visible.length > 1) {
-
- startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
- endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase);
-
- return {
- start: startPage.start,
- end: endPage.end
- };
- }
-
-};
-
-ContinuousViewManager.prototype.paginatedLocation = function(){
- var visible = this.visible();
- var startA, startB, endA, endB;
- var pageLeft, pageRight;
- var container = this.container.getBoundingClientRect();
-
- if(visible.length === 1) {
- startA = container.left - visible[0].position().left;
- endA = startA + this.layout.spreadWidth;
-
- return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);
- }
-
- if(visible.length > 1) {
-
- // Left Col
- startA = container.left - visible[0].position().left;
- endA = startA + this.layout.columnWidth;
-
- // Right Col
- startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left;
- endB = startB + this.layout.columnWidth;
-
- pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);
- pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB);
-
- return {
- start: pageLeft.start,
- end: pageRight.end
- };
- }
-};
-
-/*
-Continuous.prototype.current = function(what){
- var view, top;
- var container = this.container.getBoundingClientRect();
- var length = this.views.length - 1;
-
- if(this.settings.axis === "horizontal") {
-
- for (var i = length; i >= 0; i--) {
- view = this.views[i];
- left = view.position().left;
-
- if(left < container.right) {
-
- if(this._current == view) {
- break;
}
- this._current = view;
- break;
+ } else {
+ this.ignore = false;
}
- }
- } else {
+ this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop);
+ this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft);
- for (var i = length; i >= 0; i--) {
- view = this.views[i];
- top = view.bounds().top;
- if(top < container.bottom) {
+ this.prevScrollTop = scrollTop;
+ this.prevScrollLeft = scrollLeft;
- if(this._current == view) {
- break;
- }
+ clearTimeout(this.scrollTimeout);
+ this.scrollTimeout = setTimeout(function(){
+ this.scrollDeltaVert = 0;
+ this.scrollDeltaHorz = 0;
+ }.bind(this), 150);
- this._current = view;
- break;
- }
- }
+ this.scrolled = false;
+ // }
- }
+ // this.tick.call(window, this.onScroll.bind(this));
- return this._current;
-};
-*/
+ };
-ContinuousViewManager.prototype.updateLayout = function() {
- if (!this.stage) {
- return;
- }
+ // resizeView(view) {
+ //
+ // if(this.settings.axis === "horizontal") {
+ // view.lock("height", this.stage.width, this.stage.height);
+ // } else {
+ // view.lock("width", this.stage.width, this.stage.height);
+ // }
+ //
+ // };
- if(this.settings.axis === "vertical") {
- this.layout.calculate(this._stageSize.width, this._stageSize.height);
- } else {
- this.layout.calculate(
- this._stageSize.width,
- this._stageSize.height,
- this.settings.gap
- );
+ currentLocation(){
- // Set the look ahead offset for what is visible
- this.settings.offset = this.layout.delta;
-
- this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]);
-
- }
-
- // Set the dimensions for views
- this.viewSettings.width = this.layout.width;
- this.viewSettings.height = this.layout.height;
-
- this.setLayout(this.layout);
-
-};
-
-ContinuousViewManager.prototype.next = function(){
-
- if(this.settings.axis === "horizontal") {
-
- this.scrollLeft = this.container.scrollLeft;
-
- if(this.container.scrollLeft +
- this.container.offsetWidth +
- this.layout.delta < this.container.scrollWidth) {
- this.scrollBy(this.layout.delta, 0);
+ if (this.settings.axis === "vertical") {
+ this.location = this.scrolledLocation();
} else {
- this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
+ this.location = this.paginatedLocation();
}
- } else {
- this.scrollBy(0, this.layout.height);
- }
-};
+ return this.location;
+ };
-ContinuousViewManager.prototype.prev = function(){
- if(this.settings.axis === "horizontal") {
- this.scrollBy(-this.layout.delta, 0);
- } else {
- this.scrollBy(0, -this.layout.height);
- }
-};
+ scrolledLocation(){
-ContinuousViewManager.prototype.updateFlow = function(flow){
- var axis = (flow === "paginated") ? "horizontal" : "vertical";
+ var visible = this.visible();
+ var startPage, endPage;
- this.settings.axis = axis;
+ var container = this.container.getBoundingClientRect();
- this.viewSettings.axis = axis;
+ if(visible.length === 1) {
+ return this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
+ }
- this.settings.overflow = (flow === "paginated") ? "hidden" : "auto";
+ if(visible.length > 1) {
- // this.views.each(function(view){
- // view.setAxis(axis);
- // });
+ startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
+ endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase);
- if (this.settings.axis === "vertical") {
- this.settings.infinite = true;
- } else {
- this.settings.infinite = false;
- }
+ return {
+ start: startPage.start,
+ end: endPage.end
+ };
+ }
-};
-module.exports = ContinuousViewManager;
+ };
+
+ paginatedLocation(){
+ var visible = this.visible();
+ var startA, startB, endA, endB;
+ var pageLeft, pageRight;
+ var container = this.container.getBoundingClientRect();
+
+ if(visible.length === 1) {
+ startA = container.left - visible[0].position().left;
+ endA = startA + this.layout.spreadWidth;
+
+ return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);
+ }
+
+ if(visible.length > 1) {
+
+ // Left Col
+ startA = container.left - visible[0].position().left;
+ endA = startA + this.layout.columnWidth;
+
+ // Right Col
+ startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left;
+ endB = startB + this.layout.columnWidth;
+
+ pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);
+ pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB);
+
+ return {
+ start: pageLeft.start,
+ end: pageRight.end
+ };
+ }
+ };
+
+ /*
+ current(what){
+ var view, top;
+ var container = this.container.getBoundingClientRect();
+ var length = this.views.length - 1;
+
+ if(this.settings.axis === "horizontal") {
+
+ for (var i = length; i >= 0; i--) {
+ view = this.views[i];
+ left = view.position().left;
+
+ if(left < container.right) {
+
+ if(this._current == view) {
+ break;
+ }
+
+ this._current = view;
+ break;
+ }
+ }
+
+ } else {
+
+ for (var i = length; i >= 0; i--) {
+ view = this.views[i];
+ top = view.bounds().top;
+ if(top < container.bottom) {
+
+ if(this._current == view) {
+ break;
+ }
+
+ this._current = view;
+
+ break;
+ }
+ }
+
+ }
+
+ return this._current;
+ };
+ */
+
+ updateLayout() {
+
+ if (!this.stage) {
+ return;
+ }
+
+ if(this.settings.axis === "vertical") {
+ this.layout.calculate(this._stageSize.width, this._stageSize.height);
+ } else {
+ this.layout.calculate(
+ this._stageSize.width,
+ this._stageSize.height,
+ this.settings.gap
+ );
+
+ // Set the look ahead offset for what is visible
+ this.settings.offset = this.layout.delta;
+
+ this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]);
+
+ }
+
+ // Set the dimensions for views
+ this.viewSettings.width = this.layout.width;
+ this.viewSettings.height = this.layout.height;
+
+ this.setLayout(this.layout);
+
+ };
+
+ next(){
+
+ if(this.settings.axis === "horizontal") {
+
+ this.scrollLeft = this.container.scrollLeft;
+
+ if(this.container.scrollLeft +
+ this.container.offsetWidth +
+ this.layout.delta < this.container.scrollWidth) {
+ this.scrollBy(this.layout.delta, 0);
+ } else {
+ this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
+ }
+
+ } else {
+ this.scrollBy(0, this.layout.height);
+ }
+ };
+
+ prev(){
+ if(this.settings.axis === "horizontal") {
+ this.scrollBy(-this.layout.delta, 0);
+ } else {
+ this.scrollBy(0, -this.layout.height);
+ }
+ };
+
+ updateFlow(flow){
+ var axis = (flow === "paginated") ? "horizontal" : "vertical";
+
+ this.settings.axis = axis;
+
+ this.viewSettings.axis = axis;
+
+ this.settings.overflow = (flow === "paginated") ? "hidden" : "auto";
+
+ // this.views.each(function(view){
+ // view.setAxis(axis);
+ // });
+
+ if (this.settings.axis === "vertical") {
+ this.settings.infinite = true;
+ } else {
+ this.settings.infinite = false;
+ }
+
+ };
+}
+
+export default ContinuousViewManager;
diff --git a/src/managers/default/index.js b/src/managers/default/index.js
index 678bae0..6da8504 100644
--- a/src/managers/default/index.js
+++ b/src/managers/default/index.js
@@ -1,573 +1,575 @@
-var EventEmitter = require('event-emitter');
-var core = require('../../core');
-var EpubCFI = require('../../epubcfi');
-var Mapping = require('../../mapping');
-var Queue = require('../../queue');
-var Stage = require('../helpers/stage');
-var Views = require('../helpers/views');
-
-function DefaultViewManager(options) {
-
- this.name = "default";
- this.View = options.view;
- this.request = options.request;
- this.renditionQueue = options.queue;
- this.q = new Queue(this);
-
- this.settings = core.extend(this.settings || {}, {
- infinite: true,
- hidden: false,
- width: undefined,
- height: undefined,
- // globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'},
- // layout: null,
- axis: "vertical",
- ignoreClass: ''
- });
-
- core.extend(this.settings, options.settings || {});
-
- this.viewSettings = {
- ignoreClass: this.settings.ignoreClass,
- axis: this.settings.axis,
- layout: this.layout,
- width: 0,
- height: 0
- };
-
-}
-
-DefaultViewManager.prototype.render = function(element, size){
-
- // Save the stage
- this.stage = new Stage({
- width: size.width,
- height: size.height,
- overflow: this.settings.overflow,
- hidden: this.settings.hidden,
- axis: this.settings.axis
- });
-
- this.stage.attachTo(element);
-
- // Get this stage container div
- this.container = this.stage.getContainer();
-
- // Views array methods
- this.views = new Views(this.container);
-
- // Calculate Stage Size
- this._bounds = this.bounds();
- this._stageSize = this.stage.size();
-
- // Set the dimensions for views
- this.viewSettings.width = this._stageSize.width;
- this.viewSettings.height = this._stageSize.height;
-
- // Function to handle a resize event.
- // Will only attach if width and height are both fixed.
- this.stage.onResize(this.onResized.bind(this));
-
- // Add Event Listeners
- this.addEventListeners();
-
- // Add Layout method
- // this.applyLayoutMethod();
- if (this.layout) {
- this.updateLayout();
- }
-};
-
-DefaultViewManager.prototype.addEventListeners = function(){
- window.addEventListener('unload', function(e){
- this.destroy();
- }.bind(this));
-};
-
-DefaultViewManager.prototype.destroy = function(){
- // this.views.each(function(view){
- // view.destroy();
- // });
-
- /*
-
- clearTimeout(this.trimTimeout);
- if(this.settings.hidden) {
- this.element.removeChild(this.wrapper);
- } else {
- this.element.removeChild(this.container);
- }
- */
-};
-
-DefaultViewManager.prototype.onResized = function(e) {
- clearTimeout(this.resizeTimeout);
- this.resizeTimeout = setTimeout(function(){
- this.resize();
- }.bind(this), 150);
-};
-
-DefaultViewManager.prototype.resize = function(width, height){
-
- // Clear the queue
- this.q.clear();
-
- this._stageSize = this.stage.size(width, height);
- this._bounds = this.bounds();
-
- // Update for new views
- this.viewSettings.width = this._stageSize.width;
- this.viewSettings.height = this._stageSize.height;
-
- // Update for existing views
- this.views.each(function(view) {
- view.size(this._stageSize.width, this._stageSize.height);
- }.bind(this));
-
- this.updateLayout();
-
- this.emit("resized", {
- width: this.stage.width,
- height: this.stage.height
- });
-
-};
-
-DefaultViewManager.prototype.createView = function(section) {
- return new this.View(section, this.viewSettings);
-};
-
-DefaultViewManager.prototype.display = function(section, target){
-
- var displaying = new core.defer();
- var displayed = displaying.promise;
-
- // Check to make sure the section we want isn't already shown
- var visible = this.views.find(section);
-
- // View is already shown, just move to correct location
- if(visible && target) {
- offset = visible.locationOf(target);
- this.moveTo(offset);
- displaying.resolve();
- return displayed;
- }
-
- // Hide all current views
- this.views.hide();
-
- this.views.clear();
-
- this.add(section)
- .then(function(view){
-
- // Move to correct place within the section, if needed
- if(target) {
- offset = view.locationOf(target);
- this.moveTo(offset);
- }
-
- }.bind(this))
- .then(function(){
- var next;
- if (this.layout.name === "pre-paginated" &&
- this.layout.divisor > 1) {
- next = section.next();
- if (next) {
- return this.add(next);
- }
- }
- }.bind(this))
- .then(function(){
-
- this.views.show();
-
- displaying.resolve();
-
- }.bind(this))
- // .then(function(){
- // return this.hooks.display.trigger(view);
- // }.bind(this))
- // .then(function(){
- // this.views.show();
- // }.bind(this));
- return displayed;
-};
-
-DefaultViewManager.prototype.afterDisplayed = function(view){
- this.emit("added", view);
-};
-
-DefaultViewManager.prototype.afterResized = function(view){
- this.emit("resize", view.section);
-};
-
-// DefaultViewManager.prototype.moveTo = function(offset){
-// this.scrollTo(offset.left, offset.top);
-// };
-
-DefaultViewManager.prototype.moveTo = function(offset){
- var distX = 0,
- distY = 0;
-
- if(this.settings.axis === "vertical") {
- distY = offset.top;
- } else {
- distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;
-
- if (distX + this.layout.delta > this.container.scrollWidth) {
- distX = this.container.scrollWidth - this.layout.delta;
- }
- }
-
- this.scrollTo(distX, distY);
-};
-
-DefaultViewManager.prototype.add = function(section){
- var view = this.createView(section);
-
- this.views.append(view);
-
- // view.on("shown", this.afterDisplayed.bind(this));
- view.onDisplayed = this.afterDisplayed.bind(this);
- view.onResize = this.afterResized.bind(this);
-
- return view.display(this.request);
-
-};
-
-DefaultViewManager.prototype.append = function(section){
- var view = this.createView(section);
- this.views.append(view);
- return view.display(this.request);
-};
-
-DefaultViewManager.prototype.prepend = function(section){
- var view = this.createView(section);
-
- this.views.prepend(view);
- return view.display(this.request);
-};
-// DefaultViewManager.prototype.resizeView = function(view) {
-//
-// if(this.settings.globalLayoutProperties.layout === "pre-paginated") {
-// view.lock("both", this.bounds.width, this.bounds.height);
-// } else {
-// view.lock("width", this.bounds.width, this.bounds.height);
-// }
-//
-// };
-
-DefaultViewManager.prototype.next = function(){
- var next;
- var view;
- var left;
-
- if(!this.views.length) return;
-
- if(this.settings.axis === "horizontal") {
-
- this.scrollLeft = this.container.scrollLeft;
-
- left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;
-
- if(left < this.container.scrollWidth) {
- this.scrollBy(this.layout.delta, 0);
- } else if (left - this.layout.columnWidth === this.container.scrollWidth) {
- this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
- } else {
- next = this.views.last().section.next();
- }
-
-
- } else {
-
- next = this.views.last().section.next();
-
- }
-
- if(next) {
- this.views.clear();
-
- return this.append(next)
- .then(function(){
- var right;
- if (this.layout.name && this.layout.divisor > 1) {
- right = next.next();
- if (right) {
- return this.append(right);
- }
- }
- }.bind(this))
- .then(function(){
- this.views.show();
- }.bind(this));
- }
-
-
-};
-
-DefaultViewManager.prototype.prev = function(){
- var prev;
- var view;
- var left;
-
- if(!this.views.length) return;
-
- if(this.settings.axis === "horizontal") {
-
- this.scrollLeft = this.container.scrollLeft;
-
- left = this.container.scrollLeft;
-
- if(left > 0) {
- this.scrollBy(-this.layout.delta, 0);
- } else {
- prev = this.views.first().section.prev();
- }
-
-
- } else {
-
- prev = this.views.first().section.prev();
-
- }
-
- if(prev) {
- this.views.clear();
-
- return this.prepend(prev)
- .then(function(){
- var left;
- if (this.layout.name && this.layout.divisor > 1) {
- left = prev.prev();
- if (left) {
- return this.prepend(left);
- }
- }
- }.bind(this))
- .then(function(){
- if(this.settings.axis === "horizontal") {
- this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
- }
- this.views.show();
- }.bind(this));
- }
-};
-
-DefaultViewManager.prototype.current = function(){
- var visible = this.visible();
- if(visible.length){
- // Current is the last visible view
- return visible[visible.length-1];
- }
- return null;
-};
-
-DefaultViewManager.prototype.currentLocation = function(){
-
- if (this.settings.axis === "vertical") {
- this.location = this.scrolledLocation();
- } else {
- this.location = this.paginatedLocation();
- }
- return this.location;
-};
-
-DefaultViewManager.prototype.scrolledLocation = function(){
- var view;
-
- if(this.views.length) {
- view = this.views.first();
- return this.mapping.page(view, view.section.cfiBase);
- }
-
-};
-
-DefaultViewManager.prototype.paginatedLocation = function(){
- var view;
- var start, end;
-
- if(this.views.length) {
- view = this.views.first();
- start = this._bounds.left - view.position().left;
- end = start + this.layout.spreadWidth;
- return this.mapping.page(view, view.section.cfiBase, start, end);
- }
-
-};
-
-DefaultViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _container){
- var position = view.position();
- var container = _container || this.bounds();
-
- if(this.settings.axis === "horizontal" &&
- position.right > container.left - offsetPrev &&
- position.left < container.right + offsetNext) {
-
- return true;
-
- } else if(this.settings.axis === "vertical" &&
- position.bottom > container.top - offsetPrev &&
- position.top < container.bottom + offsetNext) {
-
- return true;
- }
-
- return false;
-
-};
-
-DefaultViewManager.prototype.visible = function(){
- // return this.views.displayed();
- var container = this.bounds();
- var views = this.views.displayed();
- var viewsLength = views.length;
- var visible = [];
- var isVisible;
- var view;
-
- for (var i = 0; i < viewsLength; i++) {
- view = views[i];
- isVisible = this.isVisible(view, 0, 0, container);
-
- if(isVisible === true) {
- visible.push(view);
- }
-
- }
- return visible;
-};
-
-DefaultViewManager.prototype.scrollBy = function(x, y, silent){
- if(silent) {
- this.ignore = true;
- }
-
- if(this.settings.height) {
-
- if(x) this.container.scrollLeft += x;
- if(y) this.container.scrollTop += y;
-
- } else {
- window.scrollBy(x,y);
- }
- // console.log("scrollBy", x, y);
- this.scrolled = true;
- this.onScroll();
-};
-
-DefaultViewManager.prototype.scrollTo = function(x, y, silent){
- if(silent) {
- this.ignore = true;
- }
-
- if(this.settings.height) {
- this.container.scrollLeft = x;
- this.container.scrollTop = y;
- } else {
- window.scrollTo(x,y);
- }
- // console.log("scrollTo", x, y);
- this.scrolled = true;
- this.onScroll();
- // if(this.container.scrollLeft != x){
- // setTimeout(function() {
- // this.scrollTo(x, y, silent);
- // }.bind(this), 10);
- // return;
- // };
- };
-
-DefaultViewManager.prototype.onScroll = function(){
-
-};
-
-DefaultViewManager.prototype.bounds = function() {
- var bounds;
-
- bounds = this.stage.bounds();
-
- return bounds;
-};
-
-DefaultViewManager.prototype.applyLayout = function(layout) {
-
- this.layout = layout;
- this.updateLayout();
-
- this.mapping = new Mapping(this.layout);
- // this.manager.layout(this.layout.format);
-};
-
-DefaultViewManager.prototype.updateLayout = function() {
- if (!this.stage) {
- return;
- }
-
- this._stageSize = this.stage.size();
-
- if(this.settings.axis === "vertical") {
- this.layout.calculate(this._stageSize.width, this._stageSize.height);
- } else {
- this.layout.calculate(
- this._stageSize.width,
- this._stageSize.height,
- this.settings.gap
- );
-
- // Set the look ahead offset for what is visible
- this.settings.offset = this.layout.delta;
-
- this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]);
-
- }
-
- // Set the dimensions for views
- this.viewSettings.width = this.layout.width;
- this.viewSettings.height = this.layout.height;
-
- this.setLayout(this.layout);
-
-};
-
-DefaultViewManager.prototype.setLayout = function(layout){
-
- this.viewSettings.layout = layout;
-
- if(this.views) {
-
- this.views.each(function(view){
- view.setLayout(layout);
+import EventEmitter from 'event-emitter';
+import {extend, defer} from '../../utils/core';
+import EpubCFI from '../../epubcfi';
+import Mapping from '../../mapping';
+import Queue from '../../queue';
+import Stage from '../helpers/stage';
+import Views from '../helpers/views';
+
+class DefaultViewManager {
+ constructor(options) {
+
+ this.name = "default";
+ this.View = options.view;
+ this.request = options.request;
+ this.renditionQueue = options.queue;
+ this.q = new Queue(this);
+
+ this.settings = extend(this.settings || {}, {
+ infinite: true,
+ hidden: false,
+ width: undefined,
+ height: undefined,
+ // globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'},
+ // layout: null,
+ axis: "vertical",
+ ignoreClass: ''
});
+ extend(this.settings, options.settings || {});
+
+ this.viewSettings = {
+ ignoreClass: this.settings.ignoreClass,
+ axis: this.settings.axis,
+ layout: this.layout,
+ width: 0,
+ height: 0
+ };
+
}
-};
+ render(element, size){
-DefaultViewManager.prototype.updateFlow = function(flow){
- var axis = (flow === "paginated") ? "horizontal" : "vertical";
+ // Save the stage
+ this.stage = new Stage({
+ width: size.width,
+ height: size.height,
+ overflow: this.settings.overflow,
+ hidden: this.settings.hidden,
+ axis: this.settings.axis
+ });
- this.settings.axis = axis;
+ this.stage.attachTo(element);
- this.viewSettings.axis = axis;
+ // Get this stage container div
+ this.container = this.stage.getContainer();
- this.settings.overflow = (flow === "paginated") ? "hidden" : "auto";
- // this.views.each(function(view){
- // view.setAxis(axis);
- // });
+ // Views array methods
+ this.views = new Views(this.container);
-};
+ // Calculate Stage Size
+ this._bounds = this.bounds();
+ this._stageSize = this.stage.size();
-DefaultViewManager.prototype.getContents = function(){
- var contents = [];
- this.views.each(function(view){
- contents.push(view.contents);
- });
- return contents;
-};
+ // Set the dimensions for views
+ this.viewSettings.width = this._stageSize.width;
+ this.viewSettings.height = this._stageSize.height;
+
+ // Function to handle a resize event.
+ // Will only attach if width and height are both fixed.
+ this.stage.onResize(this.onResized.bind(this));
+
+ // Add Event Listeners
+ this.addEventListeners();
+
+ // Add Layout method
+ // this.applyLayoutMethod();
+ if (this.layout) {
+ this.updateLayout();
+ }
+ };
+
+ addEventListeners(){
+ window.addEventListener('unload', function(e){
+ this.destroy();
+ }.bind(this));
+ };
+
+ destroy(){
+ // this.views.each(function(view){
+ // view.destroy();
+ // });
+
+ /*
+
+ clearTimeout(this.trimTimeout);
+ if(this.settings.hidden) {
+ this.element.removeChild(this.wrapper);
+ } else {
+ this.element.removeChild(this.container);
+ }
+ */
+ };
+
+ onResized(e) {
+ clearTimeout(this.resizeTimeout);
+ this.resizeTimeout = setTimeout(function(){
+ this.resize();
+ }.bind(this), 150);
+ };
+
+ resize(width, height){
+
+ // Clear the queue
+ this.q.clear();
+
+ this._stageSize = this.stage.size(width, height);
+ this._bounds = this.bounds();
+
+ // Update for new views
+ this.viewSettings.width = this._stageSize.width;
+ this.viewSettings.height = this._stageSize.height;
+
+ // Update for existing views
+ this.views.each(function(view) {
+ view.size(this._stageSize.width, this._stageSize.height);
+ }.bind(this));
+
+ this.updateLayout();
+
+ this.emit("resized", {
+ width: this.stage.width,
+ height: this.stage.height
+ });
+
+ };
+
+ createView(section) {
+ return new this.View(section, this.viewSettings);
+ };
+
+ display(section, target){
+
+ var displaying = new defer();
+ var displayed = displaying.promise;
+
+ // Check to make sure the section we want isn't already shown
+ var visible = this.views.find(section);
+
+ // View is already shown, just move to correct location
+ if(visible && target) {
+ offset = visible.locationOf(target);
+ this.moveTo(offset);
+ displaying.resolve();
+ return displayed;
+ }
+
+ // Hide all current views
+ this.views.hide();
+
+ this.views.clear();
+
+ this.add(section)
+ .then(function(view){
+
+ // Move to correct place within the section, if needed
+ if(target) {
+ offset = view.locationOf(target);
+ this.moveTo(offset);
+ }
+
+ }.bind(this))
+ .then(function(){
+ var next;
+ if (this.layout.name === "pre-paginated" &&
+ this.layout.divisor > 1) {
+ next = section.next();
+ if (next) {
+ return this.add(next);
+ }
+ }
+ }.bind(this))
+ .then(function(){
+
+ this.views.show();
+
+ displaying.resolve();
+
+ }.bind(this))
+ // .then(function(){
+ // return this.hooks.display.trigger(view);
+ // }.bind(this))
+ // .then(function(){
+ // this.views.show();
+ // }.bind(this));
+ return displayed;
+ };
+
+ afterDisplayed(view){
+ this.emit("added", view);
+ };
+
+ afterResized(view){
+ this.emit("resize", view.section);
+ };
+
+ // moveTo(offset){
+ // this.scrollTo(offset.left, offset.top);
+ // };
+
+ moveTo(offset){
+ var distX = 0,
+ distY = 0;
+
+ if(this.settings.axis === "vertical") {
+ distY = offset.top;
+ } else {
+ distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;
+
+ if (distX + this.layout.delta > this.container.scrollWidth) {
+ distX = this.container.scrollWidth - this.layout.delta;
+ }
+ }
+
+ this.scrollTo(distX, distY);
+ };
+
+ add(section){
+ var view = this.createView(section);
+
+ this.views.append(view);
+
+ // view.on("shown", this.afterDisplayed.bind(this));
+ view.onDisplayed = this.afterDisplayed.bind(this);
+ view.onResize = this.afterResized.bind(this);
+
+ return view.display(this.request);
+
+ };
+
+ append(section){
+ var view = this.createView(section);
+ this.views.append(view);
+ return view.display(this.request);
+ };
+
+ prepend(section){
+ var view = this.createView(section);
+
+ this.views.prepend(view);
+ return view.display(this.request);
+ };
+ // resizeView(view) {
+ //
+ // if(this.settings.globalLayoutProperties.layout === "pre-paginated") {
+ // view.lock("both", this.bounds.width, this.bounds.height);
+ // } else {
+ // view.lock("width", this.bounds.width, this.bounds.height);
+ // }
+ //
+ // };
+
+ next(){
+ var next;
+ var view;
+ var left;
+
+ if(!this.views.length) return;
+
+ if(this.settings.axis === "horizontal") {
+
+ this.scrollLeft = this.container.scrollLeft;
+
+ left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;
+
+ if(left < this.container.scrollWidth) {
+ this.scrollBy(this.layout.delta, 0);
+ } else if (left - this.layout.columnWidth === this.container.scrollWidth) {
+ this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
+ } else {
+ next = this.views.last().section.next();
+ }
+
+
+ } else {
+
+ next = this.views.last().section.next();
+
+ }
+
+ if(next) {
+ this.views.clear();
+
+ return this.append(next)
+ .then(function(){
+ var right;
+ if (this.layout.name && this.layout.divisor > 1) {
+ right = next.next();
+ if (right) {
+ return this.append(right);
+ }
+ }
+ }.bind(this))
+ .then(function(){
+ this.views.show();
+ }.bind(this));
+ }
+
+
+ };
+
+ prev(){
+ var prev;
+ var view;
+ var left;
+
+ if(!this.views.length) return;
+
+ if(this.settings.axis === "horizontal") {
+
+ this.scrollLeft = this.container.scrollLeft;
+
+ left = this.container.scrollLeft;
+
+ if(left > 0) {
+ this.scrollBy(-this.layout.delta, 0);
+ } else {
+ prev = this.views.first().section.prev();
+ }
+
+
+ } else {
+
+ prev = this.views.first().section.prev();
+
+ }
+
+ if(prev) {
+ this.views.clear();
+
+ return this.prepend(prev)
+ .then(function(){
+ var left;
+ if (this.layout.name && this.layout.divisor > 1) {
+ left = prev.prev();
+ if (left) {
+ return this.prepend(left);
+ }
+ }
+ }.bind(this))
+ .then(function(){
+ if(this.settings.axis === "horizontal") {
+ this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
+ }
+ this.views.show();
+ }.bind(this));
+ }
+ };
+
+ current(){
+ var visible = this.visible();
+ if(visible.length){
+ // Current is the last visible view
+ return visible[visible.length-1];
+ }
+ return null;
+ };
+
+ currentLocation(){
+
+ if (this.settings.axis === "vertical") {
+ this.location = this.scrolledLocation();
+ } else {
+ this.location = this.paginatedLocation();
+ }
+ return this.location;
+ };
+
+ scrolledLocation(){
+ var view;
+
+ if(this.views.length) {
+ view = this.views.first();
+ return this.mapping.page(view, view.section.cfiBase);
+ }
+
+ };
+
+ paginatedLocation(){
+ var view;
+ var start, end;
+
+ if(this.views.length) {
+ view = this.views.first();
+ start = this._bounds.left - view.position().left;
+ end = start + this.layout.spreadWidth;
+ return this.mapping.page(view, view.section.cfiBase, start, end);
+ }
+
+ };
+
+ isVisible(view, offsetPrev, offsetNext, _container){
+ var position = view.position();
+ var container = _container || this.bounds();
+
+ if(this.settings.axis === "horizontal" &&
+ position.right > container.left - offsetPrev &&
+ position.left < container.right + offsetNext) {
+
+ return true;
+
+ } else if(this.settings.axis === "vertical" &&
+ position.bottom > container.top - offsetPrev &&
+ position.top < container.bottom + offsetNext) {
+
+ return true;
+ }
+
+ return false;
+
+ };
+
+ visible(){
+ // return this.views.displayed();
+ var container = this.bounds();
+ var views = this.views.displayed();
+ var viewsLength = views.length;
+ var visible = [];
+ var isVisible;
+ var view;
+
+ for (var i = 0; i < viewsLength; i++) {
+ view = views[i];
+ isVisible = this.isVisible(view, 0, 0, container);
+
+ if(isVisible === true) {
+ visible.push(view);
+ }
+
+ }
+ return visible;
+ };
+
+ scrollBy(x, y, silent){
+ if(silent) {
+ this.ignore = true;
+ }
+
+ if(this.settings.height) {
+
+ if(x) this.container.scrollLeft += x;
+ if(y) this.container.scrollTop += y;
+
+ } else {
+ window.scrollBy(x,y);
+ }
+ // console.log("scrollBy", x, y);
+ this.scrolled = true;
+ this.onScroll();
+ };
+
+ scrollTo(x, y, silent){
+ if(silent) {
+ this.ignore = true;
+ }
+
+ if(this.settings.height) {
+ this.container.scrollLeft = x;
+ this.container.scrollTop = y;
+ } else {
+ window.scrollTo(x,y);
+ }
+ // console.log("scrollTo", x, y);
+ this.scrolled = true;
+ this.onScroll();
+ // if(this.container.scrollLeft != x){
+ // setTimeout(function() {
+ // this.scrollTo(x, y, silent);
+ // }.bind(this), 10);
+ // return;
+ // };
+ };
+
+ onScroll(){
+
+ };
+
+ bounds() {
+ var bounds;
+
+ bounds = this.stage.bounds();
+
+ return bounds;
+ };
+
+ applyLayout(layout) {
+
+ this.layout = layout;
+ this.updateLayout();
+
+ this.mapping = new Mapping(this.layout);
+ // this.manager.layout(this.layout.format);
+ };
+
+ updateLayout() {
+ if (!this.stage) {
+ return;
+ }
+
+ this._stageSize = this.stage.size();
+
+ if(this.settings.axis === "vertical") {
+ this.layout.calculate(this._stageSize.width, this._stageSize.height);
+ } else {
+ this.layout.calculate(
+ this._stageSize.width,
+ this._stageSize.height,
+ this.settings.gap
+ );
+
+ // Set the look ahead offset for what is visible
+ this.settings.offset = this.layout.delta;
+
+ this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]);
+
+ }
+
+ // Set the dimensions for views
+ this.viewSettings.width = this.layout.width;
+ this.viewSettings.height = this.layout.height;
+
+ this.setLayout(this.layout);
+
+ };
+
+ setLayout(layout){
+
+ this.viewSettings.layout = layout;
+
+ if(this.views) {
+
+ this.views.each(function(view){
+ view.setLayout(layout);
+ });
+
+ }
+
+ };
+
+ updateFlow(flow){
+ var axis = (flow === "paginated") ? "horizontal" : "vertical";
+
+ this.settings.axis = axis;
+
+ this.viewSettings.axis = axis;
+
+ this.settings.overflow = (flow === "paginated") ? "hidden" : "auto";
+ // this.views.each(function(view){
+ // view.setAxis(axis);
+ // });
+
+ };
+
+ getContents(){
+ var contents = [];
+ this.views.each(function(view){
+ contents.push(view.contents);
+ });
+ return contents;
+ };
+}
//-- Enable binding events to Manager
EventEmitter(DefaultViewManager.prototype);
- module.exports = DefaultViewManager;
+export default DefaultViewManager;
diff --git a/src/managers/helpers/stage.js b/src/managers/helpers/stage.js
index 8f4c08c..9f0b5e4 100644
--- a/src/managers/helpers/stage.js
+++ b/src/managers/helpers/stage.js
@@ -1,231 +1,231 @@
-var core = require('../../core');
+import {uuid, isNumber, isElement, windowBounds} from '../../utils/core';
-function Stage(_options) {
- this.settings = _options || {};
- this.id = "epubjs-container-" + core.uuid();
+class Stage {
+ constructor(_options) {
+ this.settings = _options || {};
+ this.id = "epubjs-container-" + uuid();
- this.container = this.create(this.settings);
+ this.container = this.create(this.settings);
- if(this.settings.hidden) {
- this.wrapper = this.wrap(this.container);
- }
-
-}
-
-/*
-* Creates an element to render to.
-* Resizes to passed width and height or to the elements size
-*/
-Stage.prototype.create = function(options){
- var height = options.height;// !== false ? options.height : "100%";
- var width = options.width;// !== false ? options.width : "100%";
- var overflow = options.overflow || false;
- var axis = options.axis || "vertical";
-
- if(options.height && core.isNumber(options.height)) {
- height = options.height + "px";
- }
-
- if(options.width && core.isNumber(options.width)) {
- width = options.width + "px";
- }
-
- // Create new container element
- container = document.createElement("div");
-
- container.id = this.id;
- container.classList.add("epub-container");
-
- // Style Element
- // container.style.fontSize = "0";
- container.style.wordSpacing = "0";
- container.style.lineHeight = "0";
- container.style.verticalAlign = "top";
-
- if(axis === "horizontal") {
- container.style.whiteSpace = "nowrap";
- }
-
- if(width){
- container.style.width = width;
- }
-
- if(height){
- container.style.height = height;
- }
-
- if (overflow) {
- container.style.overflow = overflow;
- }
-
- return container;
-};
-
-Stage.wrap = function(container) {
- var wrapper = document.createElement("div");
-
- wrapper.style.visibility = "hidden";
- wrapper.style.overflow = "hidden";
- wrapper.style.width = "0";
- wrapper.style.height = "0";
-
- wrapper.appendChild(container);
- return wrapper;
-};
-
-
-Stage.prototype.getElement = function(_element){
- var element;
-
- if(core.isElement(_element)) {
- element = _element;
- } else if (typeof _element === "string") {
- element = document.getElementById(_element);
- }
-
- if(!element){
- console.error("Not an Element");
- return;
- }
-
- return element;
-};
-
-Stage.prototype.attachTo = function(what){
-
- var element = this.getElement(what);
- var base;
-
- if(!element){
- return;
- }
-
- if(this.settings.hidden) {
- base = this.wrapper;
- } else {
- base = this.container;
- }
-
- element.appendChild(base);
-
- this.element = element;
-
- return element;
-
-};
-
-Stage.prototype.getContainer = function() {
- return this.container;
-};
-
-Stage.prototype.onResize = function(func){
- // 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.
- if(!core.isNumber(this.settings.width) ||
- !core.isNumber(this.settings.height) ) {
- window.addEventListener("resize", func, false);
- }
-
-};
-
-Stage.prototype.size = function(width, height){
- var bounds;
- // var width = _width || this.settings.width;
- // var height = _height || this.settings.height;
-
- // If width or height are set to false, inherit them from containing element
- if(width === null) {
- bounds = this.element.getBoundingClientRect();
-
- if(bounds.width) {
- width = bounds.width;
- this.container.style.width = bounds.width + "px";
- }
- }
-
- if(height === null) {
- bounds = bounds || this.element.getBoundingClientRect();
-
- if(bounds.height) {
- height = bounds.height;
- this.container.style.height = bounds.height + "px";
+ if(this.settings.hidden) {
+ this.wrapper = this.wrap(this.container);
}
}
- if(!core.isNumber(width)) {
- bounds = this.container.getBoundingClientRect();
- width = bounds.width;
- //height = bounds.height;
- }
+ /*
+ * Creates an element to render to.
+ * Resizes to passed width and height or to the elements size
+ */
+ create(options){
+ var height = options.height;// !== false ? options.height : "100%";
+ var width = options.width;// !== false ? options.width : "100%";
+ var overflow = options.overflow || false;
+ var axis = options.axis || "vertical";
- if(!core.isNumber(height)) {
- bounds = bounds || this.container.getBoundingClientRect();
- //width = bounds.width;
- height = bounds.height;
- }
+ if(options.height && isNumber(options.height)) {
+ height = options.height + "px";
+ }
+ if(options.width && isNumber(options.width)) {
+ width = options.width + "px";
+ }
- this.containerStyles = window.getComputedStyle(this.container);
+ // Create new container element
+ let container = document.createElement("div");
- this.containerPadding = {
- left: parseFloat(this.containerStyles["padding-left"]) || 0,
- right: parseFloat(this.containerStyles["padding-right"]) || 0,
- top: parseFloat(this.containerStyles["padding-top"]) || 0,
- bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0
+ container.id = this.id;
+ container.classList.add("epub-container");
+
+ // Style Element
+ // container.style.fontSize = "0";
+ container.style.wordSpacing = "0";
+ container.style.lineHeight = "0";
+ container.style.verticalAlign = "top";
+
+ if(axis === "horizontal") {
+ container.style.whiteSpace = "nowrap";
+ }
+
+ if(width){
+ container.style.width = width;
+ }
+
+ if(height){
+ container.style.height = height;
+ }
+
+ if (overflow) {
+ container.style.overflow = overflow;
+ }
+
+ return container;
};
- return {
- width: width -
- this.containerPadding.left -
- this.containerPadding.right,
- height: height -
- this.containerPadding.top -
- this.containerPadding.bottom
+ wrap(container) {
+ var wrapper = document.createElement("div");
+
+ wrapper.style.visibility = "hidden";
+ wrapper.style.overflow = "hidden";
+ wrapper.style.width = "0";
+ wrapper.style.height = "0";
+
+ wrapper.appendChild(container);
+ return wrapper;
};
-};
-Stage.prototype.bounds = function(){
+ getElement(_element){
+ var element;
- if(!this.container) {
- return core.windowBounds();
- } else {
- return this.container.getBoundingClientRect();
- }
+ if(isElement(_element)) {
+ element = _element;
+ } else if (typeof _element === "string") {
+ element = document.getElementById(_element);
+ }
-}
+ if(!element){
+ console.error("Not an Element");
+ return;
+ }
-Stage.prototype.getSheet = function(){
- var style = document.createElement("style");
+ return element;
+ };
- // WebKit hack --> https://davidwalsh.name/add-rules-stylesheets
- style.appendChild(document.createTextNode(""));
+ attachTo(what){
- document.head.appendChild(style);
+ var element = this.getElement(what);
+ var base;
- return style.sheet;
-}
+ if(!element){
+ return;
+ }
-Stage.prototype.addStyleRules = function(selector, rulesArray){
- var scope = "#" + this.id + " ";
- var rules = "";
+ if(this.settings.hidden) {
+ base = this.wrapper;
+ } else {
+ base = this.container;
+ }
- if(!this.sheet){
- this.sheet = this.getSheet();
- }
+ element.appendChild(base);
- rulesArray.forEach(function(set) {
- for (var prop in set) {
- if(set.hasOwnProperty(prop)) {
- rules += prop + ":" + set[prop] + ";";
+ this.element = element;
+
+ return element;
+
+ };
+
+ getContainer() {
+ return this.container;
+ };
+
+ onResize(func){
+ // 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.
+ if(!isNumber(this.settings.width) ||
+ !isNumber(this.settings.height) ) {
+ window.addEventListener("resize", func, false);
+ }
+
+ };
+
+ size(width, height){
+ var bounds;
+ // var width = _width || this.settings.width;
+ // var height = _height || this.settings.height;
+
+ // If width or height are set to false, inherit them from containing element
+ if(width === null) {
+ bounds = this.element.getBoundingClientRect();
+
+ if(bounds.width) {
+ width = bounds.width;
+ this.container.style.width = bounds.width + "px";
}
}
- })
- this.sheet.insertRule(scope + selector + " {" + rules + "}", 0);
+ if(height === null) {
+ bounds = bounds || this.element.getBoundingClientRect();
+
+ if(bounds.height) {
+ height = bounds.height;
+ this.container.style.height = bounds.height + "px";
+ }
+
+ }
+
+ if(!isNumber(width)) {
+ bounds = this.container.getBoundingClientRect();
+ width = bounds.width;
+ //height = bounds.height;
+ }
+
+ if(!isNumber(height)) {
+ bounds = bounds || this.container.getBoundingClientRect();
+ //width = bounds.width;
+ height = bounds.height;
+ }
+
+
+ this.containerStyles = window.getComputedStyle(this.container);
+
+ this.containerPadding = {
+ left: parseFloat(this.containerStyles["padding-left"]) || 0,
+ right: parseFloat(this.containerStyles["padding-right"]) || 0,
+ top: parseFloat(this.containerStyles["padding-top"]) || 0,
+ bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0
+ };
+
+ return {
+ width: width -
+ this.containerPadding.left -
+ this.containerPadding.right,
+ height: height -
+ this.containerPadding.top -
+ this.containerPadding.bottom
+ };
+
+ };
+
+ bounds(){
+
+ if(!this.container) {
+ return windowBounds();
+ } else {
+ return this.container.getBoundingClientRect();
+ }
+
+ }
+
+ getSheet(){
+ var style = document.createElement("style");
+
+ // WebKit hack --> https://davidwalsh.name/add-rules-stylesheets
+ style.appendChild(document.createTextNode(""));
+
+ document.head.appendChild(style);
+
+ return style.sheet;
+ }
+
+ addStyleRules(selector, rulesArray){
+ var scope = "#" + this.id + " ";
+ var rules = "";
+
+ if(!this.sheet){
+ this.sheet = this.getSheet();
+ }
+
+ rulesArray.forEach(function(set) {
+ for (var prop in set) {
+ if(set.hasOwnProperty(prop)) {
+ rules += prop + ":" + set[prop] + ";";
+ }
+ }
+ })
+
+ this.sheet.insertRule(scope + selector + " {" + rules + "}", 0);
+ }
}
-
-
-module.exports = Stage;
+export default Stage;
diff --git a/src/managers/helpers/views.js b/src/managers/helpers/views.js
index 6c33c66..99804b5 100644
--- a/src/managers/helpers/views.js
+++ b/src/managers/helpers/views.js
@@ -1,165 +1,167 @@
-function Views(container) {
- this.container = container;
- this._views = [];
- this.length = 0;
- this.hidden = false;
-};
+class Views {
+ constructor(container) {
+ this.container = container;
+ this._views = [];
+ this.length = 0;
+ this.hidden = false;
+ };
-Views.prototype.all = function() {
- return this._views;
-};
+ all() {
+ return this._views;
+ };
-Views.prototype.first = function() {
- return this._views[0];
-};
+ first() {
+ return this._views[0];
+ };
-Views.prototype.last = function() {
- return this._views[this._views.length-1];
-};
+ last() {
+ return this._views[this._views.length-1];
+ };
-Views.prototype.indexOf = function(view) {
- return this._views.indexOf(view);
-};
+ indexOf(view) {
+ return this._views.indexOf(view);
+ };
-Views.prototype.slice = function() {
- return this._views.slice.apply(this._views, arguments);
-};
+ slice() {
+ return this._views.slice.apply(this._views, arguments);
+ };
-Views.prototype.get = function(i) {
- return this._views[i];
-};
+ get(i) {
+ return this._views[i];
+ };
-Views.prototype.append = function(view){
- this._views.push(view);
- if(this.container){
- this.container.appendChild(view.element);
- }
- this.length++;
- return view;
-};
-
-Views.prototype.prepend = function(view){
- this._views.unshift(view);
- if(this.container){
- this.container.insertBefore(view.element, this.container.firstChild);
- }
- this.length++;
- return view;
-};
-
-Views.prototype.insert = function(view, index) {
- this._views.splice(index, 0, view);
-
- if(this.container){
- if(index < this.container.children.length){
- this.container.insertBefore(view.element, this.container.children[index]);
- } else {
+ append(view){
+ this._views.push(view);
+ if(this.container){
this.container.appendChild(view.element);
}
- }
+ this.length++;
+ return view;
+ };
- this.length++;
- return view;
-};
+ prepend(view){
+ this._views.unshift(view);
+ if(this.container){
+ this.container.insertBefore(view.element, this.container.firstChild);
+ }
+ this.length++;
+ return view;
+ };
-Views.prototype.remove = function(view) {
- var index = this._views.indexOf(view);
+ insert(view, index) {
+ this._views.splice(index, 0, view);
- if(index > -1) {
- this._views.splice(index, 1);
- }
+ if(this.container){
+ if(index < this.container.children.length){
+ this.container.insertBefore(view.element, this.container.children[index]);
+ } else {
+ this.container.appendChild(view.element);
+ }
+ }
+
+ this.length++;
+ return view;
+ };
+
+ remove(view) {
+ var index = this._views.indexOf(view);
+
+ if(index > -1) {
+ this._views.splice(index, 1);
+ }
- this.destroy(view);
-
- this.length--;
-};
-
-Views.prototype.destroy = function(view) {
- if(view.displayed){
- view.destroy();
- }
-
- if(this.container){
- this.container.removeChild(view.element);
- }
- view = null;
-};
-
-// Iterators
-
-Views.prototype.each = function() {
- return this._views.forEach.apply(this._views, arguments);
-};
-
-Views.prototype.clear = function(){
- // Remove all views
- var view;
- var len = this.length;
-
- if(!this.length) return;
-
- for (var i = 0; i < len; i++) {
- view = this._views[i];
this.destroy(view);
- }
- this._views = [];
- this.length = 0;
-};
+ this.length--;
+ };
-Views.prototype.find = function(section){
-
- var view;
- var len = this.length;
-
- for (var i = 0; i < len; i++) {
- view = this._views[i];
- if(view.displayed && view.section.index == section.index) {
- return view;
- }
- }
-
-};
-
-Views.prototype.displayed = function(){
- var displayed = [];
- var view;
- var len = this.length;
-
- for (var i = 0; i < len; i++) {
- view = this._views[i];
+ destroy(view) {
if(view.displayed){
- displayed.push(view);
+ view.destroy();
}
- }
- return displayed;
-};
-Views.prototype.show = function(){
- var view;
- var len = this.length;
-
- for (var i = 0; i < len; i++) {
- view = this._views[i];
- if(view.displayed){
- view.show();
+ if(this.container){
+ this.container.removeChild(view.element);
}
- }
- this.hidden = false;
-};
+ view = null;
+ };
-Views.prototype.hide = function(){
- var view;
- var len = this.length;
+ // Iterators
- for (var i = 0; i < len; i++) {
- view = this._views[i];
- if(view.displayed){
- view.hide();
+ each() {
+ return this._views.forEach.apply(this._views, arguments);
+ };
+
+ clear(){
+ // Remove all views
+ var view;
+ var len = this.length;
+
+ if(!this.length) return;
+
+ for (var i = 0; i < len; i++) {
+ view = this._views[i];
+ this.destroy(view);
}
- }
- this.hidden = true;
-};
-module.exports = Views;
+ this._views = [];
+ this.length = 0;
+ };
+
+ find(section){
+
+ var view;
+ var len = this.length;
+
+ for (var i = 0; i < len; i++) {
+ view = this._views[i];
+ if(view.displayed && view.section.index == section.index) {
+ return view;
+ }
+ }
+
+ };
+
+ displayed(){
+ var displayed = [];
+ var view;
+ var len = this.length;
+
+ for (var i = 0; i < len; i++) {
+ view = this._views[i];
+ if(view.displayed){
+ displayed.push(view);
+ }
+ }
+ return displayed;
+ };
+
+ show(){
+ var view;
+ var len = this.length;
+
+ for (var i = 0; i < len; i++) {
+ view = this._views[i];
+ if(view.displayed){
+ view.show();
+ }
+ }
+ this.hidden = false;
+ };
+
+ hide(){
+ var view;
+ var len = this.length;
+
+ for (var i = 0; i < len; i++) {
+ view = this._views[i];
+ if(view.displayed){
+ view.hide();
+ }
+ }
+ this.hidden = true;
+ };
+}
+
+export default Views;
diff --git a/src/managers/views/iframe.js b/src/managers/views/iframe.js
index ad2bd8f..b082d85 100644
--- a/src/managers/views/iframe.js
+++ b/src/managers/views/iframe.js
@@ -1,575 +1,577 @@
-var EventEmitter = require('event-emitter');
-var core = require('../../core');
-var EpubCFI = require('../../epubcfi');
-var Contents = require('../../contents');
-
-function IframeView(section, options) {
- this.settings = core.extend({
- ignoreClass : '',
- axis: 'vertical',
- width: 0,
- height: 0,
- layout: undefined,
- globalLayoutProperties: {},
- }, options || {});
-
- this.id = "epubjs-view-" + core.uuid();
- this.section = section;
- this.index = section.index;
-
- this.element = this.container(this.settings.axis);
-
- this.added = false;
- this.displayed = false;
- this.rendered = false;
-
- this.width = this.settings.width;
- this.height = this.settings.height;
-
- this.fixedWidth = 0;
- this.fixedHeight = 0;
-
- // Blank Cfi for Parsing
- this.epubcfi = new EpubCFI();
-
- this.layout = this.settings.layout;
- // Dom events to listen for
- // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
-};
-
-IframeView.prototype.container = function(axis) {
- var element = document.createElement('div');
-
- element.classList.add("epub-view");
-
- // this.element.style.minHeight = "100px";
- element.style.height = "0px";
- element.style.width = "0px";
- element.style.overflow = "hidden";
-
- if(axis && axis == "horizontal"){
- element.style.display = "inline-block";
- } else {
- element.style.display = "block";
- }
-
- return element;
-};
-
-IframeView.prototype.create = function() {
-
- if(this.iframe) {
- return this.iframe;
- }
-
- if(!this.element) {
- this.element = this.createContainer();
- }
-
- this.iframe = document.createElement('iframe');
- this.iframe.id = this.id;
- this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations
- this.iframe.style.overflow = "hidden";
- this.iframe.seamless = "seamless";
- // Back up if seamless isn't supported
- this.iframe.style.border = "none";
-
- this.resizing = true;
-
- // this.iframe.style.display = "none";
- this.element.style.visibility = "hidden";
- this.iframe.style.visibility = "hidden";
-
- this.iframe.style.width = "0";
- this.iframe.style.height = "0";
- this._width = 0;
- this._height = 0;
-
- this.element.appendChild(this.iframe);
- this.added = true;
-
- this.elementBounds = core.bounds(this.element);
-
- // if(width || height){
- // this.resize(width, height);
- // } else if(this.width && this.height){
- // this.resize(this.width, this.height);
- // } else {
- // this.iframeBounds = core.bounds(this.iframe);
- // }
-
- // Firefox has trouble with baseURI and srcdoc
- // TODO: Disable for now in firefox
-
- if(!!("srcdoc" in this.iframe)) {
- this.supportsSrcdoc = true;
- } else {
- this.supportsSrcdoc = false;
- }
-
- return this.iframe;
-};
-
-IframeView.prototype.render = function(request, show) {
-
- // view.onLayout = this.layout.format.bind(this.layout);
- this.create();
-
- // Fit to size of the container, apply padding
- this.size();
-
- if(!this.sectionRender) {
- this.sectionRender = this.section.render(request);
- }
-
- // Render Chain
- return this.sectionRender
- .then(function(contents){
- return this.load(contents);
- }.bind(this))
- // .then(function(doc){
- // return this.hooks.content.trigger(view, this);
- // }.bind(this))
- .then(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
- 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
- this.addListeners();
-
- if(show !== false) {
- //this.q.enqueue(function(view){
- // this.show();
- //}, view);
- }
- // this.map = new Map(view, this.layout);
- //this.hooks.show.trigger(view, this);
- this.emit("rendered", this.section);
-
- }.bind(this))
- .catch(function(e){
- console.error(e);
- this.emit("loaderror", e);
- }.bind(this));
-
-};
-
-// Determine locks base on settings
-IframeView.prototype.size = function(_width, _height) {
- var width = _width || this.settings.width;
- var height = _height || this.settings.height;
-
- if(this.layout.name === "pre-paginated") {
- this.lock("both", width, height);
- } else if(this.settings.axis === "horizontal") {
- this.lock("height", width, height);
- } else {
- this.lock("width", width, height);
- }
-
-};
-
-// Lock an axis to element dimensions, taking borders into account
-IframeView.prototype.lock = function(what, width, height) {
- var elBorders = core.borders(this.element);
- var iframeBorders;
-
- if(this.iframe) {
- iframeBorders = core.borders(this.iframe);
- } else {
- iframeBorders = {width: 0, height: 0};
- }
-
- if(what == "width" && core.isNumber(width)){
- this.lockedWidth = width - elBorders.width - iframeBorders.width;
- this.resize(this.lockedWidth, width); // width keeps ratio correct
- }
-
- if(what == "height" && core.isNumber(height)){
- this.lockedHeight = height - elBorders.height - iframeBorders.height;
- this.resize(width, this.lockedHeight);
- }
-
- if(what === "both" &&
- core.isNumber(width) &&
- core.isNumber(height)){
-
- this.lockedWidth = width - elBorders.width - iframeBorders.width;
- this.lockedHeight = height - elBorders.height - iframeBorders.height;
-
- this.resize(this.lockedWidth, this.lockedHeight);
- }
-
- if(this.displayed && this.iframe) {
-
- // this.contents.layout();
- this.expand();
-
- }
-
-
-
-};
-
-// Resize a single axis based on content dimensions
-IframeView.prototype.expand = function(force) {
- var width = this.lockedWidth;
- var height = this.lockedHeight;
- var columns;
-
- var textWidth, textHeight;
-
- if(!this.iframe || this._expanding) return;
-
- this._expanding = true;
-
- // Expand Horizontally
- // if(height && !width) {
- if(this.settings.axis === "horizontal") {
- // Get the width of the text
- textWidth = this.contents.textWidth();
- // Check if the textWidth has changed
- if(textWidth != this._textWidth){
- // Get the contentWidth by resizing the iframe
- // Check with a min reset of the textWidth
- width = this.contentWidth(textWidth);
-
- columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap));
-
- if ( this.settings.layout.divisor > 1 &&
- this.settings.layout.name === "reflowable" &&
- (columns % 2 > 0)) {
- // add a blank page
- width += this.settings.layout.gap + this.settings.layout.columnWidth;
- }
-
- // Save the textWdith
- this._textWidth = textWidth;
- // Save the contentWidth
- this._contentWidth = width;
- } else {
- // Otherwise assume content height hasn't changed
- width = this._contentWidth;
- }
- } // Expand Vertically
- else if(this.settings.axis === "vertical") {
- textHeight = this.contents.textHeight();
- if(textHeight != this._textHeight){
- height = this.contentHeight(textHeight);
- this._textHeight = textHeight;
- this._contentHeight = height;
- } else {
- height = this._contentHeight;
- }
-
- }
-
- // Only Resize if dimensions have changed or
- // if Frame is still hidden, so needs reframing
- if(this._needsReframe || width != this._width || height != this._height){
- this.resize(width, height);
- }
-
- this._expanding = false;
-};
-
-IframeView.prototype.contentWidth = function(min) {
- var prev;
- var width;
-
- // Save previous width
- prev = this.iframe.style.width;
- // Set the iframe size to min, width will only ever be greater
- // Will preserve the aspect ratio
- this.iframe.style.width = (min || 0) + "px";
- // Get the scroll overflow width
- width = this.contents.scrollWidth();
- // Reset iframe size back
- this.iframe.style.width = prev;
- return width;
-};
-
-IframeView.prototype.contentHeight = function(min) {
- var prev;
- var height;
-
- prev = this.iframe.style.height;
- this.iframe.style.height = (min || 0) + "px";
- height = this.contents.scrollHeight();
-
- this.iframe.style.height = prev;
- return height;
-};
-
-
-IframeView.prototype.resize = function(width, height) {
-
- if(!this.iframe) return;
-
- if(core.isNumber(width)){
- this.iframe.style.width = width + "px";
- this._width = width;
- }
-
- if(core.isNumber(height)){
- this.iframe.style.height = height + "px";
- this._height = height;
- }
-
- this.iframeBounds = core.bounds(this.iframe);
-
- this.reframe(this.iframeBounds.width, this.iframeBounds.height);
-
-};
-
-IframeView.prototype.reframe = function(width, height) {
- var size;
-
- // if(!this.displayed) {
- // this._needsReframe = true;
- // return;
- // }
- if(core.isNumber(width)){
- this.element.style.width = width + "px";
- }
-
- if(core.isNumber(height)){
- this.element.style.height = height + "px";
- }
-
- this.prevBounds = this.elementBounds;
-
- this.elementBounds = core.bounds(this.element);
-
- size = {
- width: this.elementBounds.width,
- height: this.elementBounds.height,
- widthDelta: this.elementBounds.width - this.prevBounds.width,
- heightDelta: this.elementBounds.height - this.prevBounds.height,
+import EventEmitter from 'event-emitter';
+import {extend, borders, uuid, isNumber, bounds, defer} from '../../utils/core';
+import EpubCFI from '../../epubcfi';
+import Contents from '../../contents';
+
+class IframeView {
+ constructor(section, options) {
+ this.settings = extend({
+ ignoreClass : '',
+ axis: 'vertical',
+ width: 0,
+ height: 0,
+ layout: undefined,
+ globalLayoutProperties: {},
+ }, options || {});
+
+ this.id = "epubjs-view-" + uuid();
+ this.section = section;
+ this.index = section.index;
+
+ this.element = this.container(this.settings.axis);
+
+ this.added = false;
+ this.displayed = false;
+ this.rendered = false;
+
+ this.width = this.settings.width;
+ this.height = this.settings.height;
+
+ this.fixedWidth = 0;
+ this.fixedHeight = 0;
+
+ // Blank Cfi for Parsing
+ this.epubcfi = new EpubCFI();
+
+ this.layout = this.settings.layout;
+ // Dom events to listen for
+ // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
};
- this.onResize(this, size);
+ container(axis) {
+ var element = document.createElement('div');
- this.emit("resized", size);
+ element.classList.add("epub-view");
-};
+ // this.element.style.minHeight = "100px";
+ element.style.height = "0px";
+ element.style.width = "0px";
+ element.style.overflow = "hidden";
+
+ if(axis && axis == "horizontal"){
+ element.style.display = "inline-block";
+ } else {
+ element.style.display = "block";
+ }
+
+ return element;
+ };
+
+ create() {
+
+ if(this.iframe) {
+ return this.iframe;
+ }
+
+ if(!this.element) {
+ this.element = this.createContainer();
+ }
+
+ this.iframe = document.createElement('iframe');
+ this.iframe.id = this.id;
+ this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations
+ this.iframe.style.overflow = "hidden";
+ this.iframe.seamless = "seamless";
+ // Back up if seamless isn't supported
+ this.iframe.style.border = "none";
+
+ this.resizing = true;
+
+ // this.iframe.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.iframe.style.visibility = "hidden";
+
+ this.iframe.style.width = "0";
+ this.iframe.style.height = "0";
+ this._width = 0;
+ this._height = 0;
+
+ this.element.appendChild(this.iframe);
+ this.added = true;
+
+ this.elementBounds = bounds(this.element);
+
+ // if(width || height){
+ // this.resize(width, height);
+ // } else if(this.width && this.height){
+ // this.resize(this.width, this.height);
+ // } else {
+ // this.iframeBounds = bounds(this.iframe);
+ // }
+
+ // Firefox has trouble with baseURI and srcdoc
+ // TODO: Disable for now in firefox
+
+ if(!!("srcdoc" in this.iframe)) {
+ this.supportsSrcdoc = true;
+ } else {
+ this.supportsSrcdoc = false;
+ }
+
+ return this.iframe;
+ };
+
+ render(request, show) {
+
+ // view.onLayout = this.layout.format.bind(this.layout);
+ this.create();
+
+ // Fit to size of the container, apply padding
+ this.size();
+
+ if(!this.sectionRender) {
+ this.sectionRender = this.section.render(request);
+ }
+
+ // Render Chain
+ return this.sectionRender
+ .then(function(contents){
+ return this.load(contents);
+ }.bind(this))
+ // .then(function(doc){
+ // return this.hooks.content.trigger(view, this);
+ // }.bind(this))
+ .then(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
+ 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
+ this.addListeners();
+
+ if(show !== false) {
+ //this.q.enqueue(function(view){
+ // this.show();
+ //}, view);
+ }
+ // this.map = new Map(view, this.layout);
+ //this.hooks.show.trigger(view, this);
+ this.emit("rendered", this.section);
+
+ }.bind(this))
+ .catch(function(e){
+ console.error(e);
+ this.emit("loaderror", e);
+ }.bind(this));
+
+ };
+
+ // Determine locks base on settings
+ size(_width, _height) {
+ var width = _width || this.settings.width;
+ var height = _height || this.settings.height;
+
+ if(this.layout.name === "pre-paginated") {
+ this.lock("both", width, height);
+ } else if(this.settings.axis === "horizontal") {
+ this.lock("height", width, height);
+ } else {
+ this.lock("width", width, height);
+ }
+
+ };
+
+ // Lock an axis to element dimensions, taking borders into account
+ lock(what, width, height) {
+ var elBorders = borders(this.element);
+ var iframeBorders;
+
+ if(this.iframe) {
+ iframeBorders = borders(this.iframe);
+ } else {
+ iframeBorders = {width: 0, height: 0};
+ }
+
+ if(what == "width" && isNumber(width)){
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.resize(this.lockedWidth, width); // width keeps ratio correct
+ }
+
+ if(what == "height" && isNumber(height)){
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+ this.resize(width, this.lockedHeight);
+ }
+
+ if(what === "both" &&
+ isNumber(width) &&
+ isNumber(height)){
+
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+
+ this.resize(this.lockedWidth, this.lockedHeight);
+ }
+
+ if(this.displayed && this.iframe) {
+
+ // this.contents.layout();
+ this.expand();
+
+ }
-IframeView.prototype.load = function(contents) {
- var loading = new core.defer();
- var loaded = loading.promise;
- if(!this.iframe) {
- loading.reject(new Error("No Iframe Available"));
- return loaded;
- }
+ };
- this.iframe.onload = function(event) {
+ // Resize a single axis based on content dimensions
+ expand(force) {
+ var width = this.lockedWidth;
+ var height = this.lockedHeight;
+ var columns;
- this.onLoad(event, loading);
+ var textWidth, textHeight;
- }.bind(this);
+ if(!this.iframe || this._expanding) return;
- if(this.supportsSrcdoc){
- this.iframe.srcdoc = contents;
- } else {
+ this._expanding = true;
- this.document = this.iframe.contentDocument;
+ // Expand Horizontally
+ // if(height && !width) {
+ if(this.settings.axis === "horizontal") {
+ // Get the width of the text
+ textWidth = this.contents.textWidth();
+ // Check if the textWidth has changed
+ if(textWidth != this._textWidth){
+ // Get the contentWidth by resizing the iframe
+ // Check with a min reset of the textWidth
+ width = this.contentWidth(textWidth);
- if(!this.document) {
- loading.reject(new Error("No Document Available"));
+ columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap));
+
+ if ( this.settings.layout.divisor > 1 &&
+ this.settings.layout.name === "reflowable" &&
+ (columns % 2 > 0)) {
+ // add a blank page
+ width += this.settings.layout.gap + this.settings.layout.columnWidth;
+ }
+
+ // Save the textWdith
+ this._textWidth = textWidth;
+ // Save the contentWidth
+ this._contentWidth = width;
+ } else {
+ // Otherwise assume content height hasn't changed
+ width = this._contentWidth;
+ }
+ } // Expand Vertically
+ else if(this.settings.axis === "vertical") {
+ textHeight = this.contents.textHeight();
+ if(textHeight != this._textHeight){
+ height = this.contentHeight(textHeight);
+ this._textHeight = textHeight;
+ this._contentHeight = height;
+ } else {
+ height = this._contentHeight;
+ }
+
+ }
+
+ // Only Resize if dimensions have changed or
+ // if Frame is still hidden, so needs reframing
+ if(this._needsReframe || width != this._width || height != this._height){
+ this.resize(width, height);
+ }
+
+ this._expanding = false;
+ };
+
+ contentWidth(min) {
+ var prev;
+ var width;
+
+ // Save previous width
+ prev = this.iframe.style.width;
+ // Set the iframe size to min, width will only ever be greater
+ // Will preserve the aspect ratio
+ this.iframe.style.width = (min || 0) + "px";
+ // Get the scroll overflow width
+ width = this.contents.scrollWidth();
+ // Reset iframe size back
+ this.iframe.style.width = prev;
+ return width;
+ };
+
+ contentHeight(min) {
+ var prev;
+ var height;
+
+ prev = this.iframe.style.height;
+ this.iframe.style.height = (min || 0) + "px";
+ height = this.contents.scrollHeight();
+
+ this.iframe.style.height = prev;
+ return height;
+ };
+
+
+ resize(width, height) {
+
+ if(!this.iframe) return;
+
+ if(isNumber(width)){
+ this.iframe.style.width = width + "px";
+ this._width = width;
+ }
+
+ if(isNumber(height)){
+ this.iframe.style.height = height + "px";
+ this._height = height;
+ }
+
+ this.iframeBounds = bounds(this.iframe);
+
+ this.reframe(this.iframeBounds.width, this.iframeBounds.height);
+
+ };
+
+ reframe(width, height) {
+ var size;
+
+ // if(!this.displayed) {
+ // this._needsReframe = true;
+ // return;
+ // }
+ if(isNumber(width)){
+ this.element.style.width = width + "px";
+ }
+
+ if(isNumber(height)){
+ this.element.style.height = height + "px";
+ }
+
+ this.prevBounds = this.elementBounds;
+
+ this.elementBounds = bounds(this.element);
+
+ size = {
+ width: this.elementBounds.width,
+ height: this.elementBounds.height,
+ widthDelta: this.elementBounds.width - this.prevBounds.width,
+ heightDelta: this.elementBounds.height - this.prevBounds.height,
+ };
+
+ this.onResize(this, size);
+
+ this.emit("resized", size);
+
+ };
+
+
+ load(contents) {
+ var loading = new defer();
+ var loaded = loading.promise;
+
+ if(!this.iframe) {
+ loading.reject(new Error("No Iframe Available"));
return loaded;
}
- this.iframe.contentDocument.open();
- this.iframe.contentDocument.write(contents);
- this.iframe.contentDocument.close();
+ this.iframe.onload = function(event) {
- }
+ this.onLoad(event, loading);
- return loaded;
-};
+ }.bind(this);
-IframeView.prototype.onLoad = function(event, promise) {
-
- this.window = this.iframe.contentWindow;
- this.document = this.iframe.contentDocument;
-
- this.contents = new Contents(this.document, this.document.body, this.section.cfiBase);
-
- this.rendering = false;
-
- var link = this.document.querySelector("link[rel='canonical']");
- if (link) {
- link.setAttribute("href", this.section.url);
+ if(this.supportsSrcdoc){
+ this.iframe.srcdoc = contents;
} else {
- link = this.document.createElement("link");
- link.setAttribute("rel", "canonical");
- link.setAttribute("href", this.section.url);
- this.document.querySelector("head").appendChild(link);
+
+ this.document = this.iframe.contentDocument;
+
+ if(!this.document) {
+ loading.reject(new Error("No Document Available"));
+ return loaded;
+ }
+
+ this.iframe.contentDocument.open();
+ this.iframe.contentDocument.write(contents);
+ this.iframe.contentDocument.close();
+
}
- this.contents.on("expand", function () {
- if(this.displayed && this.iframe) {
- this.expand();
- }
- });
-
- promise.resolve(this.contents);
-};
-
-
-
-// IframeView.prototype.layout = function(layoutFunc) {
-//
-// this.iframe.style.display = "inline-block";
-//
-// // Reset Body Styles
-// // this.document.body.style.margin = "0";
-// //this.document.body.style.display = "inline-block";
-// //this.document.documentElement.style.width = "auto";
-//
-// if(layoutFunc){
-// this.layoutFunc = layoutFunc;
-// }
-//
-// this.contents.layout(this.layoutFunc);
-//
-// };
-//
-// IframeView.prototype.onLayout = function(view) {
-// // stub
-// };
-
-IframeView.prototype.setLayout = function(layout) {
- this.layout = layout;
-};
-
-IframeView.prototype.setAxis = function(axis) {
- this.settings.axis = axis;
-};
-
-IframeView.prototype.resizeListenters = function() {
- // Test size again
- clearTimeout(this.expanding);
- this.expanding = setTimeout(this.expand.bind(this), 350);
-};
-
-IframeView.prototype.addListeners = function() {
- //TODO: Add content listeners for expanding
-};
-
-IframeView.prototype.removeListeners = function(layoutFunc) {
- //TODO: remove content listeners for expanding
-};
-
-IframeView.prototype.display = function(request) {
- var displayed = new core.defer();
-
- if (!this.displayed) {
-
- this.render(request).then(function () {
-
- this.emit("displayed", this);
- this.onDisplayed(this);
-
- this.displayed = true;
- displayed.resolve(this);
-
- }.bind(this));
-
- } else {
- displayed.resolve(this);
- }
-
-
- return displayed.promise;
-};
-
-IframeView.prototype.show = function() {
-
- this.element.style.visibility = "visible";
-
- if(this.iframe){
- this.iframe.style.visibility = "visible";
- }
-
- this.emit("shown", this);
-};
-
-IframeView.prototype.hide = function() {
- // this.iframe.style.display = "none";
- this.element.style.visibility = "hidden";
- this.iframe.style.visibility = "hidden";
-
- this.stopExpanding = true;
- this.emit("hidden", this);
-};
-
-IframeView.prototype.position = function() {
- return this.element.getBoundingClientRect();
-};
-
-IframeView.prototype.locationOf = function(target) {
- var parentPos = this.iframe.getBoundingClientRect();
- var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
-
- return {
- "left": window.scrollX + parentPos.left + targetPos.left,
- "top": window.scrollY + parentPos.top + targetPos.top
+ return loaded;
};
-};
-IframeView.prototype.onDisplayed = function(view) {
- // Stub, override with a custom functions
-};
+ onLoad(event, promise) {
-IframeView.prototype.onResize = function(view, e) {
- // Stub, override with a custom functions
-};
+ this.window = this.iframe.contentWindow;
+ this.document = this.iframe.contentDocument;
-IframeView.prototype.bounds = function() {
- if(!this.elementBounds) {
- this.elementBounds = core.bounds(this.element);
- }
- return this.elementBounds;
-};
+ this.contents = new Contents(this.document, this.document.body, this.section.cfiBase);
-IframeView.prototype.destroy = function() {
+ this.rendering = false;
- if(this.displayed){
- this.displayed = false;
+ var link = this.document.querySelector("link[rel='canonical']");
+ if (link) {
+ link.setAttribute("href", this.section.url);
+ } else {
+ link = this.document.createElement("link");
+ link.setAttribute("rel", "canonical");
+ link.setAttribute("href", this.section.url);
+ this.document.querySelector("head").appendChild(link);
+ }
- this.removeListeners();
+ this.contents.on("expand", function () {
+ if(this.displayed && this.iframe) {
+ this.expand();
+ }
+ });
+
+ promise.resolve(this.contents);
+ };
+
+
+
+ // layout(layoutFunc) {
+ //
+ // this.iframe.style.display = "inline-block";
+ //
+ // // Reset Body Styles
+ // // this.document.body.style.margin = "0";
+ // //this.document.body.style.display = "inline-block";
+ // //this.document.documentElement.style.width = "auto";
+ //
+ // if(layoutFunc){
+ // this.layoutFunc = layoutFunc;
+ // }
+ //
+ // this.contents.layout(this.layoutFunc);
+ //
+ // };
+ //
+ // onLayout(view) {
+ // // stub
+ // };
+
+ setLayout(layout) {
+ this.layout = layout;
+ };
+
+ setAxis(axis) {
+ this.settings.axis = axis;
+ };
+
+ resizeListenters() {
+ // Test size again
+ clearTimeout(this.expanding);
+ this.expanding = setTimeout(this.expand.bind(this), 350);
+ };
+
+ addListeners() {
+ //TODO: Add content listeners for expanding
+ };
+
+ removeListeners(layoutFunc) {
+ //TODO: remove content listeners for expanding
+ };
+
+ display(request) {
+ var displayed = new defer();
+
+ if (!this.displayed) {
+
+ this.render(request).then(function () {
+
+ this.emit("displayed", this);
+ this.onDisplayed(this);
+
+ this.displayed = true;
+ displayed.resolve(this);
+
+ }.bind(this));
+
+ } else {
+ displayed.resolve(this);
+ }
+
+
+ return displayed.promise;
+ };
+
+ show() {
+
+ this.element.style.visibility = "visible";
+
+ if(this.iframe){
+ this.iframe.style.visibility = "visible";
+ }
+
+ this.emit("shown", this);
+ };
+
+ hide() {
+ // this.iframe.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.iframe.style.visibility = "hidden";
this.stopExpanding = true;
- this.element.removeChild(this.iframe);
- this.displayed = false;
- this.iframe = null;
+ this.emit("hidden", this);
+ };
- this._textWidth = null;
- this._textHeight = null;
- this._width = null;
- this._height = null;
- }
- // this.element.style.height = "0px";
- // this.element.style.width = "0px";
-};
+ position() {
+ return this.element.getBoundingClientRect();
+ };
+
+ locationOf(target) {
+ var parentPos = this.iframe.getBoundingClientRect();
+ var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
+
+ return {
+ "left": window.scrollX + parentPos.left + targetPos.left,
+ "top": window.scrollY + parentPos.top + targetPos.top
+ };
+ };
+
+ onDisplayed(view) {
+ // Stub, override with a custom functions
+ };
+
+ onResize(view, e) {
+ // Stub, override with a custom functions
+ };
+
+ bounds() {
+ if(!this.elementBounds) {
+ this.elementBounds = bounds(this.element);
+ }
+ return this.elementBounds;
+ };
+
+ destroy() {
+
+ if(this.displayed){
+ this.displayed = false;
+
+ this.removeListeners();
+
+ this.stopExpanding = true;
+ this.element.removeChild(this.iframe);
+ this.displayed = false;
+ this.iframe = null;
+
+ this._textWidth = null;
+ this._textHeight = null;
+ this._width = null;
+ this._height = null;
+ }
+ // this.element.style.height = "0px";
+ // this.element.style.width = "0px";
+ };
+}
EventEmitter(IframeView.prototype);
-module.exports = IframeView;
+export default IframeView;
diff --git a/src/managers/views/inline.js b/src/managers/views/inline.js
index 4469c1f..e207334 100644
--- a/src/managers/views/inline.js
+++ b/src/managers/views/inline.js
@@ -1,429 +1,431 @@
-var EventEmitter = require('event-emitter');
-var core = require('../../core');
-var EpubCFI = require('../../epubcfi');
-var Contents = require('../../contents');
-// var URI = require('urijs');
-
-function InlineView(section, options) {
- this.settings = core.extend({
- ignoreClass : '',
- axis: 'vertical',
- width: 0,
- height: 0,
- layout: undefined,
- globalLayoutProperties: {},
- }, options || {});
-
- this.id = "epubjs-view:" + core.uuid();
- this.section = section;
- this.index = section.index;
-
- this.element = this.container(this.settings.axis);
-
- this.added = false;
- this.displayed = false;
- this.rendered = false;
-
- this.width = this.settings.width;
- this.height = this.settings.height;
-
- this.fixedWidth = 0;
- this.fixedHeight = 0;
-
- // Blank Cfi for Parsing
- this.epubcfi = new EpubCFI();
-
- this.layout = this.settings.layout;
- // Dom events to listen for
- // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
-
-};
-
-InlineView.prototype.container = function(axis) {
- var element = document.createElement('div');
-
- 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";
-
- if(axis && axis == "horizontal"){
- element.style.display = "inline-block";
- } else {
- element.style.display = "block";
- }
-
- return element;
-};
-
-InlineView.prototype.create = function() {
-
- if(this.frame) {
- return this.frame;
- }
-
- if(!this.element) {
- this.element = this.createContainer();
- }
-
- this.frame = document.createElement('div');
- this.frame.id = this.id;
- this.frame.style.overflow = "hidden";
- this.frame.style.wordSpacing = "initial";
- this.frame.style.lineHeight = "initial";
-
- this.resizing = true;
-
- // this.frame.style.display = "none";
- this.element.style.visibility = "hidden";
- this.frame.style.visibility = "hidden";
-
- if(this.settings.axis === "horizontal") {
- this.frame.style.width = "auto";
- this.frame.style.height = "0";
- } else {
- this.frame.style.width = "0";
- this.frame.style.height = "auto";
- }
-
- this._width = 0;
- this._height = 0;
-
- this.element.appendChild(this.frame);
- this.added = true;
-
- this.elementBounds = core.bounds(this.element);
-
- return this.frame;
-};
-
-InlineView.prototype.render = function(request, show) {
-
- // view.onLayout = this.layout.format.bind(this.layout);
- this.create();
-
- // Fit to size of the container, apply padding
- this.size();
-
- // Render Chain
- return this.section.render(request)
- .then(function(contents){
- return this.load(contents);
- }.bind(this))
- // .then(function(doc){
- // return this.hooks.content.trigger(view, this);
- // }.bind(this))
- .then(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
- 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
- this.addListeners();
-
- if(show !== false) {
- //this.q.enqueue(function(view){
- this.show();
- //}, view);
- }
- // this.map = new Map(view, this.layout);
- //this.hooks.show.trigger(view, this);
- this.emit("rendered", this.section);
-
- }.bind(this))
- .catch(function(e){
- this.emit("loaderror", e);
- }.bind(this));
-
-};
-
-// Determine locks base on settings
-InlineView.prototype.size = function(_width, _height) {
- var width = _width || this.settings.width;
- var height = _height || this.settings.height;
-
- if(this.layout.name === "pre-paginated") {
- // TODO: check if these are different than the size set in chapter
- this.lock("both", width, height);
- } else if(this.settings.axis === "horizontal") {
- this.lock("height", width, height);
- } else {
- this.lock("width", width, height);
- }
-
-};
-
-// Lock an axis to element dimensions, taking borders into account
-InlineView.prototype.lock = function(what, width, height) {
- var elBorders = core.borders(this.element);
- var iframeBorders;
-
- if(this.frame) {
- iframeBorders = core.borders(this.frame);
- } else {
- iframeBorders = {width: 0, height: 0};
- }
-
- if(what == "width" && core.isNumber(width)){
- this.lockedWidth = width - elBorders.width - iframeBorders.width;
- this.resize(this.lockedWidth, false); // width keeps ratio correct
- }
-
- if(what == "height" && core.isNumber(height)){
- this.lockedHeight = height - elBorders.height - iframeBorders.height;
- this.resize(false, this.lockedHeight);
- }
-
- if(what === "both" &&
- core.isNumber(width) &&
- core.isNumber(height)){
-
- this.lockedWidth = width - elBorders.width - iframeBorders.width;
- this.lockedHeight = height - elBorders.height - iframeBorders.height;
-
- this.resize(this.lockedWidth, this.lockedHeight);
- }
-
-};
-
-// Resize a single axis based on content dimensions
-InlineView.prototype.expand = function(force) {
- var width = this.lockedWidth;
- var height = this.lockedHeight;
-
- var textWidth, textHeight;
-
- if(!this.frame || this._expanding) return;
-
- this._expanding = true;
-
- // Expand Horizontally
- if(this.settings.axis === "horizontal") {
- width = this.contentWidth(textWidth);
- } // Expand Vertically
- else if(this.settings.axis === "vertical") {
- height = this.contentHeight(textHeight);
- }
-
- // Only Resize if dimensions have changed or
- // if Frame is still hidden, so needs reframing
- if(this._needsReframe || width != this._width || height != this._height){
- this.resize(width, height);
- }
-
- this._expanding = false;
-};
-
-InlineView.prototype.contentWidth = function(min) {
- return this.frame.scrollWidth;
-};
-
-InlineView.prototype.contentHeight = function(min) {
- console.log(this.frame.scrollHeight);
- return this.frame.scrollHeight;
-};
-
-
-InlineView.prototype.resize = function(width, height) {
-
- if(!this.frame) return;
-
- if(core.isNumber(width)){
- this.frame.style.width = width + "px";
- this._width = width;
- }
-
- if(core.isNumber(height)){
- this.frame.style.height = height + "px";
- this._height = height;
- }
-
- this.prevBounds = this.elementBounds;
-
- this.elementBounds = core.bounds(this.element);
-
- size = {
- width: this.elementBounds.width,
- height: this.elementBounds.height,
- widthDelta: this.elementBounds.width - this.prevBounds.width,
- heightDelta: this.elementBounds.height - this.prevBounds.height,
- };
-
- this.onResize(this, size);
-
- this.emit("resized", size);
-
-};
-
-
-InlineView.prototype.load = function(contents) {
- var loading = new core.defer();
- var loaded = loading.promise;
- var doc = core.parse(contents, "text/html");
- var body = core.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.document = this.frame.ownerDocument;
- this.window = this.document.defaultView;
-
- this.contents = new Contents(this.document, this.frame);
-
- this.rendering = false;
-
- loading.resolve(this.contents);
-
-
- return loaded;
-};
-
-InlineView.prototype.setLayout = function(layout) {
- this.layout = layout;
-};
-
-
-InlineView.prototype.resizeListenters = function() {
- // Test size again
- // clearTimeout(this.expanding);
- // this.expanding = setTimeout(this.expand.bind(this), 350);
-};
-
-InlineView.prototype.addListeners = function() {
- //TODO: Add content listeners for expanding
-};
-
-InlineView.prototype.removeListeners = function(layoutFunc) {
- //TODO: remove content listeners for expanding
-};
-
-InlineView.prototype.display = function(request) {
- var displayed = new core.defer();
-
- if (!this.displayed) {
-
- this.render(request).then(function () {
-
- this.emit("displayed", this);
- this.onDisplayed(this);
-
- this.displayed = true;
-
- displayed.resolve(this);
-
- }.bind(this));
-
- } else {
- displayed.resolve(this);
- }
-
-
- return displayed.promise;
-};
-
-InlineView.prototype.show = function() {
-
- this.element.style.visibility = "visible";
-
- if(this.frame){
- this.frame.style.visibility = "visible";
- }
-
- this.emit("shown", this);
-};
-
-InlineView.prototype.hide = function() {
- // this.frame.style.display = "none";
- this.element.style.visibility = "hidden";
- this.frame.style.visibility = "hidden";
-
- this.stopExpanding = true;
- this.emit("hidden", this);
-};
-
-InlineView.prototype.position = function() {
- return this.element.getBoundingClientRect();
-};
-
-InlineView.prototype.locationOf = function(target) {
- var parentPos = this.frame.getBoundingClientRect();
- var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
-
- return {
- "left": window.scrollX + parentPos.left + targetPos.left,
- "top": window.scrollY + parentPos.top + targetPos.top
- };
-};
-
-InlineView.prototype.onDisplayed = function(view) {
- // Stub, override with a custom functions
-};
-
-InlineView.prototype.onResize = function(view, e) {
- // Stub, override with a custom functions
-};
-
-InlineView.prototype.bounds = function() {
- if(!this.elementBounds) {
- this.elementBounds = core.bounds(this.element);
- }
- return this.elementBounds;
-};
-
-InlineView.prototype.destroy = function() {
-
- if(this.displayed){
+import EventEmitter from 'event-emitter';
+import {extend, borders, uuid, isNumber, bounds, defer} from '../../utils/core';
+import EpubCFI from '../../epubcfi';
+import Contents from '../../contents';
+// import URI from 'urijs';
+
+class InlineView {
+ constructor(section, options) {
+ this.settings = extend({
+ ignoreClass : '',
+ axis: 'vertical',
+ width: 0,
+ height: 0,
+ layout: undefined,
+ globalLayoutProperties: {},
+ }, options || {});
+
+ this.id = "epubjs-view:" + uuid();
+ this.section = section;
+ this.index = section.index;
+
+ this.element = this.container(this.settings.axis);
+
+ this.added = false;
this.displayed = false;
+ this.rendered = false;
- this.removeListeners();
+ this.width = this.settings.width;
+ this.height = this.settings.height;
+
+ this.fixedWidth = 0;
+ this.fixedHeight = 0;
+
+ // Blank Cfi for Parsing
+ this.epubcfi = new EpubCFI();
+
+ this.layout = this.settings.layout;
+ // Dom events to listen for
+ // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
+
+ };
+
+ container(axis) {
+ var element = document.createElement('div');
+
+ 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";
+
+ if(axis && axis == "horizontal"){
+ element.style.display = "inline-block";
+ } else {
+ element.style.display = "block";
+ }
+
+ return element;
+ };
+
+ create() {
+
+ if(this.frame) {
+ return this.frame;
+ }
+
+ if(!this.element) {
+ this.element = this.createContainer();
+ }
+
+ this.frame = document.createElement('div');
+ this.frame.id = this.id;
+ this.frame.style.overflow = "hidden";
+ this.frame.style.wordSpacing = "initial";
+ this.frame.style.lineHeight = "initial";
+
+ this.resizing = true;
+
+ // this.frame.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.frame.style.visibility = "hidden";
+
+ if(this.settings.axis === "horizontal") {
+ this.frame.style.width = "auto";
+ this.frame.style.height = "0";
+ } else {
+ this.frame.style.width = "0";
+ this.frame.style.height = "auto";
+ }
+
+ this._width = 0;
+ this._height = 0;
+
+ this.element.appendChild(this.frame);
+ this.added = true;
+
+ this.elementBounds = bounds(this.element);
+
+ return this.frame;
+ };
+
+ render(request, show) {
+
+ // view.onLayout = this.layout.format.bind(this.layout);
+ this.create();
+
+ // Fit to size of the container, apply padding
+ this.size();
+
+ // Render Chain
+ return this.section.render(request)
+ .then(function(contents){
+ return this.load(contents);
+ }.bind(this))
+ // .then(function(doc){
+ // return this.hooks.content.trigger(view, this);
+ // }.bind(this))
+ .then(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
+ 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
+ this.addListeners();
+
+ if(show !== false) {
+ //this.q.enqueue(function(view){
+ this.show();
+ //}, view);
+ }
+ // this.map = new Map(view, this.layout);
+ //this.hooks.show.trigger(view, this);
+ this.emit("rendered", this.section);
+
+ }.bind(this))
+ .catch(function(e){
+ this.emit("loaderror", e);
+ }.bind(this));
+
+ };
+
+ // Determine locks base on settings
+ size(_width, _height) {
+ var width = _width || this.settings.width;
+ var height = _height || this.settings.height;
+
+ if(this.layout.name === "pre-paginated") {
+ // TODO: check if these are different than the size set in chapter
+ this.lock("both", width, height);
+ } else if(this.settings.axis === "horizontal") {
+ this.lock("height", width, height);
+ } else {
+ this.lock("width", width, height);
+ }
+
+ };
+
+ // Lock an axis to element dimensions, taking borders into account
+ lock(what, width, height) {
+ var elBorders = borders(this.element);
+ var iframeBorders;
+
+ if(this.frame) {
+ iframeBorders = borders(this.frame);
+ } else {
+ iframeBorders = {width: 0, height: 0};
+ }
+
+ if(what == "width" && isNumber(width)){
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.resize(this.lockedWidth, false); // width keeps ratio correct
+ }
+
+ if(what == "height" && isNumber(height)){
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+ this.resize(false, this.lockedHeight);
+ }
+
+ if(what === "both" &&
+ isNumber(width) &&
+ isNumber(height)){
+
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+
+ this.resize(this.lockedWidth, this.lockedHeight);
+ }
+
+ };
+
+ // Resize a single axis based on content dimensions
+ expand(force) {
+ var width = this.lockedWidth;
+ var height = this.lockedHeight;
+
+ var textWidth, textHeight;
+
+ if(!this.frame || this._expanding) return;
+
+ this._expanding = true;
+
+ // Expand Horizontally
+ if(this.settings.axis === "horizontal") {
+ width = this.contentWidth(textWidth);
+ } // Expand Vertically
+ else if(this.settings.axis === "vertical") {
+ height = this.contentHeight(textHeight);
+ }
+
+ // Only Resize if dimensions have changed or
+ // if Frame is still hidden, so needs reframing
+ if(this._needsReframe || width != this._width || height != this._height){
+ this.resize(width, height);
+ }
+
+ this._expanding = false;
+ };
+
+ contentWidth(min) {
+ return this.frame.scrollWidth;
+ };
+
+ contentHeight(min) {
+ console.log(this.frame.scrollHeight);
+ return this.frame.scrollHeight;
+ };
+
+
+ resize(width, height) {
+
+ if(!this.frame) return;
+
+ if(isNumber(width)){
+ this.frame.style.width = width + "px";
+ this._width = width;
+ }
+
+ if(isNumber(height)){
+ this.frame.style.height = height + "px";
+ this._height = height;
+ }
+
+ this.prevBounds = this.elementBounds;
+
+ this.elementBounds = bounds(this.element);
+
+ size = {
+ width: this.elementBounds.width,
+ height: this.elementBounds.height,
+ widthDelta: this.elementBounds.width - this.prevBounds.width,
+ heightDelta: this.elementBounds.height - this.prevBounds.height,
+ };
+
+ this.onResize(this, size);
+
+ this.emit("resized", size);
+
+ };
+
+
+ load(contents) {
+ var loading = new defer();
+ var loaded = loading.promise;
+ var doc = parse(contents, "text/html");
+ 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.document = this.frame.ownerDocument;
+ this.window = this.document.defaultView;
+
+ this.contents = new Contents(this.document, this.frame);
+
+ this.rendering = false;
+
+ loading.resolve(this.contents);
+
+
+ return loaded;
+ };
+
+ setLayout(layout) {
+ this.layout = layout;
+ };
+
+
+ resizeListenters() {
+ // Test size again
+ // clearTimeout(this.expanding);
+ // this.expanding = setTimeout(this.expand.bind(this), 350);
+ };
+
+ addListeners() {
+ //TODO: Add content listeners for expanding
+ };
+
+ removeListeners(layoutFunc) {
+ //TODO: remove content listeners for expanding
+ };
+
+ display(request) {
+ var displayed = new defer();
+
+ if (!this.displayed) {
+
+ this.render(request).then(function () {
+
+ this.emit("displayed", this);
+ this.onDisplayed(this);
+
+ this.displayed = true;
+
+ displayed.resolve(this);
+
+ }.bind(this));
+
+ } else {
+ displayed.resolve(this);
+ }
+
+
+ return displayed.promise;
+ };
+
+ show() {
+
+ this.element.style.visibility = "visible";
+
+ if(this.frame){
+ this.frame.style.visibility = "visible";
+ }
+
+ this.emit("shown", this);
+ };
+
+ hide() {
+ // this.frame.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.frame.style.visibility = "hidden";
this.stopExpanding = true;
- this.element.removeChild(this.frame);
- this.displayed = false;
- this.frame = null;
+ this.emit("hidden", this);
+ };
- this._textWidth = null;
- this._textHeight = null;
- this._width = null;
- this._height = null;
- }
- // this.element.style.height = "0px";
- // this.element.style.width = "0px";
-};
+ position() {
+ return this.element.getBoundingClientRect();
+ };
+
+ locationOf(target) {
+ var parentPos = this.frame.getBoundingClientRect();
+ var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
+
+ return {
+ "left": window.scrollX + parentPos.left + targetPos.left,
+ "top": window.scrollY + parentPos.top + targetPos.top
+ };
+ };
+
+ onDisplayed(view) {
+ // Stub, override with a custom functions
+ };
+
+ onResize(view, e) {
+ // Stub, override with a custom functions
+ };
+
+ bounds() {
+ if(!this.elementBounds) {
+ this.elementBounds = bounds(this.element);
+ }
+ return this.elementBounds;
+ };
+
+ destroy() {
+
+ if(this.displayed){
+ this.displayed = false;
+
+ this.removeListeners();
+
+ this.stopExpanding = true;
+ this.element.removeChild(this.frame);
+ this.displayed = false;
+ this.frame = null;
+
+ this._textWidth = null;
+ this._textHeight = null;
+ this._width = null;
+ this._height = null;
+ }
+ // this.element.style.height = "0px";
+ // this.element.style.width = "0px";
+ };
+}
EventEmitter(InlineView.prototype);
-module.exports = InlineView;
+export default InlineView;
diff --git a/src/mapping.js b/src/mapping.js
index 143e10d..8e18d01 100644
--- a/src/mapping.js
+++ b/src/mapping.js
@@ -1,297 +1,299 @@
-var EpubCFI = require('./epubcfi');
+import EpubCFI from './epubcfi';
-function Mapping(layout){
- this.layout = layout;
-};
-
-Mapping.prototype.section = function(view) {
- var ranges = this.findRanges(view);
- var map = this.rangeListToCfiList(view.section.cfiBase, ranges);
-
- return map;
-};
-
-Mapping.prototype.page = function(contents, cfiBase, start, end) {
- var root = contents && contents.document ? contents.document.body : false;
-
- if (!root) {
- return;
- }
-
- return this.rangePairToCfiPair(cfiBase, {
- start: this.findStart(root, start, end),
- end: this.findEnd(root, start, end)
- });
-};
-
-Mapping.prototype.walk = function(root, func) {
- //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false);
- var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
- acceptNode: function (node) {
- if ( node.data.trim().length > 0 ) {
- return NodeFilter.FILTER_ACCEPT;
- } else {
- return NodeFilter.FILTER_REJECT;
- }
- }
- }, false);
- var node;
- var result;
- while ((node = treeWalker.nextNode())) {
- result = func(node);
- if(result) break;
- }
-
- return result;
-};
-
-Mapping.prototype.findRanges = function(view){
- var columns = [];
- var scrollWidth = view.contents.scrollWidth();
- var count = this.layout.count(scrollWidth);
- var column = this.layout.column;
- var gap = this.layout.gap;
- var start, end;
-
- for (var i = 0; i < count.pages; i++) {
- start = (column + gap) * i;
- end = (column * (i+1)) + (gap * i);
- columns.push({
- start: this.findStart(view.document.body, start, end),
- end: this.findEnd(view.document.body, start, end)
- });
- }
-
- return columns;
-};
-
-Mapping.prototype.findStart = function(root, start, end){
- var stack = [root];
- var $el;
- var found;
- var $prev = root;
- while (stack.length) {
-
- $el = stack.shift();
-
- found = this.walk($el, function(node){
- var left, right;
- var elPos;
- var elRange;
-
-
- if(node.nodeType == Node.TEXT_NODE){
- elRange = document.createRange();
- elRange.selectNodeContents(node);
- elPos = elRange.getBoundingClientRect();
- } else {
- elPos = node.getBoundingClientRect();
- }
-
- left = elPos.left;
- right = elPos.right;
-
- if( left >= start && left <= end ) {
- return node;
- } else if (right > start) {
- return node;
- } else {
- $prev = node;
- stack.push(node);
- }
-
- });
-
- if(found) {
- return this.findTextStartRange(found, start, end);
- }
-
- }
-
- // Return last element
- return this.findTextStartRange($prev, start, end);
-};
-
-Mapping.prototype.findEnd = function(root, start, end){
- var stack = [root];
- var $el;
- var $prev = root;
- var found;
-
- while (stack.length) {
-
- $el = stack.shift();
-
- found = this.walk($el, function(node){
-
- var left, right;
- var elPos;
- var elRange;
-
-
- if(node.nodeType == Node.TEXT_NODE){
- elRange = document.createRange();
- elRange.selectNodeContents(node);
- elPos = elRange.getBoundingClientRect();
- } else {
- elPos = node.getBoundingClientRect();
- }
-
- left = elPos.left;
- right = elPos.right;
-
- if(left > end && $prev) {
- return $prev;
- } else if(right > end) {
- return node;
- } else {
- $prev = node;
- stack.push(node);
- }
-
- });
-
-
- if(found){
- return this.findTextEndRange(found, start, end);
- }
-
- }
-
- // end of chapter
- return this.findTextEndRange($prev, start, end);
-};
-
-
-Mapping.prototype.findTextStartRange = function(node, start, end){
- var ranges = this.splitTextNodeIntoRanges(node);
- var prev;
- var range;
- var pos;
-
- for (var i = 0; i < ranges.length; i++) {
- range = ranges[i];
-
- pos = range.getBoundingClientRect();
-
- if( pos.left >= start ) {
- return range;
- }
-
- prev = range;
-
- }
-
- return ranges[0];
-};
-
-Mapping.prototype.findTextEndRange = function(node, start, end){
- var ranges = this.splitTextNodeIntoRanges(node);
- var prev;
- var range;
- var pos;
-
- for (var i = 0; i < ranges.length; i++) {
- range = ranges[i];
-
- pos = range.getBoundingClientRect();
-
- if(pos.left > end && prev) {
- return prev;
- } else if(pos.right > end) {
- return range;
- }
-
- prev = range;
-
- }
-
- // Ends before limit
- return ranges[ranges.length-1];
-
-};
-
-Mapping.prototype.splitTextNodeIntoRanges = function(node, _splitter){
- var ranges = [];
- var textContent = node.textContent || "";
- var text = textContent.trim();
- var range;
- var rect;
- var list;
- var doc = node.ownerDocument;
- var splitter = _splitter || " ";
-
- pos = text.indexOf(splitter);
-
- if(pos === -1 || node.nodeType != Node.TEXT_NODE) {
- range = doc.createRange();
- range.selectNodeContents(node);
- return [range];
- }
-
- range = doc.createRange();
- range.setStart(node, 0);
- range.setEnd(node, pos);
- ranges.push(range);
- range = false;
-
- while ( pos != -1 ) {
-
- pos = text.indexOf(splitter, pos + 1);
- if(pos > 0) {
-
- if(range) {
- range.setEnd(node, pos);
- ranges.push(range);
- }
-
- range = doc.createRange();
- range.setStart(node, pos+1);
- }
- }
-
- if(range) {
- range.setEnd(node, text.length);
- ranges.push(range);
- }
-
- return ranges;
-};
-
-
-
-Mapping.prototype.rangePairToCfiPair = function(cfiBase, rangePair){
-
- var startRange = rangePair.start;
- var endRange = rangePair.end;
-
- startRange.collapse(true);
- endRange.collapse(true);
-
- // startCfi = section.cfiFromRange(startRange);
- // endCfi = section.cfiFromRange(endRange);
- startCfi = new EpubCFI(startRange, cfiBase).toString();
- endCfi = new EpubCFI(endRange, cfiBase).toString();
-
- return {
- start: startCfi,
- end: endCfi
+class Mapping {
+ constructor(layout) {
+ this.layout = layout;
};
-};
+ section(view) {
+ var ranges = this.findRanges(view);
+ var map = this.rangeListToCfiList(view.section.cfiBase, ranges);
-Mapping.prototype.rangeListToCfiList = function(cfiBase, columns){
- var map = [];
- var rangePair, cifPair;
+ return map;
+ };
- for (var i = 0; i < columns.length; i++) {
- cifPair = this.rangePairToCfiPair(cfiBase, columns[i]);
+ page(contents, cfiBase, start, end) {
+ var root = contents && contents.document ? contents.document.body : false;
- map.push(cifPair);
+ if (!root) {
+ return;
+ }
- }
+ return this.rangePairToCfiPair(cfiBase, {
+ start: this.findStart(root, start, end),
+ end: this.findEnd(root, start, end)
+ });
+ };
- return map;
-};
+ walk(root, func) {
+ //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false);
+ var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
+ acceptNode: function (node) {
+ if ( node.data.trim().length > 0 ) {
+ return NodeFilter.FILTER_ACCEPT;
+ } else {
+ return NodeFilter.FILTER_REJECT;
+ }
+ }
+ }, false);
+ var node;
+ var result;
+ while ((node = treeWalker.nextNode())) {
+ result = func(node);
+ if(result) break;
+ }
-module.exports = Mapping;
+ return result;
+ };
+
+ findRanges(view){
+ var columns = [];
+ var scrollWidth = view.contents.scrollWidth();
+ var count = this.layout.count(scrollWidth);
+ var column = this.layout.column;
+ var gap = this.layout.gap;
+ var start, end;
+
+ for (var i = 0; i < count.pages; i++) {
+ start = (column + gap) * i;
+ end = (column * (i+1)) + (gap * i);
+ columns.push({
+ start: this.findStart(view.document.body, start, end),
+ end: this.findEnd(view.document.body, start, end)
+ });
+ }
+
+ return columns;
+ };
+
+ findStart(root, start, end){
+ var stack = [root];
+ var $el;
+ var found;
+ var $prev = root;
+ while (stack.length) {
+
+ $el = stack.shift();
+
+ found = this.walk($el, function(node){
+ var left, right;
+ var elPos;
+ var elRange;
+
+
+ if(node.nodeType == Node.TEXT_NODE){
+ elRange = document.createRange();
+ elRange.selectNodeContents(node);
+ elPos = elRange.getBoundingClientRect();
+ } else {
+ elPos = node.getBoundingClientRect();
+ }
+
+ left = elPos.left;
+ right = elPos.right;
+
+ if( left >= start && left <= end ) {
+ return node;
+ } else if (right > start) {
+ return node;
+ } else {
+ $prev = node;
+ stack.push(node);
+ }
+
+ });
+
+ if(found) {
+ return this.findTextStartRange(found, start, end);
+ }
+
+ }
+
+ // Return last element
+ return this.findTextStartRange($prev, start, end);
+ };
+
+ findEnd(root, start, end){
+ var stack = [root];
+ var $el;
+ var $prev = root;
+ var found;
+
+ while (stack.length) {
+
+ $el = stack.shift();
+
+ found = this.walk($el, function(node){
+
+ var left, right;
+ var elPos;
+ var elRange;
+
+
+ if(node.nodeType == Node.TEXT_NODE){
+ elRange = document.createRange();
+ elRange.selectNodeContents(node);
+ elPos = elRange.getBoundingClientRect();
+ } else {
+ elPos = node.getBoundingClientRect();
+ }
+
+ left = elPos.left;
+ right = elPos.right;
+
+ if(left > end && $prev) {
+ return $prev;
+ } else if(right > end) {
+ return node;
+ } else {
+ $prev = node;
+ stack.push(node);
+ }
+
+ });
+
+
+ if(found){
+ return this.findTextEndRange(found, start, end);
+ }
+
+ }
+
+ // end of chapter
+ return this.findTextEndRange($prev, start, end);
+ };
+
+
+ findTextStartRange(node, start, end){
+ var ranges = this.splitTextNodeIntoRanges(node);
+ var prev;
+ var range;
+ var pos;
+
+ for (var i = 0; i < ranges.length; i++) {
+ range = ranges[i];
+
+ pos = range.getBoundingClientRect();
+
+ if( pos.left >= start ) {
+ return range;
+ }
+
+ prev = range;
+
+ }
+
+ return ranges[0];
+ };
+
+ findTextEndRange(node, start, end){
+ var ranges = this.splitTextNodeIntoRanges(node);
+ var prev;
+ var range;
+ var pos;
+
+ for (var i = 0; i < ranges.length; i++) {
+ range = ranges[i];
+
+ pos = range.getBoundingClientRect();
+
+ if(pos.left > end && prev) {
+ return prev;
+ } else if(pos.right > end) {
+ return range;
+ }
+
+ prev = range;
+
+ }
+
+ // Ends before limit
+ return ranges[ranges.length-1];
+
+ };
+
+ splitTextNodeIntoRanges(node, _splitter){
+ var ranges = [];
+ var textContent = node.textContent || "";
+ var text = textContent.trim();
+ var range;
+ var rect;
+ var list;
+ var doc = node.ownerDocument;
+ var splitter = _splitter || " ";
+
+ var pos = text.indexOf(splitter);
+
+ if(pos === -1 || node.nodeType != Node.TEXT_NODE) {
+ range = doc.createRange();
+ range.selectNodeContents(node);
+ return [range];
+ }
+
+ range = doc.createRange();
+ range.setStart(node, 0);
+ range.setEnd(node, pos);
+ ranges.push(range);
+ range = false;
+
+ while ( pos != -1 ) {
+
+ pos = text.indexOf(splitter, pos + 1);
+ if(pos > 0) {
+
+ if(range) {
+ range.setEnd(node, pos);
+ ranges.push(range);
+ }
+
+ range = doc.createRange();
+ range.setStart(node, pos+1);
+ }
+ }
+
+ if(range) {
+ range.setEnd(node, text.length);
+ ranges.push(range);
+ }
+
+ return ranges;
+ };
+
+
+
+ rangePairToCfiPair(cfiBase, rangePair){
+
+ var startRange = rangePair.start;
+ var endRange = rangePair.end;
+
+ startRange.collapse(true);
+ endRange.collapse(true);
+
+ // startCfi = section.cfiFromRange(startRange);
+ // endCfi = section.cfiFromRange(endRange);
+ let startCfi = new EpubCFI(startRange, cfiBase).toString();
+ let endCfi = new EpubCFI(endRange, cfiBase).toString();
+
+ return {
+ start: startCfi,
+ end: endCfi
+ };
+
+ };
+
+ rangeListToCfiList(cfiBase, columns){
+ var map = [];
+ var rangePair, cifPair;
+
+ for (var i = 0; i < columns.length; i++) {
+ cifPair = this.rangePairToCfiPair(cfiBase, columns[i]);
+
+ map.push(cifPair);
+
+ }
+
+ return map;
+ };
+}
+
+export default Mapping;
diff --git a/src/navigation.js b/src/navigation.js
index 776ff20..ccd0d09 100644
--- a/src/navigation.js
+++ b/src/navigation.js
@@ -1,200 +1,201 @@
-var core = require('./core');
-var path = require('path');
+import {qs, qsa, querySelectorByType} from './utils/core';
/**
* Navigation Parser
* @param {document} xml navigation html / xhtml / ncx
*/
-function Navigation(xml){
- this.toc = [];
- this.tocByHref = {};
- this.tocById = {};
+class Navigation {
+ constructor(xml) {
+ this.toc = [];
+ this.tocByHref = {};
+ this.tocById = {};
- if (xml) {
- this.parse(xml);
- }
-};
-
-/**
- * Parse out the navigation items
- * @param {document} xml navigation html / xhtml / ncx
- */
-Navigation.prototype.parse = function(xml) {
- var html = core.qs(xml, "html");
- var ncx = core.qs(xml, "ncx");
-
- if(html) {
- this.toc = this.parseNav(xml);
- } else if(ncx){
- this.toc = this.parseNcx(xml);
- }
-
- this.unpack(this.toc);
-};
-
-/**
- * Unpack navigation items
- * @private
- * @param {array} toc
- */
-Navigation.prototype.unpack = function(toc) {
- var item;
-
- for (var i = 0; i < toc.length; i++) {
- item = toc[i];
- this.tocByHref[item.href] = i;
- this.tocById[item.id] = i;
- }
-
-};
-
-/**
- * Get an item from the navigation
- * @param {string} target
- * @return {object} navItems
- */
-Navigation.prototype.get = function(target) {
- var index;
-
- if(!target) {
- return this.toc;
- }
-
- if(target.indexOf("#") === 0) {
- index = this.tocById[target.substring(1)];
- } else if(target in this.tocByHref){
- index = this.tocByHref[target];
- }
-
- return this.toc[index];
-};
-
-/**
- * Parse from a Epub > 3.0 Nav
- * @private
- * @param {document} navHtml
- * @return {array} navigation list
- */
-Navigation.prototype.parseNav = function(navHtml){
- var navElement = core.querySelectorByType(navHtml, "nav", "toc");
- var navItems = navElement ? core.qsa(navElement, "li") : [];
- var length = navItems.length;
- var i;
- var toc = {};
- var list = [];
- var item, parent;
-
- if(!navItems || length === 0) return list;
-
- for (i = 0; i < length; ++i) {
- item = this.navItem(navItems[i]);
- toc[item.id] = item;
- if(!item.parent) {
- list.push(item);
- } else {
- parent = toc[item.parent];
- parent.subitems.push(item);
+ if (xml) {
+ this.parse(xml);
}
- }
-
- return list;
-};
-
-/**
- * Create a navItem
- * @private
- * @param {element} item
- * @return {object} navItem
- */
-Navigation.prototype.navItem = function(item){
- var id = item.getAttribute('id') || false,
- content = core.qs(item, "a"),
- src = content.getAttribute('href') || '',
- text = content.textContent || "",
- subitems = [],
- parentNode = item.parentNode,
- parent;
-
- if(parentNode && parentNode.nodeName === "navPoint") {
- parent = parentNode.getAttribute('id');
- }
-
- return {
- "id": id,
- "href": src,
- "label": text,
- "subitems" : subitems,
- "parent" : parent
};
-};
-/**
- * Parse from a Epub > 3.0 NC
- * @private
- * @param {document} navHtml
- * @return {array} navigation list
- */
-Navigation.prototype.parseNcx = function(tocXml){
- var navPoints = core.qsa(tocXml, "navPoint");
- var length = navPoints.length;
- var i;
- var toc = {};
- var list = [];
- var item, parent;
+ /**
+ * Parse out the navigation items
+ * @param {document} xml navigation html / xhtml / ncx
+ */
+ parse(xml) {
+ var html = qs(xml, "html");
+ var ncx = qs(xml, "ncx");
- if(!navPoints || length === 0) return list;
-
- for (i = 0; i < length; ++i) {
- item = this.ncxItem(navPoints[i]);
- toc[item.id] = item;
- if(!item.parent) {
- list.push(item);
- } else {
- parent = toc[item.parent];
- parent.subitems.push(item);
+ if(html) {
+ this.toc = this.parseNav(xml);
+ } else if(ncx){
+ this.toc = this.parseNcx(xml);
}
- }
- return list;
-};
-
-/**
- * Create a ncxItem
- * @private
- * @param {element} item
- * @return {object} ncxItem
- */
-Navigation.prototype.ncxItem = function(item){
- var id = item.getAttribute('id') || false,
- content = core.qs(item, "content"),
- src = content.getAttribute('src'),
- navLabel = core.qs(item, "navLabel"),
- text = navLabel.textContent ? navLabel.textContent : "",
- subitems = [],
- parentNode = item.parentNode,
- parent;
-
- if(parentNode && parentNode.nodeName === "navPoint") {
- parent = parentNode.getAttribute('id');
- }
-
-
- return {
- "id": id,
- "href": src,
- "label": text,
- "subitems" : subitems,
- "parent" : parent
+ this.unpack(this.toc);
};
-};
-/**
- * forEach pass through
- * @param {Function} fn function to run on each item
- * @return {method} forEach loop
- */
-Navigation.prototype.forEach = function(fn) {
- return this.toc.forEach(fn);
-};
+ /**
+ * Unpack navigation items
+ * @private
+ * @param {array} toc
+ */
+ unpack(toc) {
+ var item;
-module.exports = Navigation;
+ for (var i = 0; i < toc.length; i++) {
+ item = toc[i];
+ this.tocByHref[item.href] = i;
+ this.tocById[item.id] = i;
+ }
+
+ };
+
+ /**
+ * Get an item from the navigation
+ * @param {string} target
+ * @return {object} navItems
+ */
+ get(target) {
+ var index;
+
+ if(!target) {
+ return this.toc;
+ }
+
+ if(target.indexOf("#") === 0) {
+ index = this.tocById[target.substring(1)];
+ } else if(target in this.tocByHref){
+ index = this.tocByHref[target];
+ }
+
+ return this.toc[index];
+ };
+
+ /**
+ * Parse from a Epub > 3.0 Nav
+ * @private
+ * @param {document} navHtml
+ * @return {array} navigation list
+ */
+ parseNav(navHtml){
+ var navElement = querySelectorByType(navHtml, "nav", "toc");
+ var navItems = navElement ? qsa(navElement, "li") : [];
+ var length = navItems.length;
+ var i;
+ var toc = {};
+ var list = [];
+ var item, parent;
+
+ if(!navItems || length === 0) return list;
+
+ for (i = 0; i < length; ++i) {
+ item = this.navItem(navItems[i]);
+ toc[item.id] = item;
+ if(!item.parent) {
+ list.push(item);
+ } else {
+ parent = toc[item.parent];
+ parent.subitems.push(item);
+ }
+ }
+
+ return list;
+ };
+
+ /**
+ * Create a navItem
+ * @private
+ * @param {element} item
+ * @return {object} navItem
+ */
+ navItem(item){
+ var id = item.getAttribute('id') || false,
+ content = qs(item, "a"),
+ src = content.getAttribute('href') || '',
+ text = content.textContent || "",
+ subitems = [],
+ parentNode = item.parentNode,
+ parent;
+
+ if(parentNode && parentNode.nodeName === "navPoint") {
+ parent = parentNode.getAttribute('id');
+ }
+
+ return {
+ "id": id,
+ "href": src,
+ "label": text,
+ "subitems" : subitems,
+ "parent" : parent
+ };
+ };
+
+ /**
+ * Parse from a Epub > 3.0 NC
+ * @private
+ * @param {document} navHtml
+ * @return {array} navigation list
+ */
+ parseNcx(tocXml){
+ var navPoints = qsa(tocXml, "navPoint");
+ var length = navPoints.length;
+ var i;
+ var toc = {};
+ var list = [];
+ var item, parent;
+
+ if(!navPoints || length === 0) return list;
+
+ for (i = 0; i < length; ++i) {
+ item = this.ncxItem(navPoints[i]);
+ toc[item.id] = item;
+ if(!item.parent) {
+ list.push(item);
+ } else {
+ parent = toc[item.parent];
+ parent.subitems.push(item);
+ }
+ }
+
+ return list;
+ };
+
+ /**
+ * Create a ncxItem
+ * @private
+ * @param {element} item
+ * @return {object} ncxItem
+ */
+ ncxItem(item){
+ var id = item.getAttribute('id') || false,
+ content = qs(item, "content"),
+ src = content.getAttribute('src'),
+ navLabel = qs(item, "navLabel"),
+ text = navLabel.textContent ? navLabel.textContent : "",
+ subitems = [],
+ parentNode = item.parentNode,
+ parent;
+
+ if(parentNode && parentNode.nodeName === "navPoint") {
+ parent = parentNode.getAttribute('id');
+ }
+
+
+ return {
+ "id": id,
+ "href": src,
+ "label": text,
+ "subitems" : subitems,
+ "parent" : parent
+ };
+ };
+
+ /**
+ * forEach pass through
+ * @param {Function} fn function to run on each item
+ * @return {method} forEach loop
+ */
+ forEach(fn) {
+ return this.toc.forEach(fn);
+ };
+}
+
+export default Navigation;
diff --git a/src/packaging.js b/src/packaging.js
index 9b473c5..bc5c9bb 100644
--- a/src/packaging.js
+++ b/src/packaging.js
@@ -1,282 +1,283 @@
-var path = require('path');
-var core = require('./core');
-var EpubCFI = require('./epubcfi');
+import {qs, qsa, qsp} from './utils/core';
+import EpubCFI from './epubcfi';
/**
* Open Packaging Format Parser
* @class
* @param {document} packageDocument OPF XML
*/
-function Packaging(packageDocument) {
- if (packageDocument) {
- this.parse(packageDocument);
- }
-};
-
-/**
- * Parse OPF XML
- * @param {document} packageDocument OPF XML
- * @return {object} parsed package parts
- */
-Packaging.prototype.parse = function(packageDocument){
- var metadataNode, manifestNode, spineNode;
-
- if(!packageDocument) {
- console.error("Package File Not Found");
- return;
- }
-
- metadataNode = core.qs(packageDocument, "metadata");
- if(!metadataNode) {
- console.error("No Metadata Found");
- return;
- }
-
- manifestNode = core.qs(packageDocument, "manifest");
- if(!manifestNode) {
- console.error("No Manifest Found");
- return;
- }
-
- spineNode = core.qs(packageDocument, "spine");
- if(!spineNode) {
- console.error("No Spine Found");
- return;
- }
-
- this.manifest = this.parseManifest(manifestNode);
- this.navPath = this.findNavPath(manifestNode);
- this.ncxPath = this.findNcxPath(manifestNode, spineNode);
- this.coverPath = this.findCoverPath(packageDocument);
-
- this.spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);
-
- this.spine = this.parseSpine(spineNode, this.manifest);
-
- this.metadata = this.parseMetadata(metadataNode);
-
- this.metadata.direction = spineNode.getAttribute("page-progression-direction");
-
-
- return {
- 'metadata' : this.metadata,
- 'spine' : this.spine,
- 'manifest' : this.manifest,
- 'navPath' : this.navPath,
- 'ncxPath' : this.ncxPath,
- 'coverPath': this.coverPath,
- 'spineNodeIndex' : this.spineNodeIndex
- };
-};
-
-/**
- * Parse Metadata
- * @private
- * @param {document} xml
- * @return {object} metadata
- */
-Packaging.prototype.parseMetadata = function(xml){
- var metadata = {};
-
- metadata.title = this.getElementText(xml, 'title');
- metadata.creator = this.getElementText(xml, 'creator');
- metadata.description = this.getElementText(xml, 'description');
-
- metadata.pubdate = this.getElementText(xml, 'date');
-
- metadata.publisher = this.getElementText(xml, 'publisher');
-
- metadata.identifier = this.getElementText(xml, "identifier");
- metadata.language = this.getElementText(xml, "language");
- metadata.rights = this.getElementText(xml, "rights");
-
- metadata.modified_date = this.getPropertyText(xml, 'dcterms:modified');
-
- metadata.layout = this.getPropertyText(xml, "rendition:layout");
- metadata.orientation = this.getPropertyText(xml, 'rendition:orientation');
- metadata.flow = this.getPropertyText(xml, 'rendition:flow');
- metadata.viewport = this.getPropertyText(xml, 'rendition:viewport');
- // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
-
- return metadata;
-};
-
-/**
- * Parse Manifest
- * @private
- * @param {document} manifestXml
- * @return {object} manifest
- */
-Packaging.prototype.parseManifest = function(manifestXml){
- var manifest = {};
-
- //-- Turn items into an array
- // var selected = manifestXml.querySelectorAll("item");
- var selected = core.qsa(manifestXml, "item");
- var items = Array.prototype.slice.call(selected);
-
- //-- Create an object with the id as key
- items.forEach(function(item){
- var id = item.getAttribute('id'),
- href = item.getAttribute('href') || '',
- type = item.getAttribute('media-type') || '',
- properties = item.getAttribute('properties') || '';
-
- manifest[id] = {
- 'href' : href,
- // 'url' : href,
- 'type' : type,
- 'properties' : properties.length ? properties.split(' ') : []
- };
-
- });
-
- return manifest;
-
-};
-
-/**
- * Parse Spine
- * @param {document} spineXml
- * @param {Packaging.manifest} manifest
- * @return {object} spine
- */
-Packaging.prototype.parseSpine = function(spineXml, manifest){
- var spine = [];
-
- var selected = spineXml.getElementsByTagName("itemref"),
- items = Array.prototype.slice.call(selected);
-
- var epubcfi = new EpubCFI();
-
- //-- Add to array to mantain ordering and cross reference with manifest
- items.forEach(function(item, index){
- var idref = item.getAttribute('idref');
- // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);
- var props = item.getAttribute('properties') || '';
- var propArray = props.length ? props.split(' ') : [];
- // var manifestProps = manifest[Id].properties;
- // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];
-
- var itemref = {
- 'idref' : idref,
- 'linear' : item.getAttribute('linear') || '',
- 'properties' : propArray,
- // 'href' : manifest[Id].href,
- // 'url' : manifest[Id].url,
- 'index' : index
- // 'cfiBase' : cfiBase
- };
- spine.push(itemref);
- });
-
- return spine;
-};
-
-/**
- * Find TOC NAV
- * @private
- */
-Packaging.prototype.findNavPath = function(manifestNode){
- // Find item with property 'nav'
- // Should catch nav irregardless of order
- // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']");
- var node = core.qsp(manifestNode, "item", {"properties":"nav"});
- return node ? node.getAttribute('href') : false;
-};
-
-/**
- * Find TOC NCX
- * media-type="application/x-dtbncx+xml" href="toc.ncx"
- * @private
- */
-Packaging.prototype.findNcxPath = function(manifestNode, spineNode){
- // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
- var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"});
- 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
- // according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,
- // "The item that describes the NCX must be referenced by the spine toc attribute."
- if (!node) {
- tocId = spineNode.getAttribute("toc");
- if(tocId) {
- // node = manifestNode.querySelector("item[id='" + tocId + "']");
- node = manifestNode.getElementById(tocId);
+class Packaging {
+ constructor(packageDocument) {
+ if (packageDocument) {
+ this.parse(packageDocument);
}
- }
+ };
- return node ? node.getAttribute('href') : false;
-};
+ /**
+ * Parse OPF XML
+ * @param {document} packageDocument OPF XML
+ * @return {object} parsed package parts
+ */
+ parse(packageDocument){
+ var metadataNode, manifestNode, spineNode;
-/**
- * Find the Cover Path
- *
- * Fallback for Epub 2.0
- * @param {document} packageXml
- * @return {string} href
- */
-Packaging.prototype.findCoverPath = function(packageXml){
- var pkg = core.qs(packageXml, "package");
- var epubVersion = pkg.getAttribute('version');
+ if(!packageDocument) {
+ console.error("Package File Not Found");
+ return;
+ }
- if (epubVersion === '2.0') {
- var metaCover = core.qsp(packageXml, 'meta', {'name':'cover'});
- if (metaCover) {
- var coverId = metaCover.getAttribute('content');
- // var cover = packageXml.querySelector("item[id='" + coverId + "']");
- var cover = packageXml.getElementById(coverId);
- return cover ? cover.getAttribute('href') : '';
+ metadataNode = qs(packageDocument, "metadata");
+ if(!metadataNode) {
+ console.error("No Metadata Found");
+ return;
+ }
+
+ manifestNode = qs(packageDocument, "manifest");
+ if(!manifestNode) {
+ console.error("No Manifest Found");
+ return;
+ }
+
+ spineNode = qs(packageDocument, "spine");
+ if(!spineNode) {
+ console.error("No Spine Found");
+ return;
+ }
+
+ this.manifest = this.parseManifest(manifestNode);
+ this.navPath = this.findNavPath(manifestNode);
+ this.ncxPath = this.findNcxPath(manifestNode, spineNode);
+ this.coverPath = this.findCoverPath(packageDocument);
+
+ this.spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);
+
+ this.spine = this.parseSpine(spineNode, this.manifest);
+
+ this.metadata = this.parseMetadata(metadataNode);
+
+ this.metadata.direction = spineNode.getAttribute("page-progression-direction");
+
+
+ return {
+ 'metadata' : this.metadata,
+ 'spine' : this.spine,
+ 'manifest' : this.manifest,
+ 'navPath' : this.navPath,
+ 'ncxPath' : this.ncxPath,
+ 'coverPath': this.coverPath,
+ 'spineNodeIndex' : this.spineNodeIndex
+ };
+ };
+
+ /**
+ * Parse Metadata
+ * @private
+ * @param {document} xml
+ * @return {object} metadata
+ */
+ parseMetadata(xml){
+ var metadata = {};
+
+ metadata.title = this.getElementText(xml, 'title');
+ metadata.creator = this.getElementText(xml, 'creator');
+ metadata.description = this.getElementText(xml, 'description');
+
+ metadata.pubdate = this.getElementText(xml, 'date');
+
+ metadata.publisher = this.getElementText(xml, 'publisher');
+
+ metadata.identifier = this.getElementText(xml, "identifier");
+ metadata.language = this.getElementText(xml, "language");
+ metadata.rights = this.getElementText(xml, "rights");
+
+ metadata.modified_date = this.getPropertyText(xml, 'dcterms:modified');
+
+ metadata.layout = this.getPropertyText(xml, "rendition:layout");
+ metadata.orientation = this.getPropertyText(xml, 'rendition:orientation');
+ metadata.flow = this.getPropertyText(xml, 'rendition:flow');
+ metadata.viewport = this.getPropertyText(xml, 'rendition:viewport');
+ // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
+
+ return metadata;
+ };
+
+ /**
+ * Parse Manifest
+ * @private
+ * @param {document} manifestXml
+ * @return {object} manifest
+ */
+ parseManifest(manifestXml){
+ var manifest = {};
+
+ //-- Turn items into an array
+ // var selected = manifestXml.querySelectorAll("item");
+ var selected = qsa(manifestXml, "item");
+ var items = Array.prototype.slice.call(selected);
+
+ //-- Create an object with the id as key
+ items.forEach(function(item){
+ var id = item.getAttribute('id'),
+ href = item.getAttribute('href') || '',
+ type = item.getAttribute('media-type') || '',
+ properties = item.getAttribute('properties') || '';
+
+ manifest[id] = {
+ 'href' : href,
+ // 'url' : href,
+ 'type' : type,
+ 'properties' : properties.length ? properties.split(' ') : []
+ };
+
+ });
+
+ return manifest;
+
+ };
+
+ /**
+ * Parse Spine
+ * @param {document} spineXml
+ * @param {Packaging.manifest} manifest
+ * @return {object} spine
+ */
+ parseSpine(spineXml, manifest){
+ var spine = [];
+
+ var selected = spineXml.getElementsByTagName("itemref"),
+ items = Array.prototype.slice.call(selected);
+
+ var epubcfi = new EpubCFI();
+
+ //-- Add to array to mantain ordering and cross reference with manifest
+ items.forEach(function(item, index){
+ var idref = item.getAttribute('idref');
+ // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);
+ var props = item.getAttribute('properties') || '';
+ var propArray = props.length ? props.split(' ') : [];
+ // var manifestProps = manifest[Id].properties;
+ // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];
+
+ var itemref = {
+ 'idref' : idref,
+ 'linear' : item.getAttribute('linear') || '',
+ 'properties' : propArray,
+ // 'href' : manifest[Id].href,
+ // 'url' : manifest[Id].url,
+ 'index' : index
+ // 'cfiBase' : cfiBase
+ };
+ spine.push(itemref);
+ });
+
+ return spine;
+ };
+
+ /**
+ * Find TOC NAV
+ * @private
+ */
+ findNavPath(manifestNode){
+ // Find item with property 'nav'
+ // Should catch nav irregardless of order
+ // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']");
+ var node = qsp(manifestNode, "item", {"properties":"nav"});
+ return node ? node.getAttribute('href') : false;
+ };
+
+ /**
+ * Find TOC NCX
+ * media-type="application/x-dtbncx+xml" href="toc.ncx"
+ * @private
+ */
+ findNcxPath(manifestNode, spineNode){
+ // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
+ var node = qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"});
+ 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
+ // according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,
+ // "The item that describes the NCX must be referenced by the spine toc attribute."
+ if (!node) {
+ tocId = spineNode.getAttribute("toc");
+ if(tocId) {
+ // node = manifestNode.querySelector("item[id='" + tocId + "']");
+ node = manifestNode.getElementById(tocId);
+ }
+ }
+
+ return node ? node.getAttribute('href') : false;
+ };
+
+ /**
+ * Find the Cover Path
+ *
+ * Fallback for Epub 2.0
+ * @param {document} packageXml
+ * @return {string} href
+ */
+ findCoverPath(packageXml){
+ var pkg = qs(packageXml, "package");
+ var epubVersion = pkg.getAttribute('version');
+
+ if (epubVersion === '2.0') {
+ var metaCover = qsp(packageXml, 'meta', {'name':'cover'});
+ if (metaCover) {
+ var coverId = metaCover.getAttribute('content');
+ // var cover = packageXml.querySelector("item[id='" + coverId + "']");
+ var cover = packageXml.getElementById(coverId);
+ return cover ? cover.getAttribute('href') : '';
+ }
+ else {
+ return false;
+ }
}
else {
- return false;
+ // var node = packageXml.querySelector("item[properties='cover-image']");
+ var node = qsp(packageXml, 'item', {'properties':'cover-image'});
+ return node ? node.getAttribute('href') : '';
}
- }
- else {
- // var node = packageXml.querySelector("item[properties='cover-image']");
- var node = core.qsp(packageXml, 'item', {'properties':'cover-image'});
- return node ? node.getAttribute('href') : '';
- }
-};
+ };
-/**
- * Get text of a namespaced element
- * @private
- * @param {document} xml
- * @param {string} tag
- * @return {string} text
- */
-Packaging.prototype.getElementText = function(xml, tag){
- var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag),
- el;
+ /**
+ * Get text of a namespaced element
+ * @private
+ * @param {document} xml
+ * @param {string} tag
+ * @return {string} text
+ */
+ getElementText(xml, tag){
+ var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag),
+ el;
- if(!found || found.length === 0) return '';
+ if(!found || found.length === 0) return '';
- el = found[0];
+ el = found[0];
- if(el.childNodes.length){
- return el.childNodes[0].nodeValue;
- }
+ if(el.childNodes.length){
+ return el.childNodes[0].nodeValue;
+ }
- return '';
+ return '';
-};
+ };
-/**
- * Get text by property
- * @private
- * @param {document} xml
- * @param {string} property
- * @return {string} text
- */
-Packaging.prototype.getPropertyText = function(xml, property){
- var el = core.qsp(xml, "meta", {"property":property});
+ /**
+ * Get text by property
+ * @private
+ * @param {document} xml
+ * @param {string} property
+ * @return {string} text
+ */
+ getPropertyText(xml, property){
+ var el = qsp(xml, "meta", {"property":property});
- if(el && el.childNodes.length){
- return el.childNodes[0].nodeValue;
- }
+ if(el && el.childNodes.length){
+ return el.childNodes[0].nodeValue;
+ }
- return '';
-};
+ return '';
+ };
+}
-module.exports = Packaging;
+export default Packaging;
diff --git a/src/pagelist.js b/src/pagelist.js
index 4035251..4ad4626 100644
--- a/src/pagelist.js
+++ b/src/pagelist.js
@@ -1,249 +1,257 @@
-var EpubCFI = require('./epubcfi');
-var core = require('./core');
+import EpubCFI from './epubcfi';
+import {
+ qs,
+ qsa,
+ querySelectorByType,
+ indexOfSorted,
+ locationOf
+} from './utils/core';
/**
* Page List Parser
* @param {[document]} xml
*/
-function PageList(xml) {
- this.pages = [];
- this.locations = [];
- this.epubcfi = new EpubCFI();
+class PageList {
+ constructor(xml) {
+ this.pages = [];
+ this.locations = [];
+ this.epubcfi = new EpubCFI();
- if (xml) {
- this.pageList = this.parse(xml);
- }
-
- if(this.pageList && this.pageList.length) {
- this.process(this.pageList);
- }
-};
-
-/**
- * Parse PageList Xml
- * @param {document} xml
- */
-PageList.prototype.parse = function(xml) {
- var html = core.qs(xml, "html");
- // var ncx = core.qs(xml, "ncx");
-
- if(html) {
- this.toc = this.parseNav(xml);
- } else if(ncx){ // Not supported
- // this.toc = this.parseNcx(xml);
- return;
- }
-
-};
-
-/**
- * Parse a Nav PageList
- * @private
- * @param {document} navHtml
- * @return {PageList.item[]} list
- */
-PageList.prototype.parseNav = function(navHtml){
- var navElement = core.querySelectorByType(navHtml, "nav", "page-list");
- var navItems = navElement ? core.qsa(navElement, "li") : [];
- var length = navItems.length;
- var i;
- var toc = {};
- var list = [];
- var item;
-
- if(!navItems || length === 0) return list;
-
- for (i = 0; i < length; ++i) {
- item = this.item(navItems[i]);
- list.push(item);
- }
-
- return list;
-};
-
-/**
- * Page List Item
- * @private
- * @param {object} item
- * @return {object} pageListItem
- */
-PageList.prototype.item = function(item){
- var id = item.getAttribute('id') || false,
- content = core.qs(item, "a"),
- href = content.getAttribute('href') || '',
- text = content.textContent || "",
- page = parseInt(text),
- isCfi = href.indexOf("epubcfi"),
- split,
- packageUrl,
- cfi;
-
- if(isCfi != -1) {
- split = href.split("#");
- packageUrl = split[0];
- cfi = split.length > 1 ? split[1] : false;
- return {
- "cfi" : cfi,
- "href" : href,
- "packageUrl" : packageUrl,
- "page" : page
- };
- } else {
- return {
- "href" : href,
- "page" : page
- };
- }
-};
-
-/**
- * Process pageList items
- * @private
- * @param {array} pageList
- */
-PageList.prototype.process = function(pageList){
- pageList.forEach(function(item){
- this.pages.push(item.page);
- if (item.cfi) {
- this.locations.push(item.cfi);
+ if (xml) {
+ this.pageList = this.parse(xml);
}
- }, this);
- this.firstPage = parseInt(this.pages[0]);
- this.lastPage = parseInt(this.pages[this.pages.length-1]);
- this.totalPages = this.lastPage - this.firstPage;
-};
-
-/**
- * Replace HREFs with CFI
- * TODO: implement getting CFI from Href
- */
-PageList.prototype.addCFIs = function() {
- this.pageList.forEach(function(pg){
- if(!pg.cfi) {
- // epubcfi.generateCfiFromHref(pg.href, book).then(function(cfi){
- // pg.cfi = cfi;
- // pg.packageUrl = book.settings.packageUrl;
- // });
+ if(this.pageList && this.pageList.length) {
+ this.process(this.pageList);
}
- });
+ };
+
+ /**
+ * Parse PageList Xml
+ * @param {document} xml
+ */
+ parse(xml) {
+ var html = qs(xml, "html");
+ // var ncx = qs(xml, "ncx");
+
+ if(html) {
+ this.toc = this.parseNav(xml);
+ } else if(ncx){ // Not supported
+ // this.toc = this.parseNcx(xml);
+ return;
+ }
+
+ };
+
+ /**
+ * Parse a Nav PageList
+ * @private
+ * @param {document} navHtml
+ * @return {PageList.item[]} list
+ */
+ parseNav(navHtml){
+ var navElement = querySelectorByType(navHtml, "nav", "page-list");
+ var navItems = navElement ? qsa(navElement, "li") : [];
+ var length = navItems.length;
+ var i;
+ var toc = {};
+ var list = [];
+ var item;
+
+ if(!navItems || length === 0) return list;
+
+ for (i = 0; i < length; ++i) {
+ item = this.item(navItems[i]);
+ list.push(item);
+ }
+
+ return list;
+ };
+
+ /**
+ * Page List Item
+ * @private
+ * @param {object} item
+ * @return {object} pageListItem
+ */
+ item(item){
+ var id = item.getAttribute('id') || false,
+ content = qs(item, "a"),
+ href = content.getAttribute('href') || '',
+ text = content.textContent || "",
+ page = parseInt(text),
+ isCfi = href.indexOf("epubcfi"),
+ split,
+ packageUrl,
+ cfi;
+
+ if(isCfi != -1) {
+ split = href.split("#");
+ packageUrl = split[0];
+ cfi = split.length > 1 ? split[1] : false;
+ return {
+ "cfi" : cfi,
+ "href" : href,
+ "packageUrl" : packageUrl,
+ "page" : page
+ };
+ } else {
+ return {
+ "href" : href,
+ "page" : page
+ };
+ }
+ };
+
+ /**
+ * Process pageList items
+ * @private
+ * @param {array} pageList
+ */
+ process(pageList){
+ pageList.forEach(function(item){
+ this.pages.push(item.page);
+ if (item.cfi) {
+ this.locations.push(item.cfi);
+ }
+ }, this);
+ this.firstPage = parseInt(this.pages[0]);
+ this.lastPage = parseInt(this.pages[this.pages.length-1]);
+ this.totalPages = this.lastPage - this.firstPage;
+ };
+
+
+ /**
+ * Replace HREFs with CFI
+ * TODO: implement getting CFI from Href
+ */
+ addCFIs() {
+ this.pageList.forEach(function(pg){
+ if(!pg.cfi) {
+ // epubcfi.generateCfiFromHref(pg.href, book).then(function(cfi){
+ // pg.cfi = cfi;
+ // pg.packageUrl = book.settings.packageUrl;
+ // });
+ }
+ });
+ }
+
+ /*
+ EPUBJS.generateCfiFromHref(href, book) {
+ var uri = EPUBJS.core.uri(href);
+ var path = uri.path;
+ var fragment = uri.fragment;
+ var spinePos = book.spineIndexByURL[path];
+ var loaded;
+ var deferred = new RSVP.defer();
+ var epubcfi = new EPUBJS.EpubCFI();
+ var spineItem;
+
+ if(typeof spinePos !== "undefined"){
+ spineItem = book.spine[spinePos];
+ loaded = book.loadXml(spineItem.url);
+ loaded.then(function(doc){
+ var element = doc.getElementById(fragment);
+ var cfi;
+ cfi = epubcfi.generateCfiFromElement(element, spineItem.cfiBase);
+ deferred.resolve(cfi);
+ });
+ }
+
+ return deferred.promise;
+ };
+ */
+
+ /**
+ * Get a PageList result from a EpubCFI
+ * @param {string} cfi EpubCFI String
+ * @return {string} page
+ */
+ pageFromCfi(cfi){
+ var pg = -1;
+
+ // Check if the pageList has not been set yet
+ if(this.locations.length === 0) {
+ return -1;
+ }
+
+ // TODO: check if CFI is valid?
+
+ // check if the cfi is in the location list
+ // var index = this.locations.indexOf(cfi);
+ var index = indexOfSorted(cfi, this.locations, this.epubcfi.compare);
+ if(index != -1) {
+ pg = this.pages[index];
+ } else {
+ // Otherwise add it to the list of locations
+ // Insert it in the correct position in the locations page
+ //index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
+ index = locationOf(cfi, this.locations, this.epubcfi.compare);
+ // Get the page at the location just before the new one, or return the first
+ pg = index-1 >= 0 ? this.pages[index-1] : this.pages[0];
+ if(pg !== undefined) {
+ // Add the new page in so that the locations and page array match up
+ //this.pages.splice(index, 0, pg);
+ } else {
+ pg = -1;
+ }
+
+ }
+ return pg;
+ };
+
+ /**
+ * Get an EpubCFI from a Page List Item
+ * @param {string} pg
+ * @return {string} cfi
+ */
+ cfiFromPage(pg){
+ var cfi = -1;
+ // check that pg is an int
+ if(typeof pg != "number"){
+ pg = parseInt(pg);
+ }
+
+ // check if the cfi is in the page list
+ // Pages could be unsorted.
+ var index = this.pages.indexOf(pg);
+ if(index != -1) {
+ cfi = this.locations[index];
+ }
+ // TODO: handle pages not in the list
+ return cfi;
+ };
+
+ /**
+ * Get a Page from Book percentage
+ * @param {number} percent
+ * @return {string} page
+ */
+ pageFromPercentage(percent){
+ var pg = Math.round(this.totalPages * percent);
+ return pg;
+ };
+
+ /**
+ * Returns a value between 0 - 1 corresponding to the location of a page
+ * @param {int} pg the page
+ * @return {number} percentage
+ */
+ percentageFromPage(pg){
+ var percentage = (pg - this.firstPage) / this.totalPages;
+ return Math.round(percentage * 1000) / 1000;
+ };
+
+ /**
+ * Returns a value between 0 - 1 corresponding to the location of a cfi
+ * @param {string} cfi EpubCFI String
+ * @return {number} percentage
+ */
+ percentageFromCfi(cfi){
+ var pg = this.pageFromCfi(cfi);
+ var percentage = this.percentageFromPage(pg);
+ return percentage;
+ };
}
-/*
-EPUBJS.EpubCFI.prototype.generateCfiFromHref = function(href, book) {
- var uri = EPUBJS.core.uri(href);
- var path = uri.path;
- var fragment = uri.fragment;
- var spinePos = book.spineIndexByURL[path];
- var loaded;
- var deferred = new RSVP.defer();
- var epubcfi = new EPUBJS.EpubCFI();
- var spineItem;
-
- if(typeof spinePos !== "undefined"){
- spineItem = book.spine[spinePos];
- loaded = book.loadXml(spineItem.url);
- loaded.then(function(doc){
- var element = doc.getElementById(fragment);
- var cfi;
- cfi = epubcfi.generateCfiFromElement(element, spineItem.cfiBase);
- deferred.resolve(cfi);
- });
- }
-
- return deferred.promise;
-};
-*/
-
-/**
- * Get a PageList result from a EpubCFI
- * @param {string} cfi EpubCFI String
- * @return {string} page
- */
-PageList.prototype.pageFromCfi = function(cfi){
- var pg = -1;
-
- // Check if the pageList has not been set yet
- if(this.locations.length === 0) {
- return -1;
- }
-
- // TODO: check if CFI is valid?
-
- // check if the cfi is in the location list
- // var index = this.locations.indexOf(cfi);
- var index = core.indexOfSorted(cfi, this.locations, this.epubcfi.compare);
- if(index != -1) {
- pg = this.pages[index];
- } else {
- // Otherwise add it to the list of locations
- // Insert it in the correct position in the locations page
- //index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
- index = EPUBJS.core.locationOf(cfi, this.locations, this.epubcfi.compare);
- // Get the page at the location just before the new one, or return the first
- pg = index-1 >= 0 ? this.pages[index-1] : this.pages[0];
- if(pg !== undefined) {
- // Add the new page in so that the locations and page array match up
- //this.pages.splice(index, 0, pg);
- } else {
- pg = -1;
- }
-
- }
- return pg;
-};
-
-/**
- * Get an EpubCFI from a Page List Item
- * @param {string} pg
- * @return {string} cfi
- */
-PageList.prototype.cfiFromPage = function(pg){
- var cfi = -1;
- // check that pg is an int
- if(typeof pg != "number"){
- pg = parseInt(pg);
- }
-
- // check if the cfi is in the page list
- // Pages could be unsorted.
- var index = this.pages.indexOf(pg);
- if(index != -1) {
- cfi = this.locations[index];
- }
- // TODO: handle pages not in the list
- return cfi;
-};
-
-/**
- * Get a Page from Book percentage
- * @param {number} percent
- * @return {string} page
- */
-PageList.prototype.pageFromPercentage = function(percent){
- var pg = Math.round(this.totalPages * percent);
- return pg;
-};
-
-/**
- * Returns a value between 0 - 1 corresponding to the location of a page
- * @param {int} pg the page
- * @return {number} percentage
- */
-PageList.prototype.percentageFromPage = function(pg){
- var percentage = (pg - this.firstPage) / this.totalPages;
- return Math.round(percentage * 1000) / 1000;
-};
-
-/**
- * Returns a value between 0 - 1 corresponding to the location of a cfi
- * @param {string} cfi EpubCFI String
- * @return {number} percentage
- */
-PageList.prototype.percentageFromCfi = function(cfi){
- var pg = this.pageFromCfi(cfi);
- var percentage = this.percentageFromPage(pg);
- return percentage;
-};
-
-module.exports = PageList;
+export default PageList;
diff --git a/src/queue.js b/src/queue.js
index 3015a53..c3e3272 100644
--- a/src/queue.js
+++ b/src/queue.js
@@ -1,198 +1,201 @@
-var core = require('./core');
+import {defer, requestAnimationFrame} from './utils/core';
/**
* Queue for handling tasks one at a time
* @class
* @param {scope} context what this will resolve to in the tasks
*/
-function Queue(context){
- this._q = [];
- this.context = context;
- this.tick = core.requestAnimationFrame;
- this.running = false;
- this.paused = false;
-};
+class Queue {
+ constructor(context){
+ this._q = [];
+ this.context = context;
+ this.tick = requestAnimationFrame;
+ this.running = false;
+ this.paused = false;
+ };
-/**
- * Add an item to the queue
- * @return {Promise}
- */
-Queue.prototype.enqueue = function() {
- var deferred, promise;
- var queued;
- var task = [].shift.call(arguments);
- var args = arguments;
+ /**
+ * Add an item to the queue
+ * @return {Promise}
+ */
+ enqueue() {
+ var deferred, promise;
+ var queued;
+ var task = [].shift.call(arguments);
+ var args = arguments;
- // Handle single args without context
- // if(args && !Array.isArray(args)) {
- // args = [args];
- // }
- if(!task) {
- return console.error("No Task Provided");
- }
+ // Handle single args without context
+ // if(args && !Array.isArray(args)) {
+ // args = [args];
+ // }
+ if(!task) {
+ return console.error("No Task Provided");
+ }
- if(typeof task === "function"){
+ if(typeof task === "function"){
- deferred = new core.defer();
- promise = deferred.promise;
+ deferred = new defer();
+ promise = deferred.promise;
- queued = {
- "task" : task,
- "args" : args,
- //"context" : context,
- "deferred" : deferred,
- "promise" : promise
- };
+ queued = {
+ "task" : task,
+ "args" : args,
+ //"context" : context,
+ "deferred" : deferred,
+ "promise" : promise
+ };
- } else {
- // Task is a promise
- queued = {
- "promise" : task
- };
+ } else {
+ // Task is a promise
+ queued = {
+ "promise" : task
+ };
- }
+ }
- this._q.push(queued);
+ this._q.push(queued);
- // Wait to start queue flush
- if (this.paused == false && !this.running) {
- // setTimeout(this.flush.bind(this), 0);
- // this.tick.call(window, this.run.bind(this));
- this.run();
- }
+ // Wait to start queue flush
+ if (this.paused == false && !this.running) {
+ // setTimeout(this.flush.bind(this), 0);
+ // this.tick.call(window, this.run.bind(this));
+ this.run();
+ }
- return queued.promise;
-};
+ return queued.promise;
+ };
-/**
- * Run one item
- * @return {Promise}
- */
-Queue.prototype.dequeue = function(){
- var inwait, task, result;
+ /**
+ * Run one item
+ * @return {Promise}
+ */
+ dequeue(){
+ var inwait, task, result;
- if(this._q.length) {
- inwait = this._q.shift();
- task = inwait.task;
- if(task){
- // console.log(task)
+ if(this._q.length) {
+ inwait = this._q.shift();
+ task = inwait.task;
+ if(task){
+ // console.log(task)
- result = task.apply(this.context, inwait.args);
+ result = task.apply(this.context, inwait.args);
- if(result && typeof result["then"] === "function") {
- // Task is a function that returns a promise
- return result.then(function(){
- inwait.deferred.resolve.apply(this.context, arguments);
- }, function(reason) {
- inwait.deferred.reject.apply(this.context, arguments);
- }.bind(this));
- } else {
- // Task resolves immediately
- inwait.deferred.resolve.apply(this.context, result);
+ if(result && typeof result["then"] === "function") {
+ // Task is a function that returns a promise
+ return result.then(function(){
+ inwait.deferred.resolve.apply(this.context, arguments);
+ }.bind(this), function(reason) {
+ inwait.deferred.reject.apply(this.context, arguments);
+ }.bind(this));
+ } else {
+ // Task resolves immediately
+ inwait.deferred.resolve.apply(this.context, result);
+ return inwait.promise;
+ }
+
+
+
+ } else if(inwait.promise) {
+ // Task is a promise
return inwait.promise;
}
-
-
- } else if(inwait.promise) {
- // Task is a promise
+ } else {
+ inwait = new defer();
+ inwait.deferred.resolve();
return inwait.promise;
}
- } else {
- inwait = new core.defer();
- inwait.deferred.resolve();
- return inwait.promise;
- }
+ };
-};
+ // Run All Immediately
+ dump(){
+ while(this._q.length) {
+ this.dequeue();
+ }
+ };
-// Run All Immediately
-Queue.prototype.dump = function(){
- while(this._q.length) {
- this.dequeue();
- }
-};
+ /**
+ * Run all tasks sequentially, at convince
+ * @return {Promise}
+ */
+ run(){
-/**
- * Run all tasks sequentially, at convince
- * @return {Promise}
- */
-Queue.prototype.run = function(){
-
- if(!this.running){
- this.running = true;
- this.defered = new core.defer();
- }
-
- this.tick.call(window, function() {
-
- if(this._q.length) {
-
- this.dequeue()
- .then(function(){
- this.run();
- }.bind(this));
-
- } else {
- this.defered.resolve();
- this.running = undefined;
+ if(!this.running){
+ this.running = true;
+ this.defered = new defer();
}
- }.bind(this));
+ this.tick.call(window, function() {
- // Unpause
- if(this.paused == true) {
- this.paused = false;
- }
+ if(this._q.length) {
- return this.defered.promise;
-};
+ this.dequeue()
+ .then(function(){
+ this.run();
+ }.bind(this));
-/**
- * Flush all, as quickly as possible
- * @return {Promise}
- */
-Queue.prototype.flush = function(){
-
- if(this.running){
- return this.running;
- }
-
- if(this._q.length) {
- this.running = this.dequeue()
- .then(function(){
+ } else {
+ this.defered.resolve();
this.running = undefined;
- return this.flush();
- }.bind(this));
+ }
- return this.running;
- }
+ }.bind(this));
-};
+ // Unpause
+ if(this.paused == true) {
+ this.paused = false;
+ }
-/**
- * Clear all items in wait
- */
-Queue.prototype.clear = function(){
- this._q = [];
- this.running = false;
-};
+ return this.defered.promise;
+ };
-/**
- * Get the number of tasks in the queue
- * @return {int} tasks
- */
-Queue.prototype.length = function(){
- return this._q.length;
-};
+ /**
+ * Flush all, as quickly as possible
+ * @return {Promise}
+ */
+ flush(){
+
+ if(this.running){
+ return this.running;
+ }
+
+ if(this._q.length) {
+ this.running = this.dequeue()
+ .then(function(){
+ this.running = undefined;
+ return this.flush();
+ }.bind(this));
+
+ return this.running;
+ }
+
+ };
+
+ /**
+ * Clear all items in wait
+ */
+ clear(){
+ this._q = [];
+ this.running = false;
+ };
+
+ /**
+ * Get the number of tasks in the queue
+ * @return {int} tasks
+ */
+ length(){
+ return this._q.length;
+ };
+
+ /**
+ * Pause a running queue
+ */
+ pause(){
+ this.paused = true;
+ };
+}
-/**
- * Pause a running queue
- */
-Queue.prototype.pause = function(){
- this.paused = true;
-};
/**
* Create a new task from a callback
@@ -203,25 +206,28 @@ Queue.prototype.pause = function(){
* @param {scope} context
* @return {function} task
*/
-function Task(task, args, context){
+class Task {
+ constructor(task, args, context){
- return function(){
- var toApply = arguments || [];
+ return function(){
+ var toApply = arguments || [];
- return new Promise(function(resolve, reject) {
- var callback = function(value){
- resolve(value);
- };
- // Add the callback to the arguments list
- toApply.push(callback);
+ return new Promise(function(resolve, reject) {
+ var callback = function(value){
+ resolve(value);
+ };
+ // Add the callback to the arguments list
+ toApply.push(callback);
- // Apply all arguments to the functions
- task.apply(this, toApply);
+ // Apply all arguments to the functions
+ task.apply(this, toApply);
- }.bind(this));
+ }.bind(this));
+
+ };
};
+}
-};
-module.exports = Queue;
+export default Queue;
diff --git a/src/rendition.js b/src/rendition.js
index acd205e..75ff7cd 100644
--- a/src/rendition.js
+++ b/src/rendition.js
@@ -1,14 +1,13 @@
-var EventEmitter = require('event-emitter');
-var path = require('path');
-var core = require('./core');
-var replace = require('./replacements');
-var Hook = require('./hook');
-var EpubCFI = require('./epubcfi');
-var Queue = require('./queue');
-var Layout = require('./layout');
-var Mapping = require('./mapping');
-var Themes = require('./themes');
-var Path = require('./core').Path;
+import EventEmitter from 'event-emitter';
+import { extend, defer, isFloat } from './utils/core';
+import {replaceLinks} from './replacements';
+import Hook from './hook';
+import EpubCFI from './epubcfi';
+import Queue from './queue';
+import Layout from './layout';
+import Mapping from './mapping';
+import Themes from './themes';
+import Path from './utils/path';
/**
* [Rendition description]
@@ -24,576 +23,578 @@ var Path = require('./core').Path;
* @param {string} options.spread
* @param {int} options.minSpreadWidth overridden by spread: none (never) / both (always)
*/
-function Rendition(book, options) {
+class Rendition {
+ constructor(book, options) {
- this.settings = core.extend(this.settings || {}, {
- width: null,
- height: null,
- ignoreClass: '',
- manager: "default",
- view: "iframe",
- flow: null,
- layout: null,
- spread: null,
- minSpreadWidth: 800
- });
-
- core.extend(this.settings, options);
-
- if (typeof(this.settings.manager) === "object") {
- this.manager = this.settings.manager;
- }
-
- this.viewSettings = {
- ignoreClass: this.settings.ignoreClass
- };
-
- this.book = book;
-
- this.views = null;
-
- /**
- * Adds Hook methods to the Rendition prototype
- * @property {Hook} hooks
- */
- this.hooks = {};
- this.hooks.display = new Hook(this);
- this.hooks.serialize = new Hook(this);
- /**
- * @property {method} hooks.content
- * @type {Hook}
- */
- this.hooks.content = new Hook(this);
- this.hooks.layout = new Hook(this);
- this.hooks.render = new Hook(this);
- this.hooks.show = new Hook(this);
-
- this.hooks.content.register(replace.links.bind(this));
- this.hooks.content.register(this.passViewEvents.bind(this));
-
- // this.hooks.display.register(this.afterDisplay.bind(this));
- this.themes = new Themes(this);
-
- this.epubcfi = new EpubCFI();
-
- this.q = new Queue(this);
-
- this.q.enqueue(this.book.opened);
-
- // Block the queue until rendering is started
- this.starting = new core.defer();
- this.started = this.starting.promise;
- this.q.enqueue(this.start);
-};
-
-/**
- * Set the manager function
- * @param {function} manager
- */
-Rendition.prototype.setManager = function(manager) {
- this.manager = manager;
-};
-
-/**
- * Require the manager from passed string, or as a function
- * @param {string|function} manager [description]
- * @return {method}
- */
-Rendition.prototype.requireManager = function(manager) {
- var viewManager;
-
- // If manager is a string, try to load from register managers,
- // or require included managers directly
- if (typeof manager === "string") {
- // Use global or require
- viewManager = typeof ePub != "undefined" ? ePub.ViewManagers[manager] : undefined; //require('./managers/'+manager);
- } else {
- // otherwise, assume we were passed a function
- viewManager = manager
- }
-
- return viewManager;
-};
-
-/**
- * Require the view from passed string, or as a function
- * @param {string|function} view
- * @return {view}
- */
-Rendition.prototype.requireView = function(view) {
- var View;
-
- if (typeof view == "string") {
- View = typeof ePub != "undefined" ? ePub.Views[view] : undefined; //require('./views/'+view);
- } else {
- // otherwise, assume we were passed a function
- View = view
- }
-
- return View;
-};
-
-/**
- * Start the rendering
- * @return {Promise} rendering has started
- */
-Rendition.prototype.start = function(){
-
- if(!this.manager) {
- this.ViewManager = this.requireManager(this.settings.manager);
- this.View = this.requireView(this.settings.view);
-
- this.manager = new this.ViewManager({
- view: this.View,
- queue: this.q,
- request: this.book.load.bind(this.book),
- settings: this.settings
- });
- }
-
- // Parse metadata to get layout props
- this.settings.globalLayoutProperties = this.determineLayoutProperties(this.book.package.metadata);
-
- this.flow(this.settings.globalLayoutProperties.flow);
-
- this.layout(this.settings.globalLayoutProperties);
-
- // Listen for displayed views
- this.manager.on("added", this.afterDisplayed.bind(this));
-
- // Listen for resizing
- this.manager.on("resized", this.onResized.bind(this));
-
- // Listen for scroll changes
- this.manager.on("scroll", this.reportLocation.bind(this));
-
-
- this.on('displayed', this.reportLocation.bind(this));
-
- // Trigger that rendering has started
- this.emit("started");
-
- // Start processing queue
- this.starting.resolve();
-};
-
-/**
- * Call to attach the container to an element in the dom
- * Container must be attached before rendering can begin
- * @param {element} element to attach to
- * @return {Promise}
- */
-Rendition.prototype.attachTo = function(element){
-
- return this.q.enqueue(function () {
-
- // Start rendering
- this.manager.render(element, {
- "width" : this.settings.width,
- "height" : this.settings.height
+ this.settings = extend(this.settings || {}, {
+ width: null,
+ height: null,
+ ignoreClass: '',
+ manager: "default",
+ view: "iframe",
+ flow: null,
+ layout: null,
+ spread: null,
+ minSpreadWidth: 800
});
- // Trigger Attached
- this.emit("attached");
+ extend(this.settings, options);
- }.bind(this));
+ if (typeof(this.settings.manager) === "object") {
+ this.manager = this.settings.manager;
+ }
-};
+ this.viewSettings = {
+ ignoreClass: this.settings.ignoreClass
+ };
-/**
- * Display a point in the book
- * The request will be added to the rendering Queue,
- * so it will wait until book is opened, rendering started
- * and all other rendering tasks have finished to be called.
- * @param {string} target Url or EpubCFI
- * @return {Promise}
- */
-Rendition.prototype.display = function(target){
+ this.book = book;
- return this.q.enqueue(this._display, target);
+ this.views = null;
-};
+ /**
+ * Adds Hook methods to the Rendition prototype
+ * @property {Hook} hooks
+ */
+ this.hooks = {};
+ this.hooks.display = new Hook(this);
+ this.hooks.serialize = new Hook(this);
+ /**
+ * @property {method} hooks.content
+ * @type {Hook}
+ */
+ this.hooks.content = new Hook(this);
+ this.hooks.layout = new Hook(this);
+ this.hooks.render = new Hook(this);
+ this.hooks.show = new Hook(this);
-/**
- * Tells the manager what to display immediately
- * @private
- * @param {string} target Url or EpubCFI
- * @return {Promise}
- */
-Rendition.prototype._display = function(target){
- var isCfiString = this.epubcfi.isCfiString(target);
- var displaying = new core.defer();
- var displayed = displaying.promise;
- var section;
- var moveTo;
+ this.hooks.content.register(replaceLinks.bind(this));
+ this.hooks.content.register(this.passViewEvents.bind(this));
- // Check if this is a book percentage
- if (this.book.locations.length && core.isFloat(target)) {
- console.log("percentage", target);
- target = book.locations.cfiFromPercentage(target);
- console.log("cfi", target);
- }
+ // this.hooks.display.register(this.afterDisplay.bind(this));
+ this.themes = new Themes(this);
- section = this.book.spine.get(target);
+ this.epubcfi = new EpubCFI();
- if(!section){
- displaying.reject(new Error("No Section Found"));
- return displayed;
- }
+ this.q = new Queue(this);
- // Trim the target fragment
- // removing the chapter
- if(!isCfiString && typeof target === "string" &&
- target.indexOf("#") > -1) {
- moveTo = target.substring(target.indexOf("#")+1);
- }
+ this.q.enqueue(this.book.opened);
- if (isCfiString) {
- moveTo = target;
- }
-
- return this.manager.display(section, moveTo)
- .then(function(){
- // this.emit("displayed", section);
- }.bind(this));
-
-};
-
-/*
-Rendition.prototype.render = function(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 has been displayed
- * @private
- * @param {*} view
- */
-Rendition.prototype.afterDisplayed = function(view){
- this.hooks.content.trigger(view, this);
- this.emit("rendered", view.section);
- this.reportLocation();
-};
-
-/**
- * Report resize events and display the last seen location
- * @private
- */
-Rendition.prototype.onResized = function(size){
-
- if(this.location) {
- this.display(this.location.start);
- }
-
- this.emit("resized", {
- width: size.width,
- height: size.height
- });
-
-};
-
-/**
- * Move the Rendition to a specific offset
- * Usually you would be better off calling display()
- * @param {object} offset
- */
-Rendition.prototype.moveTo = function(offset){
- this.manager.moveTo(offset);
-};
-
-/**
- * Go to the next "page" in the rendition
- * @return {Promise}
- */
-Rendition.prototype.next = function(){
- return this.q.enqueue(this.manager.next.bind(this.manager))
- .then(this.reportLocation.bind(this));
-};
-
-/**
- * Go to the previous "page" in the rendition
- * @return {Promise}
- */
-Rendition.prototype.prev = function(){
- return this.q.enqueue(this.manager.prev.bind(this.manager))
- .then(this.reportLocation.bind(this));
-};
-
-//-- http://www.idpf.org/epub/301/spec/epub-publications.html#meta-properties-rendering
-/**
- * Determine the Layout properties from metadata and settings
- * @private
- * @param {object} metadata
- * @return {object} properties
- */
-Rendition.prototype.determineLayoutProperties = function(metadata){
- var properties;
- var layout = this.settings.layout || metadata.layout || "reflowable";
- var spread = this.settings.spread || metadata.spread || "auto";
- var orientation = this.settings.orientation || metadata.orientation || "auto";
- var flow = this.settings.flow || metadata.flow || "auto";
- var viewport = metadata.viewport || "";
- var minSpreadWidth = this.settings.minSpreadWidth || metadata.minSpreadWidth || 800;
-
- if (this.settings.width >= 0 && this.settings.height >= 0) {
- viewport = "width="+this.settings.width+", height="+this.settings.height+"";
- }
-
- properties = {
- layout : layout,
- spread : spread,
- orientation : orientation,
- flow : flow,
- viewport : viewport,
- minSpreadWidth : minSpreadWidth
+ // Block the queue until rendering is started
+ this.starting = new defer();
+ this.started = this.starting.promise;
+ this.q.enqueue(this.start);
};
- return properties;
-};
+ /**
+ * Set the manager function
+ * @param {function} manager
+ */
+ setManager(manager) {
+ this.manager = manager;
+ };
-// Rendition.prototype.applyLayoutProperties = function(){
-// var settings = this.determineLayoutProperties(this.book.package.metadata);
-//
-// this.flow(settings.flow);
-//
-// this.layout(settings);
-// };
+ /**
+ * Require the manager from passed string, or as a function
+ * @param {string|function} manager [description]
+ * @return {method}
+ */
+ requireManager(manager) {
+ var viewManager;
-/**
- * Adjust the flow of the rendition to paginated or scrolled
- * (scrolled-continuous vs scrolled-doc are handled by different view managers)
- * @param {string} flow
- */
-Rendition.prototype.flow = function(flow){
- var _flow;
- if (flow === "scrolled-doc" || flow === "scrolled-continuous") {
- _flow = "scrolled";
- }
+ // If manager is a string, try to load from register managers,
+ // or require included managers directly
+ if (typeof manager === "string") {
+ // Use global or require
+ viewManager = typeof ePub != "undefined" ? ePub.ViewManagers[manager] : undefined; //require('./managers/'+manager);
+ } else {
+ // otherwise, assume we were passed a function
+ viewManager = manager
+ }
- if (flow === "auto" || flow === "paginated") {
- _flow = "paginated";
- }
+ return viewManager;
+ };
- if (this._layout) {
- this._layout.flow(_flow);
- }
+ /**
+ * Require the view from passed string, or as a function
+ * @param {string|function} view
+ * @return {view}
+ */
+ requireView(view) {
+ var View;
- if (this.manager) {
- this.manager.updateFlow(_flow);
- }
-};
+ if (typeof view == "string") {
+ View = typeof ePub != "undefined" ? ePub.Views[view] : undefined; //require('./views/'+view);
+ } else {
+ // otherwise, assume we were passed a function
+ View = view
+ }
-/**
- * Adjust the layout of the rendition to reflowable or pre-paginated
- * @param {object} settings
- */
-Rendition.prototype.layout = function(settings){
- if (settings) {
- this._layout = new Layout(settings);
- this._layout.spread(settings.spread, this.settings.minSpreadWidth);
+ return View;
+ };
- this.mapping = new Mapping(this._layout);
- }
+ /**
+ * Start the rendering
+ * @return {Promise} rendering has started
+ */
+ start(){
- if (this.manager && this._layout) {
- this.manager.applyLayout(this._layout);
- }
+ if(!this.manager) {
+ this.ViewManager = this.requireManager(this.settings.manager);
+ this.View = this.requireView(this.settings.view);
- return this._layout;
-};
+ this.manager = new this.ViewManager({
+ view: this.View,
+ queue: this.q,
+ request: this.book.load.bind(this.book),
+ settings: this.settings
+ });
+ }
-/**
- * Adjust if the rendition uses spreads
- * @param {string} spread none | auto (TODO: implement landscape, portrait, both)
- * @param {int} min min width to use spreads at
- */
-Rendition.prototype.spread = function(spread, min){
+ // Parse metadata to get layout props
+ this.settings.globalLayoutProperties = this.determineLayoutProperties(this.book.package.metadata);
- this._layout.spread(spread, min);
+ this.flow(this.settings.globalLayoutProperties.flow);
- if (this.manager.isRendered()) {
- this.manager.updateLayout();
- }
-};
+ this.layout(this.settings.globalLayoutProperties);
-/**
- * Report the current location
- * @private
- */
-Rendition.prototype.reportLocation = function(){
- return this.q.enqueue(function(){
- var location = this.manager.currentLocation();
- if (location && location.then && typeof location.then === 'function') {
- location.then(function(result) {
- this.location = result;
+ // Listen for displayed views
+ this.manager.on("added", this.afterDisplayed.bind(this));
- this.percentage = this.book.locations.percentageFromCfi(result);
+ // Listen for resizing
+ this.manager.on("resized", this.onResized.bind(this));
+
+ // Listen for scroll changes
+ this.manager.on("scroll", this.reportLocation.bind(this));
+
+
+ this.on('displayed', this.reportLocation.bind(this));
+
+ // Trigger that rendering has started
+ this.emit("started");
+
+ // Start processing queue
+ this.starting.resolve();
+ };
+
+ /**
+ * Call to attach the container to an element in the dom
+ * Container must be attached before rendering can begin
+ * @param {element} element to attach to
+ * @return {Promise}
+ */
+ attachTo(element){
+
+ return this.q.enqueue(function () {
+
+ // Start rendering
+ this.manager.render(element, {
+ "width" : this.settings.width,
+ "height" : this.settings.height
+ });
+
+ // Trigger Attached
+ this.emit("attached");
+
+ }.bind(this));
+
+ };
+
+ /**
+ * Display a point in the book
+ * The request will be added to the rendering Queue,
+ * so it will wait until book is opened, rendering started
+ * and all other rendering tasks have finished to be called.
+ * @param {string} target Url or EpubCFI
+ * @return {Promise}
+ */
+ display(target){
+
+ return this.q.enqueue(this._display, target);
+
+ };
+
+ /**
+ * Tells the manager what to display immediately
+ * @private
+ * @param {string} target Url or EpubCFI
+ * @return {Promise}
+ */
+ _display(target){
+ var isCfiString = this.epubcfi.isCfiString(target);
+ var displaying = new defer();
+ var displayed = displaying.promise;
+ var section;
+ var moveTo;
+
+ // Check if this is a book percentage
+ if (this.book.locations.length && isFloat(target)) {
+ console.log("percentage", target);
+ target = book.locations.cfiFromPercentage(target);
+ console.log("cfi", target);
+ }
+
+ section = this.book.spine.get(target);
+
+ if(!section){
+ displaying.reject(new Error("No Section Found"));
+ return displayed;
+ }
+
+ // Trim the target fragment
+ // removing the chapter
+ if(!isCfiString && typeof target === "string" &&
+ target.indexOf("#") > -1) {
+ moveTo = target.substring(target.indexOf("#")+1);
+ }
+
+ if (isCfiString) {
+ moveTo = target;
+ }
+
+ return this.manager.display(section, moveTo)
+ .then(function(){
+ // this.emit("displayed", section);
+ }.bind(this));
+
+ };
+
+ /*
+ 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 has been displayed
+ * @private
+ * @param {*} view
+ */
+ afterDisplayed(view){
+ this.hooks.content.trigger(view, this);
+ this.emit("rendered", view.section);
+ this.reportLocation();
+ };
+
+ /**
+ * Report resize events and display the last seen location
+ * @private
+ */
+ onResized(size){
+
+ if(this.location) {
+ this.display(this.location.start);
+ }
+
+ this.emit("resized", {
+ width: size.width,
+ height: size.height
+ });
+
+ };
+
+ /**
+ * Move the Rendition to a specific offset
+ * Usually you would be better off calling display()
+ * @param {object} offset
+ */
+ moveTo(offset){
+ this.manager.moveTo(offset);
+ };
+
+ /**
+ * Go to the next "page" in the rendition
+ * @return {Promise}
+ */
+ next(){
+ return this.q.enqueue(this.manager.next.bind(this.manager))
+ .then(this.reportLocation.bind(this));
+ };
+
+ /**
+ * Go to the previous "page" in the rendition
+ * @return {Promise}
+ */
+ prev(){
+ return this.q.enqueue(this.manager.prev.bind(this.manager))
+ .then(this.reportLocation.bind(this));
+ };
+
+ //-- http://www.idpf.org/epub/301/spec/epub-publications.html#meta-properties-rendering
+ /**
+ * Determine the Layout properties from metadata and settings
+ * @private
+ * @param {object} metadata
+ * @return {object} properties
+ */
+ determineLayoutProperties(metadata){
+ var properties;
+ var layout = this.settings.layout || metadata.layout || "reflowable";
+ var spread = this.settings.spread || metadata.spread || "auto";
+ var orientation = this.settings.orientation || metadata.orientation || "auto";
+ var flow = this.settings.flow || metadata.flow || "auto";
+ var viewport = metadata.viewport || "";
+ var minSpreadWidth = this.settings.minSpreadWidth || metadata.minSpreadWidth || 800;
+
+ if (this.settings.width >= 0 && this.settings.height >= 0) {
+ viewport = "width="+this.settings.width+", height="+this.settings.height+"";
+ }
+
+ properties = {
+ layout : layout,
+ spread : spread,
+ orientation : orientation,
+ flow : flow,
+ viewport : viewport,
+ minSpreadWidth : minSpreadWidth
+ };
+
+ return properties;
+ };
+
+ // applyLayoutProperties(){
+ // var settings = this.determineLayoutProperties(this.book.package.metadata);
+ //
+ // this.flow(settings.flow);
+ //
+ // this.layout(settings);
+ // };
+
+ /**
+ * Adjust the flow of the rendition to paginated or scrolled
+ * (scrolled-continuous vs scrolled-doc are handled by different view managers)
+ * @param {string} flow
+ */
+ flow(flow){
+ var _flow = flow;
+ if (flow === "scrolled-doc" || flow === "scrolled-continuous") {
+ _flow = "scrolled";
+ }
+
+ if (flow === "auto" || flow === "paginated") {
+ _flow = "paginated";
+ }
+
+ if (this._layout) {
+ this._layout.flow(_flow);
+ }
+
+ if (this.manager) {
+ this.manager.updateFlow(_flow);
+ }
+ };
+
+ /**
+ * Adjust the layout of the rendition to reflowable or pre-paginated
+ * @param {object} settings
+ */
+ layout(settings){
+ if (settings) {
+ this._layout = new Layout(settings);
+ this._layout.spread(settings.spread, this.settings.minSpreadWidth);
+
+ this.mapping = new Mapping(this._layout);
+ }
+
+ if (this.manager && this._layout) {
+ this.manager.applyLayout(this._layout);
+ }
+
+ return this._layout;
+ };
+
+ /**
+ * Adjust if the rendition uses spreads
+ * @param {string} spread none | auto (TODO: implement landscape, portrait, both)
+ * @param {int} min min width to use spreads at
+ */
+ spread(spread, min){
+
+ this._layout.spread(spread, min);
+
+ if (this.manager.isRendered()) {
+ this.manager.updateLayout();
+ }
+ };
+
+ /**
+ * Report the current location
+ * @private
+ */
+ reportLocation(){
+ return this.q.enqueue(function(){
+ var location = this.manager.currentLocation();
+ if (location && location.then && typeof location.then === 'function') {
+ location.then(function(result) {
+ this.location = result;
+
+ this.percentage = this.book.locations.percentageFromCfi(result);
+ if (this.percentage != null) {
+ this.location.percentage = this.percentage;
+ }
+
+ this.emit("locationChanged", this.location);
+ }.bind(this));
+ } else if (location) {
+ this.location = location;
+ this.percentage = this.book.locations.percentageFromCfi(location);
if (this.percentage != null) {
this.location.percentage = this.percentage;
}
this.emit("locationChanged", this.location);
+ }
+
+ }.bind(this));
+ };
+
+ /**
+ * Get the Current Location CFI
+ * @return {EpubCFI} location (may be a promise)
+ */
+ currentLocation(){
+ var location = this.manager.currentLocation();
+ if (location && location.then && typeof location.then === 'function') {
+ location.then(function(result) {
+ var percentage = this.book.locations.percentageFromCfi(result);
+ if (percentage != null) {
+ result.percentage = percentage;
+ }
+ return result;
}.bind(this));
} else if (location) {
- this.location = location;
- this.percentage = this.book.locations.percentageFromCfi(location);
- if (this.percentage != null) {
- this.location.percentage = this.percentage;
- }
-
- this.emit("locationChanged", this.location);
- }
-
- }.bind(this));
-};
-
-/**
- * Get the Current Location CFI
- * @return {EpubCFI} location (may be a promise)
- */
-Rendition.prototype.currentLocation = function(){
- var location = this.manager.currentLocation();
- if (location && location.then && typeof location.then === 'function') {
- location.then(function(result) {
- var percentage = this.book.locations.percentageFromCfi(result);
+ var percentage = this.book.locations.percentageFromCfi(location);
if (percentage != null) {
- result.percentage = percentage;
+ location.percentage = percentage;
}
- return result;
- }.bind(this));
- } else if (location) {
- var percentage = this.book.locations.percentageFromCfi(location);
- if (percentage != null) {
- location.percentage = percentage;
+ return location;
}
- return location;
- }
-};
+ };
-/**
- * Remove and Clean Up the Rendition
- */
-Rendition.prototype.destroy = function(){
- // Clear the queue
- this.q.clear();
+ /**
+ * Remove and Clean Up the Rendition
+ */
+ destroy(){
+ // Clear the queue
+ this.q.clear();
- this.manager.destroy();
-};
+ this.manager.destroy();
+ };
-/**
- * Pass the events from a view
- * @private
- * @param {View} view
- */
-Rendition.prototype.passViewEvents = function(view){
- view.contents.listenedEvents.forEach(function(e){
- view.on(e, this.triggerViewEvent.bind(this));
- }.bind(this));
+ /**
+ * Pass the events from a view
+ * @private
+ * @param {View} view
+ */
+ passViewEvents(view){
+ view.contents.listenedEvents.forEach(function(e){
+ view.on(e, this.triggerViewEvent.bind(this));
+ }.bind(this));
- view.on("selected", this.triggerSelectedEvent.bind(this));
-};
+ view.on("selected", this.triggerSelectedEvent.bind(this));
+ };
-/**
- * Emit events passed by a view
- * @private
- * @param {event} e
- */
-Rendition.prototype.triggerViewEvent = function(e){
- this.emit(e.type, e);
-};
+ /**
+ * Emit events passed by a view
+ * @private
+ * @param {event} e
+ */
+ triggerViewEvent(e){
+ this.emit(e.type, e);
+ };
-/**
- * Emit a selection event's CFI Range passed from a a view
- * @private
- * @param {EpubCFI} cfirange
- */
-Rendition.prototype.triggerSelectedEvent = function(cfirange){
- this.emit("selected", cfirange);
-};
+ /**
+ * Emit a selection event's CFI Range passed from a a view
+ * @private
+ * @param {EpubCFI} cfirange
+ */
+ triggerSelectedEvent(cfirange){
+ this.emit("selected", cfirange);
+ };
-/**
- * Get a Range from a Visible CFI
- * @param {string} cfi EpubCfi String
- * @param {string} ignoreClass
- * @return {range}
- */
-Rendition.prototype.range = function(cfi, ignoreClass){
- var _cfi = new EpubCFI(cfi);
- var found = this.visible().filter(function (view) {
- if(_cfi.spinePos === view.index) return true;
- });
+ /**
+ * Get a Range from a Visible CFI
+ * @param {string} cfi EpubCfi String
+ * @param {string} ignoreClass
+ * @return {range}
+ */
+ range(cfi, ignoreClass){
+ var _cfi = new EpubCFI(cfi);
+ var found = this.visible().filter(function (view) {
+ if(_cfi.spinePos === view.index) return true;
+ });
- // Should only every return 1 item
- if (found.length) {
- return found[0].range(_cfi, ignoreClass);
- }
-};
+ // Should only every return 1 item
+ if (found.length) {
+ return found[0].range(_cfi, ignoreClass);
+ }
+ };
-/**
- * Hook to adjust images to fit in columns
- * @param {View} view
- */
-Rendition.prototype.adjustImages = function(view) {
+ /**
+ * Hook to adjust images to fit in columns
+ * @param {View} view
+ */
+ adjustImages(view) {
- view.addStylesheetRules([
- ["img",
- ["max-width", (view.layout.spreadWidth) + "px"],
- ["max-height", (view.layout.height) + "px"]
- ]
- ]);
- return new Promise(function(resolve, reject){
- // Wait to apply
- setTimeout(function() {
- resolve();
- }, 1);
- });
-};
+ view.addStylesheetRules([
+ ["img",
+ ["max-width", (view.layout.spreadWidth) + "px"],
+ ["max-height", (view.layout.height) + "px"]
+ ]
+ ]);
+ return new Promise(function(resolve, reject){
+ // Wait to apply
+ setTimeout(function() {
+ resolve();
+ }, 1);
+ });
+ };
-Rendition.prototype.getContents = function () {
- return this.manager ? this.manager.getContents() : [];
-};
+ getContents () {
+ return this.manager ? this.manager.getContents() : [];
+ };
+}
//-- Enable binding events to Renderer
EventEmitter(Rendition.prototype);
-module.exports = Rendition;
+export default Rendition;
diff --git a/src/replacements.js b/src/replacements.js
index 99e7ba4..dc98348 100644
--- a/src/replacements.js
+++ b/src/replacements.js
@@ -1,8 +1,8 @@
-// var URI = require('urijs');
-var core = require('./core');
-var Url = require('./core').Url;
+// import URI from 'urijs';
+import { qs } from './utils/core';
+import Url from './utils/url';
-function base(doc, section){
+export function replaceBase(doc, section){
var base;
var head;
@@ -12,8 +12,8 @@ function base(doc, section){
// head = doc.querySelector("head");
// base = head.querySelector("base");
- head = core.qs(doc, "head");
- base = core.qs(head, "base");
+ head = qs(doc, "head");
+ base = qs(head, "base");
if(!base) {
base = doc.createElement("base");
@@ -23,7 +23,7 @@ function base(doc, section){
base.setAttribute("href", section.url);
}
-function canonical(doc, section){
+export function replaceCanonical(doc, section){
var head;
var link;
var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url);
@@ -32,8 +32,8 @@ function canonical(doc, section){
return;
}
- head = core.qs(doc, "head");
- link = core.qs(head, "link[rel='canonical']");
+ head = qs(doc, "head");
+ link = qs(head, "link[rel='canonical']");
if (link) {
link.setAttribute("href", url);
@@ -45,10 +45,10 @@ function canonical(doc, section){
}
}
-function links(view, renderer) {
+export function replaceLinks(view, renderer) {
var links = view.document.querySelectorAll("a[href]");
- var replaceLinks = function(link){
+ var replaceLink = function(link){
var href = link.getAttribute("href");
if(href.indexOf("mailto:") === 0){
@@ -92,13 +92,13 @@ function links(view, renderer) {
}.bind(this);
for (var i = 0; i < links.length; i++) {
- replaceLinks(links[i]);
+ replaceLink(links[i]);
}
};
-function substitute(content, urls, replacements) {
+export function substitute(content, urls, replacements) {
urls.forEach(function(url, i){
if (url && replacements[i]) {
content = content.replace(new RegExp(url, 'g'), replacements[i]);
@@ -106,9 +106,3 @@ function substitute(content, urls, replacements) {
});
return content;
}
-module.exports = {
- 'base': base,
- 'canonical' : canonical,
- 'links': links,
- 'substitute': substitute
-};
diff --git a/src/request.js b/src/request.js
index 1dea92b..75c1fce 100644
--- a/src/request.js
+++ b/src/request.js
@@ -1,12 +1,12 @@
-var core = require('./core');
-var Path = require('./core').Path;
+import {defer, isXml, parse} from './utils/core';
+import Path from './utils/path';
function request(url, type, withCredentials, headers) {
var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined
var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
var uri;
- var deferred = new core.defer();
+ var deferred = new defer();
var xhr = new XMLHttpRequest();
@@ -49,7 +49,7 @@ function request(url, type, withCredentials, headers) {
}
- if(core.isXml(type)) {
+ if(isXml(type)) {
// xhr.responseType = "document";
xhr.overrideMimeType('text/xml'); // for OPF parsing
}
@@ -106,16 +106,16 @@ function request(url, type, withCredentials, headers) {
if(responseXML){
r = this.responseXML;
} else
- if(core.isXml(type)){
+ if(isXml(type)){
// xhr.overrideMimeType('text/xml'); // for OPF parsing
// If this.responseXML wasn't set, try to parse using a DOMParser from text
- r = core.parse(this.response, "text/xml");
+ r = parse(this.response, "text/xml");
}else
if(type == 'xhtml'){
- r = core.parse(this.response, "application/xhtml+xml");
+ r = parse(this.response, "application/xhtml+xml");
}else
if(type == 'html' || type == 'htm'){
- r = core.parse(this.response, "text/html");
+ r = parse(this.response, "text/html");
}else
if(type == 'json'){
r = JSON.parse(this.response);
@@ -149,4 +149,4 @@ function request(url, type, withCredentials, headers) {
return deferred.promise;
};
-module.exports = request;
+export default request;
diff --git a/src/resources.js b/src/resources.js
index 0d72acb..a09b9c6 100644
--- a/src/resources.js
+++ b/src/resources.js
@@ -1,7 +1,7 @@
-var replace = require('./replacements');
-var core = require('./core');
-var Path = require('./core').Path;
-var path = require('path');
+import {substitute} from './replacements';
+import {createBase64Url, createBlobUrl} from './utils/core';
+import Path from './utils/path';
+import path from 'path-webpack';
/**
* Handle Package Resources
@@ -12,234 +12,235 @@ var path = require('path');
* @param {[Archive]} options.archive
* @param {[method]} options.resolver
*/
-function Resources(manifest, options) {
- this.settings = {
- replacements: (options && options.replacements) || 'base64',
- archive: (options && options.archive),
- resolver: (options && options.resolver)
- };
- this.manifest = manifest;
- this.resources = Object.keys(manifest).
- map(function (key){
- return manifest[key];
- });
+class Resources {
+ constructor(manifest, options) {
+ this.settings = {
+ replacements: (options && options.replacements) || 'base64',
+ archive: (options && options.archive),
+ resolver: (options && options.resolver)
+ };
+ this.manifest = manifest;
+ this.resources = Object.keys(manifest).
+ map(function (key){
+ return manifest[key];
+ });
- this.replacementUrls = [];
+ this.replacementUrls = [];
- this.split();
- this.splitUrls();
-}
-
-/**
- * Split resources by type
- * @private
- */
-Resources.prototype.split = function(){
-
- // HTML
- this.html = this.resources.
- filter(function (item){
- if (item.type === "application/xhtml+xml" ||
- item.type === "text/html") {
- return true;
- }
- });
-
- // Exclude HTML
- this.assets = this.resources.
- filter(function (item){
- if (item.type !== "application/xhtml+xml" &&
- item.type !== "text/html") {
- return true;
- }
- });
-
- // Only CSS
- this.css = this.resources.
- filter(function (item){
- if (item.type === "text/css") {
- return true;
- }
- });
-};
-
-/**
- * Convert split resources into Urls
- * @private
- */
-Resources.prototype.splitUrls = function(){
-
- // All Assets Urls
- this.urls = this.assets.
- map(function(item) {
- return item.href;
- }.bind(this));
-
- // Css Urls
- this.cssUrls = this.css.map(function(item) {
- return item.href;
- });
-
-};
-
-/**
- * Create blob urls for all the assets
- * @param {Archive} archive
- * @param {resolver} resolver Url resolver
- * @return {Promise} returns replacement urls
- */
-Resources.prototype.replacements = function(archive, resolver){
- archive = archive || this.settings.archive;
- resolver = resolver || this.settings.resolver;
-
- if (this.settings.replacements === "none") {
- return new Promise(function(resolve, reject) {
- resolve(this.urls);
- }.bind(this));
+ this.split();
+ this.splitUrls();
}
- var replacements = this.urls.
- map(function(url) {
- var absolute = resolver(url);
+ /**
+ * Split resources by type
+ * @private
+ */
+ split(){
- return archive.createUrl(absolute, {"base64": (this.settings.replacements === "base64")});
- }.bind(this))
-
- return Promise.all(replacements)
- .then(function(replacementUrls) {
- this.replacementUrls = replacementUrls;
- return replacementUrls;
- }.bind(this));
-};
-
-/**
- * Replace URLs in CSS resources
- * @private
- * @param {[Archive]} archive
- * @param {[method]} resolver
- * @return {Promise}
- */
-Resources.prototype.replaceCss = function(archive, resolver){
- var replaced = [];
- archive = archive || this.settings.archive;
- resolver = resolver || this.settings.resolver;
- this.cssUrls.forEach(function(href) {
- var replacement = this.createCssFile(href, archive, resolver)
- .then(function (replacementUrl) {
- // switch the url in the replacementUrls
- var indexInUrls = this.urls.indexOf(href);
- if (indexInUrls > -1) {
- this.replacementUrls[indexInUrls] = replacementUrl;
+ // HTML
+ this.html = this.resources.
+ filter(function (item){
+ if (item.type === "application/xhtml+xml" ||
+ item.type === "text/html") {
+ return true;
}
+ });
+
+ // Exclude HTML
+ this.assets = this.resources.
+ filter(function (item){
+ if (item.type !== "application/xhtml+xml" &&
+ item.type !== "text/html") {
+ return true;
+ }
+ });
+
+ // Only CSS
+ this.css = this.resources.
+ filter(function (item){
+ if (item.type === "text/css") {
+ return true;
+ }
+ });
+ };
+
+ /**
+ * Convert split resources into Urls
+ * @private
+ */
+ splitUrls(){
+
+ // All Assets Urls
+ this.urls = this.assets.
+ map(function(item) {
+ return item.href;
}.bind(this));
- replaced.push(replacement);
- }.bind(this));
- return Promise.all(replaced);
-};
+ // Css Urls
+ this.cssUrls = this.css.map(function(item) {
+ return item.href;
+ });
-/**
- * Create a new CSS file with the replaced URLs
- * @private
- * @param {string} href the original css file
- * @param {[Archive]} archive
- * @param {[method]} resolver
- * @return {Promise} returns a BlobUrl to the new CSS file or a data url
- */
-Resources.prototype.createCssFile = function(href, archive, resolver){
- var newUrl;
- var indexInUrls;
+ };
+
+ /**
+ * Create blob urls for all the assets
+ * @param {Archive} archive
+ * @param {resolver} resolver Url resolver
+ * @return {Promise} returns replacement urls
+ */
+ replacements(archive, resolver){
archive = archive || this.settings.archive;
resolver = resolver || this.settings.resolver;
- if (path.isAbsolute(href)) {
- return new Promise(function(resolve, reject){
- resolve(urls, replacementUrls);
- });
+ if (this.settings.replacements === "none") {
+ return new Promise(function(resolve, reject) {
+ resolve(this.urls);
+ }.bind(this));
}
- var absolute = resolver(href);
+ var replacements = this.urls.
+ map(function(url) {
+ var absolute = resolver(url);
- // Get the text of the css file from the archive
- var textResponse = archive.getText(absolute);
- // Get asset links relative to css file
- var relUrls = this.urls.map(function(assetHref) {
- var resolved = resolver(assetHref);
- var relative = new Path(absolute).relative(resolved);
+ return archive.createUrl(absolute, {"base64": (this.settings.replacements === "base64")});
+ }.bind(this))
- return relative;
+ return Promise.all(replacements)
+ .then(function(replacementUrls) {
+ this.replacementUrls = replacementUrls;
+ return replacementUrls;
}.bind(this));
+ };
- return textResponse.then(function (text) {
- // Replacements in the css text
- text = replace.substitute(text, relUrls, this.replacementUrls);
+ /**
+ * Replace URLs in CSS resources
+ * @private
+ * @param {[Archive]} archive
+ * @param {[method]} resolver
+ * @return {Promise}
+ */
+ replaceCss(archive, resolver){
+ var replaced = [];
+ archive = archive || this.settings.archive;
+ resolver = resolver || this.settings.resolver;
+ this.cssUrls.forEach(function(href) {
+ var replacement = this.createCssFile(href, archive, resolver)
+ .then(function (replacementUrl) {
+ // switch the url in the replacementUrls
+ var indexInUrls = this.urls.indexOf(href);
+ if (indexInUrls > -1) {
+ this.replacementUrls[indexInUrls] = replacementUrl;
+ }
+ }.bind(this));
- // Get the new url
- if (this.settings.replacements === "base64") {
- newUrl = core.createBase64Url(text, 'text/css');
- } else {
- newUrl = core.createBlobUrl(text, 'text/css');
+ replaced.push(replacement);
+ }.bind(this));
+ return Promise.all(replaced);
+ };
+
+ /**
+ * Create a new CSS file with the replaced URLs
+ * @private
+ * @param {string} href the original css file
+ * @param {[Archive]} archive
+ * @param {[method]} resolver
+ * @return {Promise} returns a BlobUrl to the new CSS file or a data url
+ */
+ createCssFile(href, archive, resolver){
+ var newUrl;
+ var indexInUrls;
+ archive = archive || this.settings.archive;
+ resolver = resolver || this.settings.resolver;
+
+ if (path.isAbsolute(href)) {
+ return new Promise(function(resolve, reject){
+ resolve(urls, replacementUrls);
+ });
}
- return newUrl;
- }.bind(this));
+ var absolute = resolver(href);
-};
+ // Get the text of the css file from the archive
+ var textResponse = archive.getText(absolute);
+ // Get asset links relative to css file
+ var relUrls = this.urls.map(function(assetHref) {
+ var resolved = resolver(assetHref);
+ var relative = new Path(absolute).relative(resolved);
-/**
- * Resolve all resources URLs relative to an absolute URL
- * @param {string} absolute to be resolved to
- * @param {[resolver]} resolver
- * @return {string[]} array with relative Urls
- */
-Resources.prototype.relativeTo = function(absolute, resolver){
- resolver = resolver || this.settings.resolver;
+ return relative;
+ }.bind(this));
- // Get Urls relative to current sections
- return this.urls.
- map(function(href) {
- var resolved = resolver(href);
- var relative = new Path(absolute).relative(resolved);
- return relative;
- }.bind(this));
-};
+ return textResponse.then(function (text) {
+ // Replacements in the css text
+ text = substitute(text, relUrls, this.replacementUrls);
-/**
- * Get a URL for a resource
- * @param {string} path
- * @return {string} url
- */
-Resources.prototype.get = function(path) {
- var indexInUrls = this.urls.indexOf(path);
- if (indexInUrls === -1) {
- return;
- }
- if (this.replacementUrls.length) {
- return new Promise(function(resolve, reject) {
- resolve(this.replacementUrls[indexInUrls]);
- }.bind(this));
- } else {
- return archive.createUrl(absolute,
- {"base64": (this.settings.replacements === "base64")})
+ // Get the new url
+ if (this.settings.replacements === "base64") {
+ newUrl = createBase64Url(text, 'text/css');
+ } else {
+ newUrl = createBlobUrl(text, 'text/css');
+ }
+
+ return newUrl;
+ }.bind(this));
+
+ };
+
+ /**
+ * Resolve all resources URLs relative to an absolute URL
+ * @param {string} absolute to be resolved to
+ * @param {[resolver]} resolver
+ * @return {string[]} array with relative Urls
+ */
+ relativeTo(absolute, resolver){
+ resolver = resolver || this.settings.resolver;
+
+ // Get Urls relative to current sections
+ return this.urls.
+ map(function(href) {
+ var resolved = resolver(href);
+ var relative = new Path(absolute).relative(resolved);
+ return relative;
+ }.bind(this));
+ };
+
+ /**
+ * Get a URL for a resource
+ * @param {string} path
+ * @return {string} url
+ */
+ get(path) {
+ var indexInUrls = this.urls.indexOf(path);
+ if (indexInUrls === -1) {
+ return;
+ }
+ if (this.replacementUrls.length) {
+ return new Promise(function(resolve, reject) {
+ resolve(this.replacementUrls[indexInUrls]);
+ }.bind(this));
+ } else {
+ return archive.createUrl(absolute,
+ {"base64": (this.settings.replacements === "base64")})
+ }
}
+
+ /**
+ * Substitute urls in content, with replacements,
+ * relative to a url if provided
+ * @param {string} content
+ * @param {[string]} url url to resolve to
+ * @return {string} content with urls substituted
+ */
+ substitute(content, url) {
+ var relUrls;
+ if (url) {
+ relUrls = this.relativeTo(url);
+ } else {
+ relUrls = this.urls;
+ }
+ return substitute(content, relUrls, this.replacementUrls);
+ };
}
-/**
- * Substitute urls in content, with replacements,
- * relative to a url if provided
- * @param {string} content
- * @param {[string]} url url to resolve to
- * @return {string} content with urls substituted
- */
-Resources.prototype.substitute = function(content, url) {
- var relUrls;
- if (url) {
- relUrls = this.relativeTo(url);
- } else {
- relUrls = this.urls;
- }
- return replace.substitute(content, relUrls, this.replacementUrls);
-};
-
-
-module.exports = Resources;
+export default Resources;
diff --git a/src/section.js b/src/section.js
index acffaa3..35906c3 100644
--- a/src/section.js
+++ b/src/section.js
@@ -1,7 +1,7 @@
-var core = require('./core');
-var EpubCFI = require('./epubcfi');
-var Hook = require('./hook');
-var Url = require('./core').Url;
+import { defer } from './utils/core';
+import EpubCFI from './epubcfi';
+import Hook from './hook';
+import Url from './utils/url';
/**
* Represents a Section of the Book
@@ -9,178 +9,180 @@ var Url = require('./core').Url;
* @param {object} item The spine item representing the section
* @param {object} hooks hooks for serialize and content
*/
-function Section(item, hooks){
- this.idref = item.idref;
- this.linear = item.linear;
- this.properties = item.properties;
- this.index = item.index;
- this.href = item.href;
- this.url = item.url;
- this.next = item.next;
- this.prev = item.prev;
+class Section {
+ constructor(item, hooks){
+ this.idref = item.idref;
+ this.linear = item.linear;
+ this.properties = item.properties;
+ this.index = item.index;
+ this.href = item.href;
+ this.url = item.url;
+ this.next = item.next;
+ this.prev = item.prev;
- this.cfiBase = item.cfiBase;
+ this.cfiBase = item.cfiBase;
- if (hooks) {
- this.hooks = hooks;
- } else {
- this.hooks = {};
- this.hooks.serialize = new Hook(this);
- this.hooks.content = new Hook(this);
- }
-
-};
-
-/**
- * Load the section from its url
- * @param {method} _request a request method to use for loading
- * @return {document} a promise with the xml document
- */
-Section.prototype.load = function(_request){
- var request = _request || this.request || require('./request');
- var loading = new core.defer();
- var loaded = loading.promise;
-
- if(this.contents) {
- loading.resolve(this.contents);
- } else {
- request(this.url)
- .then(function(xml){
- var base;
- var directory = new Url(this.url).directory;
-
- this.document = xml;
- this.contents = xml.documentElement;
-
- return this.hooks.content.trigger(this.document, this);
- }.bind(this))
- .then(function(){
- loading.resolve(this.contents);
- }.bind(this))
- .catch(function(error){
- loading.reject(error);
- });
- }
-
- return loaded;
-};
-
-/**
- * Adds a base tag for resolving urls in the section
- * @private
- * @param {document} _document
- */
-Section.prototype.base = function(_document){
- var task = new core.defer();
- var base = _document.createElement("base"); // TODO: check if exists
- var head;
-
- base.setAttribute("href", window.location.origin + "/" +this.url);
-
- if(_document) {
- head = _document.querySelector("head");
- }
- if(head) {
- head.insertBefore(base, head.firstChild);
- task.resolve();
- } else {
- task.reject(new Error("No head to insert into"));
- }
-
-
- return task.promise;
-};
-
-/**
- * Render the contents of a section
- * @param {method} _request a request method to use for loading
- * @return {string} output a serialized XML Document
- */
-Section.prototype.render = function(_request){
- var rendering = new core.defer();
- var rendered = rendering.promise;
- this.output; // TODO: better way to return this from hooks?
-
- this.load(_request).
- then(function(contents){
- var serializer;
-
- if (typeof XMLSerializer === "undefined") {
- XMLSerializer = require('xmldom').XMLSerializer;
+ if (hooks) {
+ this.hooks = hooks;
+ } else {
+ this.hooks = {};
+ this.hooks.serialize = new Hook(this);
+ this.hooks.content = new Hook(this);
}
- serializer = new XMLSerializer();
- this.output = serializer.serializeToString(contents);
- return this.output;
- }.bind(this)).
- then(function(){
- return this.hooks.serialize.trigger(this.output, this);
- }.bind(this)).
- then(function(){
- rendering.resolve(this.output);
- }.bind(this))
- .catch(function(error){
- rendering.reject(error);
- });
- return rendered;
-};
-
-/**
- * Find a string in a section
- * TODO: need reimplementation from v0.2
- * @param {string} query [description]
- * @return {[type]} [description]
- */
-Section.prototype.find = function(query){
-
-};
-
-/**
-* Reconciles the current chapters layout properies with
-* the global layout properities.
-* @param {object} global The globa layout settings object, chapter properties string
-* @return {object} layoutProperties Object with layout properties
-*/
-Section.prototype.reconcileLayoutSettings = function(global){
- //-- Get the global defaults
- var settings = {
- layout : global.layout,
- spread : global.spread,
- orientation : global.orientation
};
- //-- Get the chapter's display type
- this.properties.forEach(function(prop){
- var rendition = prop.replace("rendition:", '');
- var split = rendition.indexOf("-");
- var property, value;
+ /**
+ * Load the section from its url
+ * @param {method} _request a request method to use for loading
+ * @return {document} a promise with the xml document
+ */
+ load(_request){
+ var request = _request || this.request || require('./request');
+ var loading = new defer();
+ var loaded = loading.promise;
- if(split != -1){
- property = rendition.slice(0, split);
- value = rendition.slice(split+1);
+ if(this.contents) {
+ loading.resolve(this.contents);
+ } else {
+ request(this.url)
+ .then(function(xml){
+ var base;
+ var directory = new Url(this.url).directory;
- settings[property] = value;
+ this.document = xml;
+ this.contents = xml.documentElement;
+
+ return this.hooks.content.trigger(this.document, this);
+ }.bind(this))
+ .then(function(){
+ loading.resolve(this.contents);
+ }.bind(this))
+ .catch(function(error){
+ loading.reject(error);
+ });
}
- });
- return settings;
-};
-/**
- * Get a CFI from a Range in the Section
- * @param {range} _range
- * @return {string} cfi an EpubCFI string
- */
-Section.prototype.cfiFromRange = function(_range) {
- return new EpubCFI(_range, this.cfiBase).toString();
-};
+ return loaded;
+ };
-/**
- * Get a CFI from an Element in the Section
- * @param {element} el
- * @return {string} cfi an EpubCFI string
- */
-Section.prototype.cfiFromElement = function(el) {
- return new EpubCFI(el, this.cfiBase).toString();
-};
+ /**
+ * Adds a base tag for resolving urls in the section
+ * @private
+ * @param {document} _document
+ */
+ base(_document){
+ var task = new defer();
+ var base = _document.createElement("base"); // TODO: check if exists
+ var head;
-module.exports = Section;
+ base.setAttribute("href", window.location.origin + "/" +this.url);
+
+ if(_document) {
+ head = _document.querySelector("head");
+ }
+ if(head) {
+ head.insertBefore(base, head.firstChild);
+ task.resolve();
+ } else {
+ task.reject(new Error("No head to insert into"));
+ }
+
+
+ return task.promise;
+ };
+
+ /**
+ * Render the contents of a section
+ * @param {method} _request a request method to use for loading
+ * @return {string} output a serialized XML Document
+ */
+ render(_request){
+ var rendering = new defer();
+ var rendered = rendering.promise;
+ this.output; // TODO: better way to return this from hooks?
+
+ this.load(_request).
+ then(function(contents){
+ var serializer;
+
+ if (typeof XMLSerializer === "undefined") {
+ XMLSerializer = require('xmldom').XMLSerializer;
+ }
+ serializer = new XMLSerializer();
+ this.output = serializer.serializeToString(contents);
+ return this.output;
+ }.bind(this)).
+ then(function(){
+ return this.hooks.serialize.trigger(this.output, this);
+ }.bind(this)).
+ then(function(){
+ rendering.resolve(this.output);
+ }.bind(this))
+ .catch(function(error){
+ rendering.reject(error);
+ });
+
+ return rendered;
+ };
+
+ /**
+ * Find a string in a section
+ * TODO: need reimplementation from v0.2
+ * @param {string} query [description]
+ * @return {[type]} [description]
+ */
+ find(query){
+
+ };
+
+ /**
+ * Reconciles the current chapters layout properies with
+ * the global layout properities.
+ * @param {object} global The globa layout settings object, chapter properties string
+ * @return {object} layoutProperties Object with layout properties
+ */
+ reconcileLayoutSettings(global){
+ //-- Get the global defaults
+ var settings = {
+ layout : global.layout,
+ spread : global.spread,
+ orientation : global.orientation
+ };
+
+ //-- Get the chapter's display type
+ this.properties.forEach(function(prop){
+ var rendition = prop.replace("rendition:", '');
+ var split = rendition.indexOf("-");
+ var property, value;
+
+ if(split != -1){
+ property = rendition.slice(0, split);
+ value = rendition.slice(split+1);
+
+ settings[property] = value;
+ }
+ });
+ return settings;
+ };
+
+ /**
+ * Get a CFI from a Range in the Section
+ * @param {range} _range
+ * @return {string} cfi an EpubCFI string
+ */
+ cfiFromRange(_range) {
+ return new EpubCFI(_range, this.cfiBase).toString();
+ };
+
+ /**
+ * Get a CFI from an Element in the Section
+ * @param {element} el
+ * @return {string} cfi an EpubCFI string
+ */
+ cfiFromElement(el) {
+ return new EpubCFI(el, this.cfiBase).toString();
+ };
+}
+
+export default Section;
diff --git a/src/spine.js b/src/spine.js
index 382433f..d7cc04f 100644
--- a/src/spine.js
+++ b/src/spine.js
@@ -1,161 +1,163 @@
-var core = require('./core');
-var EpubCFI = require('./epubcfi');
-var Hook = require('./hook');
-var Section = require('./section');
-var replacements = require('./replacements');
+import core from './utils/core';
+import EpubCFI from './epubcfi';
+import Hook from './hook';
+import Section from './section';
+import {replaceBase, replaceCanonical} from './replacements';
/**
* A collection of Spine Items
*/
-function Spine(){
- this.spineItems = [];
- this.spineByHref = {};
- this.spineById = {};
+class Spine {
+ constructor() {
+ this.spineItems = [];
+ this.spineByHref = {};
+ this.spineById = {};
- this.hooks = {};
- this.hooks.serialize = new Hook();
- this.hooks.content = new Hook();
+ this.hooks = {};
+ this.hooks.serialize = new Hook();
+ this.hooks.content = new Hook();
- // Register replacements
- this.hooks.content.register(replacements.base);
- this.hooks.content.register(replacements.canonical);
+ // Register replacements
+ this.hooks.content.register(replaceBase);
+ this.hooks.content.register(replaceCanonical);
- this.epubcfi = new EpubCFI();
+ this.epubcfi = new EpubCFI();
- this.loaded = false;
-};
+ this.loaded = false;
+ };
-/**
- * Unpack items from a opf into spine items
- * @param {Package} _package
- * @param {method} resolver URL resolver
- */
-Spine.prototype.unpack = function(_package, resolver) {
+ /**
+ * Unpack items from a opf into spine items
+ * @param {Package} _package
+ * @param {method} resolver URL resolver
+ */
+ unpack(_package, resolver) {
- this.items = _package.spine;
- this.manifest = _package.manifest;
- this.spineNodeIndex = _package.spineNodeIndex;
- this.baseUrl = _package.baseUrl || _package.basePath || '';
- this.length = this.items.length;
+ this.items = _package.spine;
+ this.manifest = _package.manifest;
+ this.spineNodeIndex = _package.spineNodeIndex;
+ this.baseUrl = _package.baseUrl || _package.basePath || '';
+ this.length = this.items.length;
- this.items.forEach(function(item, index){
- var href, url;
- var manifestItem = this.manifest[item.idref];
- var spineItem;
+ this.items.forEach(function(item, index){
+ var href, url;
+ var manifestItem = this.manifest[item.idref];
+ var spineItem;
- item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
+ item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
- if(manifestItem) {
- item.href = manifestItem.href;
- item.url = resolver(item.href, true);
+ if(manifestItem) {
+ item.href = manifestItem.href;
+ item.url = resolver(item.href, true);
- if(manifestItem.properties.length){
- item.properties.push.apply(item.properties, manifestItem.properties);
+ if(manifestItem.properties.length){
+ item.properties.push.apply(item.properties, manifestItem.properties);
+ }
}
+
+ item.prev = function(){ return this.get(index-1); }.bind(this);
+ item.next = function(){ return this.get(index+1); }.bind(this);
+
+ spineItem = new Section(item, this.hooks);
+
+ this.append(spineItem);
+
+
+ }.bind(this));
+
+ this.loaded = true;
+ };
+
+ /**
+ * Get an item from the spine
+ * @param {[string|int]} target
+ * @return {Section} section
+ * @example spine.get();
+ * @example spine.get(1);
+ * @example spine.get("chap1.html");
+ * @example spine.get("#id1234");
+ */
+ get(target) {
+ var index = 0;
+
+ if(this.epubcfi.isCfiString(target)) {
+ cfi = new EpubCFI(target);
+ index = cfi.spinePos;
+ } else if(target && (typeof target === "number" || isNaN(target) === false)){
+ index = target;
+ } else if(target && target.indexOf("#") === 0) {
+ index = this.spineById[target.substring(1)];
+ } else if(target) {
+ // Remove fragments
+ target = target.split("#")[0];
+ index = this.spineByHref[target];
}
- item.prev = function(){ return this.get(index-1); }.bind(this);
- item.next = function(){ return this.get(index+1); }.bind(this);
+ return this.spineItems[index] || null;
+ };
- spineItem = new Section(item, this.hooks);
+ /**
+ * Append a Section to the Spine
+ * @private
+ * @param {Section} section
+ */
+ append(section) {
+ var index = this.spineItems.length;
+ section.index = index;
- this.append(spineItem);
+ this.spineItems.push(section);
+ this.spineByHref[section.href] = index;
+ this.spineById[section.idref] = index;
- }.bind(this));
+ return index;
+ };
- this.loaded = true;
-};
+ /**
+ * Prepend a Section to the Spine
+ * @private
+ * @param {Section} section
+ */
+ prepend(section) {
+ var index = this.spineItems.unshift(section);
+ this.spineByHref[section.href] = 0;
+ this.spineById[section.idref] = 0;
-/**
- * Get an item from the spine
- * @param {[string|int]} target
- * @return {Section} section
- * @example spine.get();
- * @example spine.get(1);
- * @example spine.get("chap1.html");
- * @example spine.get("#id1234");
- */
-Spine.prototype.get = function(target) {
- var index = 0;
+ // Re-index
+ this.spineItems.forEach(function(item, index){
+ item.index = index;
+ });
- if(this.epubcfi.isCfiString(target)) {
- cfi = new EpubCFI(target);
- index = cfi.spinePos;
- } else if(target && (typeof target === "number" || isNaN(target) === false)){
- index = target;
- } else if(target && target.indexOf("#") === 0) {
- index = this.spineById[target.substring(1)];
- } else if(target) {
- // Remove fragments
- target = target.split("#")[0];
- index = this.spineByHref[target];
- }
+ return 0;
+ };
- return this.spineItems[index] || null;
-};
+ // insert(section, index) {
+ //
+ // };
-/**
- * Append a Section to the Spine
- * @private
- * @param {Section} section
- */
-Spine.prototype.append = function(section) {
- var index = this.spineItems.length;
- section.index = index;
+ /**
+ * Remove a Section from the Spine
+ * @private
+ * @param {Section} section
+ */
+ remove(section) {
+ var index = this.spineItems.indexOf(section);
- this.spineItems.push(section);
+ if(index > -1) {
+ delete this.spineByHref[section.href];
+ delete this.spineById[section.idref];
- this.spineByHref[section.href] = index;
- this.spineById[section.idref] = index;
+ return this.spineItems.splice(index, 1);
+ }
+ };
- return index;
-};
+ /**
+ * Loop over the Sections in the Spine
+ * @return {method} forEach
+ */
+ each() {
+ return this.spineItems.forEach.apply(this.spineItems, arguments);
+ };
+}
-/**
- * Prepend a Section to the Spine
- * @private
- * @param {Section} section
- */
-Spine.prototype.prepend = function(section) {
- var index = this.spineItems.unshift(section);
- this.spineByHref[section.href] = 0;
- this.spineById[section.idref] = 0;
-
- // Re-index
- this.spineItems.forEach(function(item, index){
- item.index = index;
- });
-
- return 0;
-};
-
-// Spine.prototype.insert = function(section, index) {
-//
-// };
-
-/**
- * Remove a Section from the Spine
- * @private
- * @param {Section} section
- */
-Spine.prototype.remove = function(section) {
- var index = this.spineItems.indexOf(section);
-
- if(index > -1) {
- delete this.spineByHref[section.href];
- delete this.spineById[section.idref];
-
- return this.spineItems.splice(index, 1);
- }
-};
-
-/**
- * Loop over the Sections in the Spine
- * @return {method} forEach
- */
-Spine.prototype.each = function() {
- return this.spineItems.forEach.apply(this.spineItems, arguments);
-};
-
-module.exports = Spine;
+export default Spine;
diff --git a/src/themes.js b/src/themes.js
index 65d7c0e..c08ff36 100644
--- a/src/themes.js
+++ b/src/themes.js
@@ -1,155 +1,158 @@
-var Url = require('./core').Url;
+import Url from './utils/url';
-function Themes(rendition) {
- this.rendition = rendition;
- this._themes = {
- "default" : {
- "rules" : [],
- "url" : "",
- "serialized" : ''
+class Themes {
+ constructor(rendition) {
+ this.rendition = rendition;
+ this._themes = {
+ "default" : {
+ "rules" : [],
+ "url" : "",
+ "serialized" : ''
+ }
+ };
+ this._overrides = {};
+ this._current = "default";
+ this._injected = [];
+ this.rendition.hooks.content.register(this.inject.bind(this));
+ this.rendition.hooks.content.register(this.overrides.bind(this));
+
+ }
+
+ register () {
+ if (arguments.length === 0) {
+ return;
+ }
+ if (arguments.length === 1 && typeof(arguments[0]) === "object") {
+ return this.registerThemes(arguments[0]);
+ }
+ if (arguments.length === 1 && typeof(arguments[0]) === "string") {
+ return this.default(arguments[0]);
+ }
+ if (arguments.length === 2 && typeof(arguments[1]) === "string") {
+ return this.registerUrl(arguments[0], arguments[1]);
+ }
+ if (arguments.length === 2 && typeof(arguments[1]) === "object") {
+ return this.registerRules(arguments[0], arguments[1]);
}
};
- this._overrides = {};
- this._current = "default";
- this._injected = [];
- this.rendition.hooks.content.register(this.inject.bind(this));
- this.rendition.hooks.content.register(this.overrides.bind(this));
+
+ default (theme) {
+ if (!theme) {
+ return;
+ }
+ if (typeof(theme) === "string") {
+ return this.registerUrl("default", theme);
+ }
+ if (typeof(theme) === "object") {
+ return this.registerRules("default", theme);
+ }
+ };
+
+ registerThemes (themes) {
+ for (var theme in themes) {
+ if (themes.hasOwnProperty(theme)) {
+ if (typeof(themes[theme]) === "string") {
+ this.registerUrl(theme, themes[theme]);
+ } else {
+ this.registerRules(theme, themes[theme]);
+ }
+ }
+ }
+ };
+
+ registerUrl (name, input) {
+ var url = new Url(input);
+ this._themes[name] = { "url": url.toString() };
+ };
+
+ registerRules (name, rules) {
+ this._themes[name] = { "rules": rules };
+ // TODO: serialize css rules
+ };
+
+ apply (name) {
+ var prev = this._current;
+ var contents;
+
+ this._current = name;
+ this.update(name);
+
+ contents = this.rendition.getContents();
+ contents.forEach(function (content) {
+ content.removeClass(prev);
+ content.addClass(name);
+ }.bind(this));
+ };
+
+ update (name) {
+ var contents = this.rendition.getContents();
+ contents.forEach(function (content) {
+ this.add(name, content);
+ }.bind(this));
+ };
+
+ inject (view) {
+ var links = [];
+ var themes = this._themes;
+ var theme;
+
+ for (var name in themes) {
+ if (themes.hasOwnProperty(name)) {
+ theme = themes[name];
+ if(theme.rules || (theme.url && links.indexOf(theme.url) === -1)) {
+ this.add(name, view.contents);
+ }
+ }
+ }
+
+ if(this._current) {
+ view.contents.addClass(this._current);
+ }
+ };
+
+ add (name, contents) {
+ var theme = this._themes[name];
+
+ if (!theme) {
+ return;
+ }
+
+ if (theme.url) {
+ contents.addStylesheet(theme.url);
+ } else if (theme.serialized) {
+ // TODO: handle serialized
+ } else if (theme.rules && theme.rules.length) {
+ contents.addStylesheetRules(theme.rules);
+ theme.injected = true;
+ }
+ };
+
+ override (name, value) {
+ var contents = this.rendition.getContents();
+
+ this._overrides[name] = value;
+
+ contents.forEach(function (content) {
+ content.css(name, this._overrides[name]);
+ }.bind(this));
+ };
+
+ overrides (view) {
+ var contents = view.contents;
+ var overrides = this._overrides;
+ var rules = [];
+
+ for (var rule in overrides) {
+ if (overrides.hasOwnProperty(rule)) {
+ contents.css(rule, overrides[rule]);
+ }
+ }
+ };
+
+ fontSize (size) {
+ this.override("font-size", size);
+ };
}
-Themes.prototype.register = function () {
- if (arguments.length === 0) {
- return;
- }
- if (arguments.length === 1 && typeof(arguments[0]) === "object") {
- return this.registerThemes(arguments[0]);
- }
- if (arguments.length === 1 && typeof(arguments[0]) === "string") {
- return this.default(arguments[0]);
- }
- if (arguments.length === 2 && typeof(arguments[1]) === "string") {
- return this.registerUrl(arguments[0], arguments[1]);
- }
- if (arguments.length === 2 && typeof(arguments[1]) === "object") {
- return this.registerRules(arguments[0], arguments[1]);
- }
-};
-
-Themes.prototype.default = function (theme) {
- if (!theme) {
- return;
- }
- if (typeof(theme) === "string") {
- return this.registerUrl("default", theme);
- }
- if (typeof(theme) === "object") {
- return this.registerRules("default", theme);
- }
-};
-
-Themes.prototype.registerThemes = function (themes) {
- for (var theme in themes) {
- if (themes.hasOwnProperty(theme)) {
- if (typeof(themes[theme]) === "string") {
- this.registerUrl(theme, themes[theme]);
- } else {
- this.registerRules(theme, themes[theme]);
- }
- }
- }
-};
-
-Themes.prototype.registerUrl = function (name, input) {
- var url = new Url(input);
- this._themes[name] = { "url": url.toString() };
-};
-
-Themes.prototype.registerRules = function (name, rules) {
- this._themes[name] = { "rules": rules };
- // TODO: serialize css rules
-};
-
-Themes.prototype.apply = function (name) {
- var prev = this._current;
- var contents;
-
- this._current = name;
- this.update(name);
-
- contents = this.rendition.getContents();
- contents.forEach(function (content) {
- content.removeClass(prev);
- content.addClass(name);
- }.bind(this));
-};
-
-Themes.prototype.update = function (name) {
- var contents = this.rendition.getContents();
- contents.forEach(function (content) {
- this.add(name, content);
- }.bind(this));
-};
-
-Themes.prototype.inject = function (view) {
- var links = [];
- var themes = this._themes;
- var theme;
-
- for (var name in themes) {
- if (themes.hasOwnProperty(name)) {
- theme = themes[name];
- if(theme.rules || (theme.url && links.indexOf(theme.url) === -1)) {
- this.add(name, view.contents);
- }
- }
- }
-
- if(this._current) {
- view.contents.addClass(this._current);
- }
-};
-
-Themes.prototype.add = function (name, contents) {
- var theme = this._themes[name];
-
- if (!theme) {
- return;
- }
-
- if (theme.url) {
- contents.addStylesheet(theme.url);
- } else if (theme.serialized) {
- // TODO: handle serialized
- } else if (theme.rules && theme.rules.length) {
- contents.addStylesheetRules(theme.rules);
- theme.injected = true;
- }
-};
-
-Themes.prototype.override = function (name, value) {
- var contents = this.rendition.getContents();
-
- this._overrides[name] = value;
-
- contents.forEach(function (content) {
- content.css(name, this._overrides[name]);
- }.bind(this));
-};
-
-Themes.prototype.overrides = function (view) {
- var contents = view.contents;
- var overrides = this._overrides;
- var rules = [];
-
- for (var rule in overrides) {
- if (overrides.hasOwnProperty(rule)) {
- contents.css(rule, overrides[rule]);
- }
- }
-};
-
-Themes.prototype.fontSize = function (size) {
- this.override("font-size", size);
-};
-
-module.exports = Themes;
+export default Themes;
diff --git a/src/core.js b/src/utils/core.js
similarity index 60%
rename from src/core.js
rename to src/utils/core.js
index 3debad1..70c4ef8 100644
--- a/src/core.js
+++ b/src/utils/core.js
@@ -1,144 +1,11 @@
-var base64 = require('base64-js');
-var path = require('path');
+export const requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
-var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
-
-/**
- * creates a uri object
- * @param {string} urlString a url string (relative or absolute)
- * @param {[string]} baseString optional base for the url,
- * default to window.location.href
- * @return {object} url
- */
-function Url(urlString, baseString) {
- var absolute = (urlString.indexOf('://') > -1);
- var pathname = urlString;
-
- this.Url = undefined;
- this.href = urlString;
- this.protocol = "";
- this.origin = "";
- this.fragment = "";
- this.search = "";
- this.base = baseString;
-
- if (!absolute && (typeof(baseString) !== "string")) {
- this.base = window && window.location.href;
- }
-
- // URL Polyfill doesn't throw an error if base is empty
- if (absolute || this.base) {
- try {
- this.Url = new URL(urlString, this.base);
- this.href = this.Url.href;
-
- this.protocol = this.Url.protocol;
- this.origin = this.Url.origin;
- this.fragment = this.Url.fragment;
- this.search = this.Url.search;
-
- pathname = this.Url.pathname;
- } catch (e) {
- // Skip URL parsing
- this.Url = undefined;
- }
- }
-
- this.Path = new Path(pathname);
- this.directory = this.Path.directory;
- this.filename = this.Path.filename;
- this.extension = this.Path.extension;
-
-}
-
-Url.prototype.path = function () {
- return this.Path;
-};
-
-Url.prototype.resolve = function (what) {
- var isAbsolute = (what.indexOf('://') > -1);
- var fullpath;
-
- if (isAbsolute) {
- return what;
- }
-
- fullpath = path.resolve(this.directory, what);
- return this.origin + fullpath;
-};
-
-Url.prototype.relative = function (what) {
- return path.relative(what, this.directory);
-};
-
-Url.prototype.toString = function () {
- return this.href;
-};
-
-function Path(pathString) {
- var protocol;
- var parsed;
-
- protocol = pathString.indexOf('://');
- if (protocol > -1) {
- pathString = new URL(pathString).pathname;
- }
-
- parsed = this.parse(pathString);
-
- this.path = pathString;
-
- if (this.isDirectory(pathString)) {
- this.directory = pathString;
- } else {
- this.directory = parsed.dir + "/";
- }
-
- this.filename = parsed.base;
- this.extension = parsed.ext.slice(1);
-
-}
-
-Path.prototype.parse = function (what) {
- return path.parse(what);
-};
-
-Path.prototype.isAbsolute = function (what) {
- return path.isAbsolute(what || this.path);
-};
-
-Path.prototype.isDirectory = function (what) {
- return (what.charAt(what.length-1) === '/');
-};
-
-Path.prototype.resolve = function (what) {
- return path.resolve(this.directory, what);
-};
-
-Path.prototype.relative = function (what) {
- return path.relative(this.directory, what);
-};
-
-Path.prototype.splitPath = function(filename) {
- return this.splitPathRe.exec(filename).slice(1);
-};
-
-Path.prototype.toString = function () {
- return this.path;
-};
-
-function assertPath(path) {
- if (typeof path !== 'string') {
- throw new TypeError('Path must be a string. Received ', path);
- }
-};
-
-function isElement(obj) {
+export function isElement(obj) {
return !!(obj && obj.nodeType == 1);
};
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
-function uuid() {
+export function uuid() {
var d = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random()*16)%16 | 0;
@@ -149,7 +16,7 @@ function uuid() {
};
// From Lodash
-function values(object) {
+export function values(object) {
var index = -1,
props = Object.keys(object),
length = props.length,
@@ -161,70 +28,7 @@ function values(object) {
return result;
};
-function resolveUrl(base, path) {
- var url = [],
- segments = [],
- baseUri = uri(base),
- pathUri = uri(path),
- baseDirectory = baseUri.directory,
- pathDirectory = pathUri.directory,
- directories = [],
- // folders = base.split("/"),
- paths;
-
- // if(uri.host) {
- // return path;
- // }
-
- if(baseDirectory[0] === "/") {
- baseDirectory = baseDirectory.substring(1);
- }
-
- if(pathDirectory[pathDirectory.length-1] === "/") {
- baseDirectory = baseDirectory.substring(0, baseDirectory.length-1);
- }
-
- if(pathDirectory[0] === "/") {
- pathDirectory = pathDirectory.substring(1);
- }
-
- if(pathDirectory[pathDirectory.length-1] === "/") {
- pathDirectory = pathDirectory.substring(0, pathDirectory.length-1);
- }
-
- if(baseDirectory) {
- directories = baseDirectory.split("/");
- }
-
- paths = pathDirectory.split("/");
-
- paths.reverse().forEach(function(part, index){
- if(part === ".."){
- directories.pop();
- } else if(part === directories[directories.length-1]) {
- directories.pop();
- segments.unshift(part);
- } else {
- segments.unshift(part);
- }
- });
-
- url = [baseUri.origin];
-
- if(directories.length) {
- url = url.concat(directories);
- }
-
- if(segments) {
- url = url.concat(segments);
- }
-
- url = url.concat(pathUri.filename);
-
- return url.join("/");
-};
-
-function documentHeight() {
+export function documentHeight() {
return Math.max(
document.documentElement.clientHeight,
document.body.scrollHeight,
@@ -234,15 +38,15 @@ function documentHeight() {
);
};
-function isNumber(n) {
+export function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
-function isFloat(n) {
+export function isFloat(n) {
return isNumber(n) && (Math.floor(n) !== n);
}
-function prefixed(unprefixed) {
+export function prefixed(unprefixed) {
var vendors = ["Webkit", "Moz", "O", "ms" ],
prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'],
upper = unprefixed[0].toUpperCase() + unprefixed.slice(1),
@@ -261,7 +65,7 @@ function prefixed(unprefixed) {
return unprefixed;
};
-function defaults(obj) {
+export function defaults(obj) {
for (var i = 1, length = arguments.length; i < length; i++) {
var source = arguments[i];
for (var prop in source) {
@@ -271,7 +75,7 @@ function defaults(obj) {
return obj;
};
-function extend(target) {
+export function extend(target) {
var sources = [].slice.call(arguments, 1);
sources.forEach(function (source) {
if(!source) return;
@@ -284,14 +88,14 @@ function extend(target) {
// Fast quicksort insert for sorted array -- based on:
// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
-function insert(item, array, compareFunction) {
+export function insert(item, array, compareFunction) {
var location = locationOf(item, array, compareFunction);
array.splice(location, 0, item);
return location;
};
// Returns where something would fit in
-function locationOf(item, array, compareFunction, _start, _end) {
+export function locationOf(item, array, compareFunction, _start, _end) {
var start = _start || 0;
var end = _end || array.length;
var pivot = parseInt(start + (end - start) / 2);
@@ -322,7 +126,7 @@ function locationOf(item, array, compareFunction, _start, _end) {
}
};
// Returns -1 of mpt found
-function indexOfSorted(item, array, compareFunction, _start, _end) {
+export function indexOfSorted(item, array, compareFunction, _start, _end) {
var start = _start || 0;
var end = _end || array.length;
var pivot = parseInt(start + (end - start) / 2);
@@ -352,7 +156,7 @@ function indexOfSorted(item, array, compareFunction, _start, _end) {
}
};
-function bounds(el) {
+export function bounds(el) {
var style = window.getComputedStyle(el);
var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"];
@@ -376,7 +180,7 @@ function bounds(el) {
};
-function borders(el) {
+export function borders(el) {
var style = window.getComputedStyle(el);
var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"];
@@ -400,7 +204,7 @@ function borders(el) {
};
-function windowBounds() {
+export function windowBounds() {
var width = window.innerWidth;
var height = window.innerHeight;
@@ -417,7 +221,7 @@ function windowBounds() {
};
//https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496
-function cleanStringForXpath(str) {
+export function cleanStringForXpath(str) {
var parts = str.match(/[^'"]+|['"]/g);
parts = parts.map(function(part){
if (part === "'") {
@@ -432,7 +236,7 @@ function cleanStringForXpath(str) {
return "concat(\'\'," + parts.join(",") + ")";
};
-function indexOfTextNode(textNode){
+export function indexOfTextNode(textNode){
var parent = textNode.parentNode;
var children = parent.childNodes;
var sib;
@@ -448,17 +252,17 @@ function indexOfTextNode(textNode){
return index;
};
-function isXml(ext) {
+export function isXml(ext) {
return ['xml', 'opf', 'ncx'].indexOf(ext) > -1;
}
-function createBlob(content, mime){
+export function createBlob(content, mime){
var blob = new Blob([content], {type : mime });
return blob;
};
-function createBlobUrl(content, mime){
+export function createBlobUrl(content, mime){
var _URL = window.URL || window.webkitURL || window.mozURL;
var tempUrl;
var blob = this.createBlob(content, mime);
@@ -468,7 +272,7 @@ function createBlobUrl(content, mime){
return tempUrl;
};
-function createBase64Url(content, mime){
+export function createBase64Url(content, mime){
var string;
var data;
var datauri;
@@ -485,11 +289,11 @@ function createBase64Url(content, mime){
return datauri;
};
-function type(obj){
+export function type(obj){
return Object.prototype.toString.call(obj).slice(8, -1);
}
-function parse(markup, mime, forceXMLDom) {
+export function parse(markup, mime, forceXMLDom) {
var doc;
if (typeof DOMParser === "undefined" || forceXMLDom) {
@@ -502,7 +306,7 @@ function parse(markup, mime, forceXMLDom) {
return doc;
}
-function qs(el, sel) {
+export function qs(el, sel) {
var elements;
if (!el) {
throw new Error('No Element Provided');
@@ -518,7 +322,7 @@ function qs(el, sel) {
}
}
-function qsa(el, sel) {
+export function qsa(el, sel) {
if (typeof el.querySelector != "undefined") {
return el.querySelectorAll(sel);
@@ -527,7 +331,7 @@ function qsa(el, sel) {
}
}
-function qsp(el, sel, props) {
+export function qsp(el, sel, props) {
var q, filtered;
if (typeof el.querySelector != "undefined") {
sel += '[';
@@ -558,7 +362,7 @@ function qsp(el, sel, props) {
* @param {element} root element to start with
* @param {function} func function to run on each element
*/
-function sprint(root, func) {
+export function sprint(root, func) {
var doc = root.ownerDocument || root;
if (typeof(doc.createTreeWalker) !== "undefined") {
treeWalker(root, func, NodeFilter.SHOW_TEXT);
@@ -571,14 +375,15 @@ function sprint(root, func) {
}
}
-function treeWalker(root, func, filter) {
+export function treeWalker(root, func, filter) {
var treeWalker = document.createTreeWalker(root, filter, null, false);
+ let node;
while ((node = treeWalker.nextNode())) {
func(node);
}
}
-// function walk(root, func, onlyText) {
+// export function walk(root, func, onlyText) {
// var node = root;
//
// if (node && !onlyText || node.nodeType === 3) { // Node.TEXT_NODE
@@ -597,7 +402,7 @@ function treeWalker(root, func, filter) {
* @param callback return false for continue,true for break
* @return boolean true: break visit;
*/
-function walk(node,callback){
+export function walk(node,callback){
if(callback(node)){
return true;
}
@@ -608,7 +413,7 @@ function walk(node,callback){
}
}
-function blob2base64(blob, cb) {
+export function blob2base64(blob, cb) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
@@ -617,7 +422,7 @@ function blob2base64(blob, cb) {
}
// From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible
-function defer() {
+export function defer() {
/* A method to resolve the associated Promise with the value passed.
* If the promise is already settled it does nothing.
*
@@ -648,14 +453,14 @@ function defer() {
Object.freeze(this);
}
- function querySelectorByType(html, element, type){
+ export function querySelectorByType(html, element, type){
var query;
if (typeof html.querySelector != "undefined") {
query = html.querySelector(element+'[*|type="'+type+'"]');
}
// Handle IE not supporting namespaced epub:type in querySelector
if(!query || query.length === 0) {
- query = this.qsa(html, element);
+ query = qsa(html, element);
for (var i = 0; i < query.length; i++) {
if(query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type) {
return query[i];
@@ -666,53 +471,14 @@ function defer() {
}
}
-function children(el) {
- var children = [];
+export function findChildren(el) {
+ var result = [];
var childNodes = el.parentNode.childNodes;
for (var i = 0; i < childNodes.length; i++) {
- node = childNodes[i];
+ let node = childNodes[i];
if (node.nodeType === 1) {
- children.push(node);
+ result.push(node);
}
};
- return children;
+ return result;
}
-
-module.exports = {
- 'isElement': isElement,
- 'uuid': uuid,
- 'values': values,
- 'resolveUrl': resolveUrl,
- 'indexOfSorted': indexOfSorted,
- 'documentHeight': documentHeight,
- 'isNumber': isNumber,
- 'isFloat': isFloat,
- 'prefixed': prefixed,
- 'defaults': defaults,
- 'extend': extend,
- 'insert': insert,
- 'locationOf': locationOf,
- 'indexOfSorted': indexOfSorted,
- 'requestAnimationFrame': requestAnimationFrame,
- 'bounds': bounds,
- 'borders': borders,
- 'windowBounds': windowBounds,
- 'cleanStringForXpath': cleanStringForXpath,
- 'indexOfTextNode': indexOfTextNode,
- 'isXml': isXml,
- 'createBlob': createBlob,
- 'createBlobUrl': createBlobUrl,
- 'type': type,
- 'parse' : parse,
- 'qs' : qs,
- 'qsa' : qsa,
- 'qsp' : qsp,
- 'blob2base64' : blob2base64,
- 'createBase64Url': createBase64Url,
- 'defer': defer,
- 'Url': Url,
- 'Path': Path,
- 'querySelectorByType': querySelectorByType,
- 'sprint' : sprint,
- 'children' : children
-};
diff --git a/src/utils/path.js b/src/utils/path.js
new file mode 100644
index 0000000..f21e8d5
--- /dev/null
+++ b/src/utils/path.js
@@ -0,0 +1,57 @@
+import path from 'path-webpack';
+
+class Path {
+ constructor(pathString) {
+ var protocol;
+ var parsed;
+
+ protocol = pathString.indexOf('://');
+ if (protocol > -1) {
+ pathString = new URL(pathString).pathname;
+ }
+
+ parsed = this.parse(pathString);
+
+ this.path = pathString;
+
+ if (this.isDirectory(pathString)) {
+ this.directory = pathString;
+ } else {
+ this.directory = parsed.dir + "/";
+ }
+
+ this.filename = parsed.base;
+ this.extension = parsed.ext.slice(1);
+
+ }
+
+ parse (what) {
+ return path.parse(what);
+ };
+
+ isAbsolute (what) {
+ return path.isAbsolute(what || this.path);
+ };
+
+ isDirectory (what) {
+ return (what.charAt(what.length-1) === '/');
+ };
+
+ resolve (what) {
+ return path.resolve(this.directory, what);
+ };
+
+ relative (what) {
+ return path.relative(this.directory, what);
+ };
+
+ splitPath(filename) {
+ return this.splitPathRe.exec(filename).slice(1);
+ };
+
+ toString () {
+ return this.path;
+ };
+}
+
+export default Path
diff --git a/src/utils/url.js b/src/utils/url.js
new file mode 100644
index 0000000..cd5a799
--- /dev/null
+++ b/src/utils/url.js
@@ -0,0 +1,83 @@
+import Path from './path'
+import path from 'path-webpack';
+
+/**
+ * creates a uri object
+ * @param {string} urlString a url string (relative or absolute)
+ * @param {[string]} baseString optional base for the url,
+ * default to window.location.href
+ * @return {object} url
+ */
+
+class Url {
+ constructor(urlString, baseString) {
+ var absolute = (urlString.indexOf('://') > -1);
+ var pathname = urlString;
+
+ this.Url = undefined;
+ this.href = urlString;
+ this.protocol = "";
+ this.origin = "";
+ this.fragment = "";
+ this.search = "";
+ this.base = baseString;
+
+ if (!absolute && (typeof(baseString) !== "string")) {
+ this.base = window && window.location.href;
+ }
+
+ // URL Polyfill doesn't throw an error if base is empty
+ if (absolute || this.base) {
+ try {
+ if (this.base) { // Safari doesn't like an undefined base
+ this.Url = new URL(urlString, this.base);
+ } else {
+ this.Url = new URL(urlString);
+ }
+ this.href = this.Url.href;
+
+ this.protocol = this.Url.protocol;
+ this.origin = this.Url.origin;
+ this.fragment = this.Url.fragment;
+ this.search = this.Url.search;
+
+ pathname = this.Url.pathname;
+ } catch (e) {
+ // Skip URL parsing
+ this.Url = undefined;
+ }
+ }
+
+ this.Path = new Path(pathname);
+ this.directory = this.Path.directory;
+ this.filename = this.Path.filename;
+ this.extension = this.Path.extension;
+
+ }
+
+ path () {
+ return this.Path;
+ };
+
+ resolve (what) {
+ var isAbsolute = (what.indexOf('://') > -1);
+ var fullpath;
+
+ if (isAbsolute) {
+ return what;
+ }
+
+ fullpath = path.resolve(this.directory, what);
+ return this.origin + fullpath;
+ };
+
+ relative (what) {
+ return path.relative(what, this.directory);
+ };
+
+ toString () {
+ return this.href;
+ };
+}
+
+export default Url
diff --git a/test/core.js b/test/core.js
index 7901601..089aa65 100644
--- a/test/core.js
+++ b/test/core.js
@@ -9,7 +9,7 @@ describe('Core', function() {
describe('Url', function () {
- var Url = require('../src/core').Url;
+ var Url = require('../src/utils/url');
it("Url()", function() {
var url = new Url("http://example.com/fred/chasen/derf.html");
@@ -61,7 +61,7 @@ describe('Core', function() {
describe('Path', function () {
- var Path = require('../src/core').Path;
+ var Path = require('../src/utils/path');
it("Path()", function() {
var path = new Path("/fred/chasen/derf.html");
diff --git a/test/epubcfi.js b/test/epubcfi.js
index 10acb05..520257b 100644
--- a/test/epubcfi.js
+++ b/test/epubcfi.js
@@ -8,13 +8,13 @@ describe('EpubCFI', function() {
var EpubCFI = require('../src/epubcfi.js');
it('parse a cfi on init', function() {
- var cfi = EpubCFI("epubcfi(/6/2[cover]!/6)");
+ var cfi = new EpubCFI("epubcfi(/6/2[cover]!/6)");
assert.equal( cfi.spinePos, 0, "spinePos is parsed as the first item" );
});
it('parse a cfi and ignore the base if present', function() {
- var cfi = EpubCFI("epubcfi(/6/2[cover]!/6)", "/6/6[end]");
+ var cfi = new EpubCFI("epubcfi(/6/2[cover]!/6)", "/6/6[end]");
assert.equal( cfi.spinePos, 0, "base is ignored and spinePos is parsed as the first item" );
});
@@ -56,9 +56,9 @@ describe('EpubCFI', function() {
describe('#toString()', function() {
it('parse a cfi and write it back', function() {
- assert.equal(EpubCFI("epubcfi(/6/2[cover]!/6)").toString(), "epubcfi(/6/2[cover]!/6)", "output cfi string is same as input" );
- assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)", "output cfi string is same as input" );
- assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)", "output cfi string is same as input" );
+ assert.equal(new EpubCFI("epubcfi(/6/2[cover]!/6)").toString(), "epubcfi(/6/2[cover]!/6)", "output cfi string is same as input" );
+ assert.equal(new EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)", "output cfi string is same as input" );
+ assert.equal(new EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)", "output cfi string is same as input" );
});
});
@@ -73,7 +73,7 @@ describe('EpubCFI', function() {
});
it('determine the type of a cfi', function() {
- var ogcfi = EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)");
+ var ogcfi = new EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)");
var cfi = new EpubCFI();
assert.equal( cfi.checkType(ogcfi), 'EpubCFI' );
diff --git a/test/locations.js b/test/locations.js
index c9c4094..1833880 100644
--- a/test/locations.js
+++ b/test/locations.js
@@ -2,12 +2,10 @@ var assert = require('assert');
describe('Locations', function() {
var Locations = require('../src/locations');
- var core = require('../src/core');
- var chapter = require('raw-loader!./fixtures/locations.xhtml');
+ var core = require('../src/utils/core');
describe('#parse', function() {
var Locations = require('../src/locations');
- var core = require('../src/core');
var chapter = require('raw-loader!./fixtures/locations.xhtml');
it('parse locations from a document', function() {
@@ -25,7 +23,6 @@ describe('Locations', function() {
var locations = new Locations();
var result = locations.parse(contents, "/6/4[chap01ref]", 100);
- console.log(result);
assert.equal(result.length, 15);
});
diff --git a/webpack.config.js b/webpack.config.js
index 64d44b3..6c792a7 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,19 +1,23 @@
var webpack = require("webpack");
var path = require('path');
+var BabiliPlugin = require("babili-webpack-plugin");
var PROD = (process.env.NODE_ENV === 'production')
+var LEGACY = (process.env.LEGACY)
var hostname = "localhost";
var port = "8080";
+var enter = LEGACY ? {
+ "epub.legacy": ["babel-polyfill", "./libs/url/url.js", "./src/epub.js"]
+ } : {
+ "epub": "./src/epub.js",
+ };
module.exports = {
- entry: {
- epub: "./src/epub.js",
- polyfills: ["./node_modules/es6-promise/dist/es6-promise.auto.js", "./libs/url/url.js"]
- },
- devtool: 'source-map',
+ entry: enter,
+ devtool: PROD ? false : 'source-map',
output: {
path: path.resolve("./dist"),
// path: "./dist",
- filename: "[name].js",
+ filename: PROD ? "[name].min.js" : "[name].js",
sourceMapFilename: "[name].js.map",
library: "ePub",
libraryTarget: "umd",
@@ -23,9 +27,9 @@ module.exports = {
"jszip": "JSZip",
"xmldom": "xmldom"
},
- plugins: [
- // new webpack.IgnorePlugin(/punycode|IPv6/),
- ],
+ plugins: PROD ? [
+ new BabiliPlugin()
+ ] : [],
resolve: {
alias: {
path: "path-webpack"
@@ -35,5 +39,24 @@ module.exports = {
host: hostname,
port: port,
inline: true
+ },
+ module: {
+ loaders: [
+ LEGACY ? {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: "babel-loader",
+ query: {
+ presets: ['es2015'],
+ plugins: [
+ "add-module-exports",
+ ]
+ }
+ } : {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: "babel-loader"
+ }
+ ]
}
}