diff --git "a/scripts/epub.orig.js" "b/scripts/epub.orig.js" new file mode 100644--- /dev/null +++ "b/scripts/epub.orig.js" @@ -0,0 +1,16784 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("xmldom"), (function webpackLoadOptionalExternalModule() { try { return require("jszip"); } catch(e) {} }())); + else if(typeof define === 'function' && define.amd) + define(["xmldom", "jszip"], factory); + else if(typeof exports === 'object') + exports["ePub"] = factory(require("xmldom"), (function webpackLoadOptionalExternalModule() { try { return require("jszip"); } catch(e) {} }())); + else + root["ePub"] = factory(root["xmldom"], root["jszip"]); +})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_16__, __WEBPACK_EXTERNAL_MODULE_68__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "/dist/"; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 25); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +exports.uuid = uuid; +exports.documentHeight = documentHeight; +exports.isElement = isElement; +exports.isNumber = isNumber; +exports.isFloat = isFloat; +exports.prefixed = prefixed; +exports.defaults = defaults; +exports.extend = extend; +exports.insert = insert; +exports.locationOf = locationOf; +exports.indexOfSorted = indexOfSorted; +exports.bounds = bounds; +exports.borders = borders; +exports.windowBounds = windowBounds; +exports.indexOfNode = indexOfNode; +exports.indexOfTextNode = indexOfTextNode; +exports.indexOfElementNode = indexOfElementNode; +exports.isXml = isXml; +exports.createBlob = createBlob; +exports.createBlobUrl = createBlobUrl; +exports.revokeBlobUrl = revokeBlobUrl; +exports.createBase64Url = createBase64Url; +exports.type = type; +exports.parse = parse; +exports.qs = qs; +exports.qsa = qsa; +exports.qsp = qsp; +exports.sprint = sprint; +exports.treeWalker = treeWalker; +exports.walk = walk; +exports.blob2base64 = blob2base64; +exports.defer = defer; +exports.querySelectorByType = querySelectorByType; +exports.findChildren = findChildren; +exports.parents = parents; +exports.filterChildren = filterChildren; +exports.getParentByTagName = getParentByTagName; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Core Utilities and Helpers + * @module Core +*/ + +/** + * Vendor prefixed requestAnimationFrame + * @returns {function} requestAnimationFrame + * @memberof Core + */ +var requestAnimationFrame = exports.requestAnimationFrame = typeof window != "undefined" ? window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame : false; +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var DOCUMENT_NODE = 9; +var _URL = typeof URL != "undefined" ? URL : typeof window != "undefined" ? window.URL || window.webkitURL || window.mozURL : undefined; + +/** + * Generates a UUID + * based on: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript + * @returns {string} uuid + * @memberof Core + */ +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; + d = Math.floor(d / 16); + return (c == "x" ? r : r & 0x7 | 0x8).toString(16); + }); + return uuid; +} + +/** + * Gets the height of a document + * @returns {number} height + * @memberof Core + */ +function documentHeight() { + return Math.max(document.documentElement.clientHeight, document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight); +} + +/** + * Checks if a node is an element + * @returns {boolean} + * @memberof Core + */ +function isElement(obj) { + return !!(obj && obj.nodeType == 1); +} + +/** + * @returns {boolean} + * @memberof Core + */ +function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} + +/** + * @returns {boolean} + * @memberof Core + */ +function isFloat(n) { + var f = parseFloat(n); + return f === n && isNumber(n) && Math.floor(f) !== n; +} + +/** + * Get a prefixed css property + * @returns {string} + * @memberof Core + */ +function prefixed(unprefixed) { + var vendors = ["Webkit", "webkit", "Moz", "O", "ms"]; + var prefixes = ["-webkit-", "-webkit-", "-moz-", "-o-", "-ms-"]; + var upper = unprefixed[0].toUpperCase() + unprefixed.slice(1); + var length = vendors.length; + + if (typeof document === "undefined" || typeof document.body.style[unprefixed] != "undefined") { + return unprefixed; + } + + for (var i = 0; i < length; i++) { + if (typeof document.body.style[vendors[i] + upper] != "undefined") { + return prefixes[i] + unprefixed; + } + } + + return unprefixed; +} + +/** + * Apply defaults to an object + * @param {object} obj + * @returns {object} + * @memberof Core + */ +function defaults(obj) { + for (var i = 1, length = arguments.length; i < length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (obj[prop] === void 0) obj[prop] = source[prop]; + } + } + return obj; +} + +/** + * Extend properties of an object + * @param {object} target + * @returns {object} + * @memberof Core + */ +function extend(target) { + var sources = [].slice.call(arguments, 1); + sources.forEach(function (source) { + if (!source) return; + Object.getOwnPropertyNames(source).forEach(function (propName) { + Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + return 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 + * @param {any} item + * @param {array} array + * @param {function} [compareFunction] + * @returns {number} location (in array) + * @memberof Core + */ +function insert(item, array, compareFunction) { + var location = locationOf(item, array, compareFunction); + array.splice(location, 0, item); + + return location; +} + +/** + * Finds where something would fit into a sorted array + * @param {any} item + * @param {array} array + * @param {function} [compareFunction] + * @param {function} [_start] + * @param {function} [_end] + * @returns {number} location (in array) + * @memberof Core + */ +function locationOf(item, array, compareFunction, _start, _end) { + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if (!compareFunction) { + compareFunction = function compareFunction(a, b) { + if (a > b) return 1; + if (a < b) return -1; + if (a == b) return 0; + }; + } + if (end - start <= 0) { + return pivot; + } + + compared = compareFunction(array[pivot], item); + if (end - start === 1) { + return compared >= 0 ? pivot : pivot + 1; + } + if (compared === 0) { + return pivot; + } + if (compared === -1) { + return locationOf(item, array, compareFunction, pivot, end); + } else { + return locationOf(item, array, compareFunction, start, pivot); + } +} + +/** + * Finds index of something in a sorted array + * Returns -1 if not found + * @param {any} item + * @param {array} array + * @param {function} [compareFunction] + * @param {function} [_start] + * @param {function} [_end] + * @returns {number} index (in array) or -1 + * @memberof Core + */ +function indexOfSorted(item, array, compareFunction, _start, _end) { + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if (!compareFunction) { + compareFunction = function compareFunction(a, b) { + if (a > b) return 1; + if (a < b) return -1; + if (a == b) return 0; + }; + } + if (end - start <= 0) { + return -1; // Not found + } + + compared = compareFunction(array[pivot], item); + if (end - start === 1) { + return compared === 0 ? pivot : -1; + } + if (compared === 0) { + return pivot; // Found + } + if (compared === -1) { + return indexOfSorted(item, array, compareFunction, pivot, end); + } else { + return indexOfSorted(item, array, compareFunction, start, pivot); + } +} +/** + * Find the bounds of an element + * taking padding and margin into account + * @param {element} el + * @returns {{ width: Number, height: Number}} + * @memberof Core + */ +function bounds(el) { + + var style = window.getComputedStyle(el); + var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + + var width = 0; + var height = 0; + + widthProps.forEach(function (prop) { + width += parseFloat(style[prop]) || 0; + }); + + heightProps.forEach(function (prop) { + height += parseFloat(style[prop]) || 0; + }); + + return { + height: height, + width: width + }; +} + +/** + * Find the bounds of an element + * taking padding, margin and borders into account + * @param {element} el + * @returns {{ width: Number, height: Number}} + * @memberof Core + */ +function borders(el) { + + var style = window.getComputedStyle(el); + var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + + var width = 0; + var height = 0; + + widthProps.forEach(function (prop) { + width += parseFloat(style[prop]) || 0; + }); + + heightProps.forEach(function (prop) { + height += parseFloat(style[prop]) || 0; + }); + + return { + height: height, + width: width + }; +} + +/** + * Find the equivelent of getBoundingClientRect of a browser window + * @returns {{ width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }} + * @memberof Core + */ +function windowBounds() { + + var width = window.innerWidth; + var height = window.innerHeight; + + return { + top: 0, + left: 0, + right: width, + bottom: height, + width: width, + height: height + }; +} + +/** + * Gets the index of a node in its parent + * @private + * @memberof Core + */ +function indexOfNode(node, typeId) { + var parent = node.parentNode; + var children = parent.childNodes; + var sib; + var index = -1; + for (var i = 0; i < children.length; i++) { + sib = children[i]; + if (sib.nodeType === typeId) { + index++; + } + if (sib == node) break; + } + + return index; +} + +/** + * Gets the index of a text node in its parent + * @param {node} textNode + * @returns {number} index + * @memberof Core + */ +function indexOfTextNode(textNode) { + return indexOfNode(textNode, TEXT_NODE); +} + +/** + * Gets the index of an element node in its parent + * @param {element} elementNode + * @returns {number} index + * @memberof Core + */ +function indexOfElementNode(elementNode) { + return indexOfNode(elementNode, ELEMENT_NODE); +} + +/** + * Check if extension is xml + * @param {string} ext + * @returns {boolean} + * @memberof Core + */ +function isXml(ext) { + return ["xml", "opf", "ncx"].indexOf(ext) > -1; +} + +/** + * Create a new blob + * @param {any} content + * @param {string} mime + * @returns {Blob} + * @memberof Core + */ +function createBlob(content, mime) { + return new Blob([content], { type: mime }); +} + +/** + * Create a new blob url + * @param {any} content + * @param {string} mime + * @returns {string} url + * @memberof Core + */ +function createBlobUrl(content, mime) { + var tempUrl; + var blob = createBlob(content, mime); + + tempUrl = _URL.createObjectURL(blob); + + return tempUrl; +} + +/** + * Remove a blob url + * @param {string} url + * @memberof Core + */ +function revokeBlobUrl(url) { + return _URL.revokeObjectURL(url); +} + +/** + * Create a new base64 encoded url + * @param {any} content + * @param {string} mime + * @returns {string} url + * @memberof Core + */ +function createBase64Url(content, mime) { + var data; + var datauri; + + if (typeof content !== "string") { + // Only handles strings + return; + } + + data = btoa(encodeURIComponent(content)); + + datauri = "data:" + mime + ";base64," + data; + + return datauri; +} + +/** + * Get type of an object + * @param {object} obj + * @returns {string} type + * @memberof Core + */ +function type(obj) { + return Object.prototype.toString.call(obj).slice(8, -1); +} + +/** + * Parse xml (or html) markup + * @param {string} markup + * @param {string} mime + * @param {boolean} forceXMLDom force using xmlDom to parse instead of native parser + * @returns {document} document + * @memberof Core + */ +function parse(markup, mime, forceXMLDom) { + var doc; + var Parser; + + if (typeof DOMParser === "undefined" || forceXMLDom) { + Parser = __webpack_require__(16).DOMParser; + } else { + Parser = DOMParser; + } + + // Remove byte order mark before parsing + // https://www.w3.org/International/questions/qa-byte-order-mark + if (markup.charCodeAt(0) === 0xFEFF) { + markup = markup.slice(1); + } + + doc = new Parser().parseFromString(markup, mime); + + return doc; +} + +/** + * querySelector polyfill + * @param {element} el + * @param {string} sel selector string + * @returns {element} element + * @memberof Core + */ +function qs(el, sel) { + var elements; + if (!el) { + throw new Error("No Element Provided"); + } + + if (typeof el.querySelector != "undefined") { + return el.querySelector(sel); + } else { + elements = el.getElementsByTagName(sel); + if (elements.length) { + return elements[0]; + } + } +} + +/** + * querySelectorAll polyfill + * @param {element} el + * @param {string} sel selector string + * @returns {element[]} elements + * @memberof Core + */ +function qsa(el, sel) { + + if (typeof el.querySelector != "undefined") { + return el.querySelectorAll(sel); + } else { + return el.getElementsByTagName(sel); + } +} + +/** + * querySelector by property + * @param {element} el + * @param {string} sel selector string + * @param {props[]} props + * @returns {element[]} elements + * @memberof Core + */ +function qsp(el, sel, props) { + var q, filtered; + if (typeof el.querySelector != "undefined") { + sel += "["; + for (var prop in props) { + sel += prop + "~='" + props[prop] + "'"; + } + sel += "]"; + return el.querySelector(sel); + } else { + q = el.getElementsByTagName(sel); + filtered = Array.prototype.slice.call(q, 0).filter(function (el) { + for (var prop in props) { + if (el.getAttribute(prop) === props[prop]) { + return true; + } + } + return false; + }); + + if (filtered) { + return filtered[0]; + } + } +} + +/** + * Sprint through all text nodes in a document + * @memberof Core + * @param {element} root element to start with + * @param {function} func function to run on each element + */ +function sprint(root, func) { + var doc = root.ownerDocument || root; + if (typeof doc.createTreeWalker !== "undefined") { + treeWalker(root, func, NodeFilter.SHOW_TEXT); + } else { + walk(root, function (node) { + if (node && node.nodeType === 3) { + // Node.TEXT_NODE + func(node); + } + }, true); + } +} + +function treeWalker(root, func, filter) { + var treeWalker = document.createTreeWalker(root, filter, null, false); + var node = void 0; + while (node = treeWalker.nextNode()) { + func(node); + } +} + +/** + * @memberof Core + * @param {node} node + * @param {callback} return false for continue,true for break inside callback + */ +function walk(node, callback) { + if (callback(node)) { + return true; + } + node = node.firstChild; + if (node) { + do { + var walked = walk(node, callback); + if (walked) { + return true; + } + node = node.nextSibling; + } while (node); + } +} + +/** + * Convert a blob to a base64 encoded string + * @param {Blog} blob + * @returns {string} + * @memberof Core + */ +function blob2base64(blob) { + return new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function () { + resolve(reader.result); + }; + }); +} + +/** + * Creates a new pending promise and provides methods to resolve or reject it. + * From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible + * @memberof Core + */ +function defer() { + var _this = this; + + /* A method to resolve the associated Promise with the value passed. + * If the promise is already settled it does nothing. + * + * @param {anything} value : This value is used to resolve the promise + * If the value is a Promise then the associated promise assumes the state + * of Promise passed as value. + */ + this.resolve = null; + + /* A method to reject the assocaited Promise with the value passed. + * If the promise is already settled it does nothing. + * + * @param {anything} reason: The reason for the rejection of the Promise. + * Generally its an Error object. If however a Promise is passed, then the Promise + * itself will be the reason for rejection no matter the state of the Promise. + */ + this.reject = null; + + this.id = uuid(); + + /* A newly created Pomise object. + * Initially in pending state. + */ + this.promise = new Promise(function (resolve, reject) { + _this.resolve = resolve; + _this.reject = reject; + }); + Object.freeze(this); +} + +/** + * querySelector with filter by epub type + * @param {element} html + * @param {string} element element type to find + * @param {string} type epub type to find + * @returns {element[]} elements + * @memberof Core + */ +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 = qsa(html, element); + for (var i = 0; i < query.length; i++) { + if (query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type || query[i].getAttribute("epub:type") === type) { + return query[i]; + } + } + } else { + return query; + } +} + +/** + * Find direct decendents of an element + * @param {element} el + * @returns {element[]} children + * @memberof Core + */ +function findChildren(el) { + var result = []; + var childNodes = el.childNodes; + for (var i = 0; i < childNodes.length; i++) { + var node = childNodes[i]; + if (node.nodeType === 1) { + result.push(node); + } + } + return result; +} + +/** + * Find all parents (ancestors) of an element + * @param {element} node + * @returns {element[]} parents + * @memberof Core + */ +function parents(node) { + var nodes = [node]; + for (; node; node = node.parentNode) { + nodes.unshift(node); + } + return nodes; +} + +/** + * Find all direct decendents of a specific type + * @param {element} el + * @param {string} nodeName + * @param {boolean} [single] + * @returns {element[]} children + * @memberof Core + */ +function filterChildren(el, nodeName, single) { + var result = []; + var childNodes = el.childNodes; + for (var i = 0; i < childNodes.length; i++) { + var node = childNodes[i]; + if (node.nodeType === 1 && node.nodeName.toLowerCase() === nodeName) { + if (single) { + return node; + } else { + result.push(node); + } + } + } + if (!single) { + return result; + } +} + +/** + * Filter all parents (ancestors) with tag name + * @param {element} node + * @param {string} tagname + * @returns {element[]} parents + * @memberof Core + */ +function getParentByTagName(node, tagname) { + var parent = void 0; + if (node === null || tagname === '') return; + parent = node.parentNode; + while (parent.nodeType === 1) { + if (parent.tagName.toLowerCase() === tagname) { + return parent; + } + parent = parent.parentNode; + } +} + +/** + * Lightweight Polyfill for DOM Range + * @class + * @memberof Core + */ + +var RangeObject = exports.RangeObject = function () { + function RangeObject() { + _classCallCheck(this, RangeObject); + + this.collapsed = false; + this.commonAncestorContainer = undefined; + this.endContainer = undefined; + this.endOffset = undefined; + this.startContainer = undefined; + this.startOffset = undefined; + } + + _createClass(RangeObject, [{ + key: "setStart", + value: function setStart(startNode, startOffset) { + this.startContainer = startNode; + this.startOffset = startOffset; + + if (!this.endContainer) { + this.collapse(true); + } else { + this.commonAncestorContainer = this._commonAncestorContainer(); + } + + this._checkCollapsed(); + } + }, { + key: "setEnd", + value: function setEnd(endNode, endOffset) { + this.endContainer = endNode; + this.endOffset = endOffset; + + if (!this.startContainer) { + this.collapse(false); + } else { + this.collapsed = false; + this.commonAncestorContainer = this._commonAncestorContainer(); + } + + this._checkCollapsed(); + } + }, { + key: "collapse", + value: function collapse(toStart) { + this.collapsed = true; + if (toStart) { + this.endContainer = this.startContainer; + this.endOffset = this.startOffset; + this.commonAncestorContainer = this.startContainer.parentNode; + } else { + this.startContainer = this.endContainer; + this.startOffset = this.endOffset; + this.commonAncestorContainer = this.endOffset.parentNode; + } + } + }, { + key: "selectNode", + value: function selectNode(referenceNode) { + var parent = referenceNode.parentNode; + var index = Array.prototype.indexOf.call(parent.childNodes, referenceNode); + this.setStart(parent, index); + this.setEnd(parent, index + 1); + } + }, { + key: "selectNodeContents", + value: function selectNodeContents(referenceNode) { + var end = referenceNode.childNodes[referenceNode.childNodes - 1]; + var endIndex = referenceNode.nodeType === 3 ? referenceNode.textContent.length : parent.childNodes.length; + this.setStart(referenceNode, 0); + this.setEnd(referenceNode, endIndex); + } + }, { + key: "_commonAncestorContainer", + value: function _commonAncestorContainer(startContainer, endContainer) { + var startParents = parents(startContainer || this.startContainer); + var endParents = parents(endContainer || this.endContainer); + + if (startParents[0] != endParents[0]) return undefined; + + for (var i = 0; i < startParents.length; i++) { + if (startParents[i] != endParents[i]) { + return startParents[i - 1]; + } + } + } + }, { + key: "_checkCollapsed", + value: function _checkCollapsed() { + if (this.startContainer === this.endContainer && this.startOffset === this.endOffset) { + this.collapsed = true; + } else { + this.collapsed = false; + } + } + }, { + key: "toString", + value: function toString() { + // TODO: implement walking between start and end to find text + } + }]); + + return RangeObject; +}(); + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var DOCUMENT_NODE = 9; + +/** + * Parsing and creation of EpubCFIs: http://www.idpf.org/epub/linking/cfi/epub-cfi.html + + * Implements: + * - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) + * - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) + + * Does Not Implement: + * - Temporal Offset (~) + * - Spatial Offset (@) + * - Temporal-Spatial Offset (~ + @) + * - Text Location Assertion ([) + * @class + @param {string | Range | Node } [cfiFrom] + @param {string | object} [base] + @param {string} [ignoreClass] class to ignore when parsing DOM +*/ + +var EpubCFI = function () { + function EpubCFI(cfiFrom, base, ignoreClass) { + _classCallCheck(this, EpubCFI); + + var type; + + this.str = ""; + + this.base = {}; + this.spinePos = 0; // For compatibility + + this.range = false; // true || false; + + 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 === "undefined" ? "undefined" : _typeof(base)) === "object" && base.steps) { + this.base = base; + } + + type = this.checkType(cfiFrom); + + if (type === "string") { + this.str = cfiFrom; + return (0, _core.extend)(this, this.parse(cfiFrom)); + } else if (type === "range") { + return (0, _core.extend)(this, this.fromRange(cfiFrom, this.base, ignoreClass)); + } else if (type === "node") { + return (0, _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"); + } + } + + /** + * Check the type of constructor input + * @private + */ + + + _createClass(EpubCFI, [{ + key: "checkType", + value: function checkType(cfi) { + + if (this.isCfiString(cfi)) { + return "string"; + // Is a range object + } else if ((typeof cfi === "undefined" ? "undefined" : _typeof(cfi)) === "object" && ((0, _core.type)(cfi) === "Range" || typeof cfi.startContainer != "undefined")) { + return "range"; + } else if ((typeof cfi === "undefined" ? "undefined" : _typeof(cfi)) === "object" && typeof cfi.nodeType != "undefined") { + // || typeof cfi === "function" + return "node"; + } else if ((typeof cfi === "undefined" ? "undefined" : _typeof(cfi)) === "object" && cfi instanceof EpubCFI) { + return "EpubCFI"; + } else { + return false; + } + } + + /** + * Parse a cfi string to a CFI object representation + * @param {string} cfiStr + * @returns {object} cfi + */ + + }, { + key: "parse", + value: function 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 }; + } + + 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; + } + }, { + key: "parseComponent", + value: function parseComponent(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; + } + }, { + key: "parseStep", + value: function 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 { + type = "text"; + index = (num - 1) / 2; + } + + return { + "type": type, + "index": index, + "id": id || null + }; + } + }, { + key: "parseTerminal", + value: function parseTerminal(termialStr) { + var characterOffset, textLocationAssertion; + var assertion = termialStr.match(/\[(.*)\]/); + + if (assertion && assertion[1]) { + characterOffset = parseInt(termialStr.split("[")[0]); + textLocationAssertion = assertion[1]; + } else { + characterOffset = parseInt(termialStr); + } + + if (!(0, _core.isNumber)(characterOffset)) { + characterOffset = null; + } + + return { + "offset": characterOffset, + "assertion": textLocationAssertion + }; + } + }, { + key: "getChapterComponent", + value: function getChapterComponent(cfiStr) { + + var indirection = cfiStr.split("!"); + + return indirection[0]; + } + }, { + key: "getPathComponent", + value: function getPathComponent(cfiStr) { + + var indirection = cfiStr.split("!"); + + if (indirection[1]) { + var ranges = indirection[1].split(","); + return ranges[0]; + } + } + }, { + key: "getRange", + value: function getRange(cfiStr) { + + var ranges = cfiStr.split(","); + + if (ranges.length === 3) { + return [ranges[1], ranges[2]]; + } + + return false; + } + }, { + key: "getCharecterOffsetComponent", + value: function getCharecterOffsetComponent(cfiStr) { + var splitStr = cfiStr.split(":"); + return splitStr[1] || ""; + } + }, { + key: "joinSteps", + value: function 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("/"); + } + }, { + key: "segmentString", + value: function 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; + } + + /** + * Convert CFI to a epubcfi(...) string + * @returns {string} epubcfi + */ + + }, { + key: "toString", + value: function toString() { + var cfiString = "epubcfi("; + + cfiString += this.segmentString(this.base); + + cfiString += "!"; + cfiString += this.segmentString(this.path); + + // Add Range, if present + if (this.range && this.start) { + cfiString += ","; + cfiString += this.segmentString(this.start); + } + + if (this.range && this.end) { + cfiString += ","; + cfiString += this.segmentString(this.end); + } + + cfiString += ")"; + + return cfiString; + } + + /** + * Compare which of two CFIs is earlier in the text + * @returns {number} First is earlier = 1, Second is earlier = -1, They are equal = 0 + */ + + }, { + key: "compare", + value: function compare(cfiOne, cfiTwo) { + var stepsA, stepsB; + var terminalA, terminalB; + + var rangeAStartSteps, rangeAEndSteps; + var rangeBEndSteps, rangeBEndSteps; + var rangeAStartTerminal, rangeAEndTerminal; + var rangeBStartTerminal, rangeBEndTerminal; + + 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; + } + }, { + key: "step", + value: function step(node) { + var nodeType = node.nodeType === TEXT_NODE ? "text" : "element"; + + return { + "id": node.id, + "tagName": node.tagName, + "type": nodeType, + "index": this.position(node) + }; + } + }, { + key: "filteredStep", + value: function 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) + }; + } + }, { + key: "pathTo", + value: function 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; + } + }, { + key: "equalStep", + value: function 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; + } + + /** + * Create a CFI object from a Range + * @param {Range} range + * @param {string | object} base + * @param {string} [ignoreClass] + * @returns {object} cfi + */ + + }, { + key: "fromRange", + value: function 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 === "undefined" ? "undefined" : _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; + } + + /** + * Create a CFI object from a Node + * @param {Node} anchor + * @param {string | object} base + * @param {string} [ignoreClass] + * @returns {object} cfi + */ + + }, { + key: "fromNode", + value: function fromNode(anchor, base, ignoreClass) { + var cfi = { + range: false, + base: {}, + path: {}, + start: null, + end: null + }; + + if (typeof base === "string") { + cfi.base = this.parseComponent(base); + cfi.spinePos = cfi.base.steps[1].index; + } else if ((typeof base === "undefined" ? "undefined" : _typeof(base)) === "object") { + cfi.base = base; + } + + cfi.path = this.pathTo(anchor, null, ignoreClass); + + return cfi; + } + }, { + key: "filter", + value: function 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; + } + } + }, { + key: "patchOffset", + value: function patchOffset(anchor, offset, ignoreClass) { + if (anchor.nodeType != TEXT_NODE) { + throw new Error("Anchor must be a text node"); + } + + 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; + } + }, { + key: "normalizedMap", + value: function normalizedMap(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; + } + }, { + key: "position", + value: function position(anchor) { + var children, index; + if (anchor.nodeType === ELEMENT_NODE) { + children = anchor.parentNode.children; + if (!children) { + children = (0, _core.findChildren)(anchor.parentNode); + } + index = Array.prototype.indexOf.call(children, anchor); + } else { + children = this.textNodes(anchor.parentNode); + index = children.indexOf(anchor); + } + + return index; + } + }, { + key: "filteredPosition", + value: function 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]; + } + }, { + key: "stepsToXpath", + value: function 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]; + } + */ + + }, { + key: "stepsToQuerySelector", + value: function 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(">"); + } + }, { + key: "textNodes", + value: function 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; + }); + } + }, { + key: "walkToNode", + value: function walkToNode(steps, _doc, ignoreClass) { + var doc = _doc || document; + var container = doc.documentElement; + var children; + var step; + var len = steps.length; + var i; + + for (i = 0; i < len; i++) { + step = steps[i]; + + if (step.type === "element") { + //better to get a container using id as some times step.index may not be correct + //For ex.https://github.com/futurepress/epub.js/issues/561 + if (step.id) { + container = doc.getElementById(step.id); + } else { + children = container.children || (0, _core.findChildren)(container); + container = children[step.index]; + } + } else if (step.type === "text") { + container = this.textNodes(container, ignoreClass)[step.index]; + } + if (!container) { + //Break the for loop as due to incorrect index we can get error if + //container is undefined so that other functionailties works fine + //like navigation + break; + } + } + + return container; + } + }, { + key: "findNode", + value: function 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; + } + }, { + key: "fixMiss", + value: function 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 child; + var len; + 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 + }; + } + + /** + * Creates a DOM range representing a CFI + * @param {document} _doc document referenced in the base + * @param {string} [ignoreClass] + * @return {Range} + */ + + }, { + key: "toRange", + value: function toRange(_doc, ignoreClass) { + var doc = _doc || document; + var range; + var start, end, startContainer, endContainer; + var cfi = this; + var startSteps, endSteps; + var needsIgnoring = ignoreClass ? doc.querySelector("." + ignoreClass) != null : false; + var missed; + + if (typeof doc.createRange !== "undefined") { + range = doc.createRange(); + } else { + range = new _core.RangeObject(); + } + + 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 { + console.log("No startContainer found for", this.toString()); + // 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; + } + + /** + * Check if a string is wrapped with "epubcfi()" + * @param {string} str + * @returns {boolean} + */ + + }, { + key: "isCfiString", + value: function isCfiString(str) { + if (typeof str === "string" && str.indexOf("epubcfi(") === 0 && str[str.length - 1] === ")") { + return true; + } + + return false; + } + }, { + key: "generateChapterComponent", + value: function generateChapterComponent(_spineNodeIndex, _pos, id) { + var pos = parseInt(_pos), + spineNodeIndex = (_spineNodeIndex + 1) * 2, + cfi = "/" + spineNodeIndex + "/"; + + cfi += (pos + 1) * 2; + + if (id) { + cfi += "[" + id + "]"; + } + + return cfi; + } + + /** + * Collapse a CFI Range to a single CFI Position + * @param {boolean} [toStart=false] + */ + + }, { + key: "collapse", + value: function collapse(toStart) { + if (!this.range) { + return; + } + + this.range = false; + + if (toStart) { + this.path.steps = this.path.steps.concat(this.start.steps); + this.path.terminal = this.start.terminal; + } else { + this.path.steps = this.path.steps.concat(this.end.steps); + this.path.terminal = this.end.terminal; + } + } + }]); + + return EpubCFI; +}(); + +exports.default = EpubCFI; +module.exports = exports["default"]; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var d = __webpack_require__(27) + , callable = __webpack_require__(41) + + , apply = Function.prototype.apply, call = Function.prototype.call + , create = Object.create, defineProperty = Object.defineProperty + , defineProperties = Object.defineProperties + , hasOwnProperty = Object.prototype.hasOwnProperty + , descriptor = { configurable: true, enumerable: false, writable: true } + + , on, once, off, emit, methods, descriptors, base; + +on = function (type, listener) { + var data; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) { + data = descriptor.value = create(null); + defineProperty(this, '__ee__', descriptor); + descriptor.value = null; + } else { + data = this.__ee__; + } + if (!data[type]) data[type] = listener; + else if (typeof data[type] === 'object') data[type].push(listener); + else data[type] = [data[type], listener]; + + return this; +}; + +once = function (type, listener) { + var once, self; + + callable(listener); + self = this; + on.call(this, type, once = function () { + off.call(self, type, once); + apply.call(listener, this, arguments); + }); + + once.__eeOnceListener__ = listener; + return this; +}; + +off = function (type, listener) { + var data, listeners, candidate, i; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) return this; + data = this.__ee__; + if (!data[type]) return this; + listeners = data[type]; + + if (typeof listeners === 'object') { + for (i = 0; (candidate = listeners[i]); ++i) { + if ((candidate === listener) || + (candidate.__eeOnceListener__ === listener)) { + if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; + else listeners.splice(i, 1); + } + } + } else { + if ((listeners === listener) || + (listeners.__eeOnceListener__ === listener)) { + delete data[type]; + } + } + + return this; +}; + +emit = function (type) { + var i, l, listener, listeners, args; + + if (!hasOwnProperty.call(this, '__ee__')) return; + listeners = this.__ee__[type]; + if (!listeners) return; + + if (typeof listeners === 'object') { + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; + + listeners = listeners.slice(); + for (i = 0; (listener = listeners[i]); ++i) { + apply.call(listener, this, args); + } + } else { + switch (arguments.length) { + case 1: + call.call(listeners, this); + break; + case 2: + call.call(listeners, this, arguments[1]); + break; + case 3: + call.call(listeners, this, arguments[1], arguments[2]); + break; + default: + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) { + args[i - 1] = arguments[i]; + } + apply.call(listeners, this, args); + } + } +}; + +methods = { + on: on, + once: once, + off: off, + emit: emit +}; + +descriptors = { + on: d(on), + once: d(once), + off: d(off), + emit: d(emit) +}; + +base = defineProperties({}, descriptors); + +module.exports = exports = function (o) { + return (o == null) ? create(base) : defineProperties(Object(o), descriptors); +}; +exports.methods = methods; + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +// Dom events to listen for +var DOM_EVENTS = exports.DOM_EVENTS = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + +var EVENTS = exports.EVENTS = { + BOOK: { + OPEN_FAILED: "openFailed" + }, + CONTENTS: { + EXPAND: "expand", + RESIZE: "resize", + SELECTED: "selected", + SELECTED_RANGE: "selectedRange", + LINK_CLICKED: "linkClicked" + }, + LOCATIONS: { + CHANGED: "changed" + }, + MANAGERS: { + RESIZE: "resize", + RESIZED: "resized", + ORIENTATION_CHANGE: "orientationchange", + ADDED: "added", + SCROLL: "scroll", + SCROLLED: "scrolled" + }, + VIEWS: { + AXIS: "axis", + LOAD_ERROR: "loaderror", + RENDERED: "rendered", + RESIZED: "resized", + DISPLAYED: "displayed", + SHOWN: "shown", + HIDDEN: "hidden", + MARK_CLICKED: "markClicked" + }, + RENDITION: { + STARTED: "started", + ATTACHED: "attached", + DISPLAYED: "displayed", + DISPLAY_ERROR: "displayerror", + RENDERED: "rendered", + REMOVED: "removed", + RESIZED: "resized", + ORIENTATION_CHANGE: "orientationchange", + LOCATION_CHANGED: "locationChanged", + RELOCATED: "relocated", + MARK_CLICKED: "markClicked", + SELECTED: "selected", + LAYOUT: "layout" + }, + LAYOUT: { + UPDATED: "updated" + } +}; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _pathWebpack = __webpack_require__(6); + +var _pathWebpack2 = _interopRequireDefault(_pathWebpack); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Creates a Path object for parsing and manipulation of a path strings + * + * Uses a polyfill for Nodejs path: https://nodejs.org/api/path.html + * @param {string} pathString a url string (relative or absolute) + * @class + */ +var Path = function () { + function Path(pathString) { + _classCallCheck(this, Path); + + 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 the path: https://nodejs.org/api/path.html#path_path_parse_path + * @param {string} what + * @returns {object} + */ + + + _createClass(Path, [{ + key: "parse", + value: function parse(what) { + return _pathWebpack2.default.parse(what); + } + + /** + * @param {string} what + * @returns {boolean} + */ + + }, { + key: "isAbsolute", + value: function isAbsolute(what) { + return _pathWebpack2.default.isAbsolute(what || this.path); + } + + /** + * Check if path ends with a directory + * @param {string} what + * @returns {boolean} + */ + + }, { + key: "isDirectory", + value: function isDirectory(what) { + return what.charAt(what.length - 1) === "/"; + } + + /** + * Resolve a path against the directory of the Path + * + * https://nodejs.org/api/path.html#path_path_resolve_paths + * @param {string} what + * @returns {string} resolved + */ + + }, { + key: "resolve", + value: function resolve(what) { + return _pathWebpack2.default.resolve(this.directory, what); + } + + /** + * Resolve a path relative to the directory of the Path + * + * https://nodejs.org/api/path.html#path_path_relative_from_to + * @param {string} what + * @returns {string} relative + */ + + }, { + key: "relative", + value: function relative(what) { + return _pathWebpack2.default.relative(this.directory, what); + } + }, { + key: "splitPath", + value: function splitPath(filename) { + return this.splitPathRe.exec(filename).slice(1); + } + + /** + * Return the path string + * @returns {string} path + */ + + }, { + key: "toString", + value: function toString() { + return this.path; + } + }]); + + return Path; +}(); + +exports.default = Path; +module.exports = exports["default"]; + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +var _pathWebpack = __webpack_require__(6); + +var _pathWebpack2 = _interopRequireDefault(_pathWebpack); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * creates a Url object for parsing and manipulation of a url string + * @param {string} urlString a url string (relative or absolute) + * @param {string} [baseString] optional base for the url, + * default to window.location.href + */ +var Url = function () { + function Url(urlString, baseString) { + _classCallCheck(this, Url); + + var absolute = urlString.indexOf("://") > -1; + var pathname = urlString; + var basePath; + + this.Url = undefined; + this.href = urlString; + this.protocol = ""; + this.origin = ""; + this.hash = ""; + this.hash = ""; + this.search = ""; + this.base = baseString; + + if (!absolute && baseString !== false && typeof baseString !== "string" && window && window.location) { + this.base = 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.hash = this.Url.hash; + this.search = this.Url.search; + + pathname = this.Url.pathname; + } catch (e) { + // Skip URL parsing + this.Url = undefined; + // resolve the pathname from the base + if (this.base) { + basePath = new _path2.default(this.base); + pathname = basePath.resolve(pathname); + } + } + } + + this.Path = new _path2.default(pathname); + + this.directory = this.Path.directory; + this.filename = this.Path.filename; + this.extension = this.Path.extension; + } + + /** + * @returns {Path} + */ + + + _createClass(Url, [{ + key: "path", + value: function path() { + return this.Path; + } + + /** + * Resolves a relative path to a absolute url + * @returns {string} url + */ + + }, { + key: "resolve", + value: function resolve(what) { + var isAbsolute = what.indexOf("://") > -1; + var fullpath; + + if (isAbsolute) { + return what; + } + + fullpath = _pathWebpack2.default.resolve(this.directory, what); + return this.origin + fullpath; + } + + /** + * Resolve a path relative to the url + * @returns {string} path + */ + + }, { + key: "relative", + value: function relative(what) { + return _pathWebpack2.default.relative(what, this.directory); + } + + /** + * @returns {string} + */ + + }, { + key: "toString", + value: function toString() { + return this.href; + } + }]); + + return Url; +}(); + +exports.default = Url; +module.exports = exports["default"]; + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +if (!process) { + var process = { + "cwd" : function () { return '/' } + }; +} + +function assertPath(path) { + if (typeof path !== 'string') { + throw new TypeError('Path must be a string. Received ' + path); + } +} + +// Resolves . and .. elements in a path with directory names +function normalizeStringPosix(path, allowAboveRoot) { + var res = ''; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) + code = path.charCodeAt(i); + else if (code === 47/*/*/) + break; + else + code = 47/*/*/; + if (code === 47/*/*/) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || + res.charCodeAt(res.length - 1) !== 46/*.*/ || + res.charCodeAt(res.length - 2) !== 46/*.*/) { + if (res.length > 2) { + var start = res.length - 1; + var j = start; + for (; j >= 0; --j) { + if (res.charCodeAt(j) === 47/*/*/) + break; + } + if (j !== start) { + if (j === -1) + res = ''; + else + res = res.slice(0, j); + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) + res += '/..'; + else + res = '..'; + } + } else { + if (res.length > 0) + res += '/' + path.slice(lastSlash + 1, i); + else + res = path.slice(lastSlash + 1, i); + } + lastSlash = i; + dots = 0; + } else if (code === 46/*.*/ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function _format(sep, pathObject) { + var dir = pathObject.dir || pathObject.root; + var base = pathObject.base || + ((pathObject.name || '') + (pathObject.ext || '')); + if (!dir) { + return base; + } + if (dir === pathObject.root) { + return dir + base; + } + return dir + sep + base; +} + +var posix = { + // path.resolve([from ...], to) + resolve: function resolve() { + var resolvedPath = ''; + var resolvedAbsolute = false; + var cwd; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path; + if (i >= 0) + path = arguments[i]; + else { + if (cwd === undefined) + cwd = process.cwd(); + path = cwd; + } + + assertPath(path); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charCodeAt(0) === 47/*/*/; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute); + + if (resolvedAbsolute) { + if (resolvedPath.length > 0) + return '/' + resolvedPath; + else + return '/'; + } else if (resolvedPath.length > 0) { + return resolvedPath; + } else { + return '.'; + } + }, + + + normalize: function normalize(path) { + assertPath(path); + + if (path.length === 0) + return '.'; + + var isAbsolute = path.charCodeAt(0) === 47/*/*/; + var trailingSeparator = path.charCodeAt(path.length - 1) === 47/*/*/; + + // Normalize the path + path = normalizeStringPosix(path, !isAbsolute); + + if (path.length === 0 && !isAbsolute) + path = '.'; + if (path.length > 0 && trailingSeparator) + path += '/'; + + if (isAbsolute) + return '/' + path; + return path; + }, + + + isAbsolute: function isAbsolute(path) { + assertPath(path); + return path.length > 0 && path.charCodeAt(0) === 47/*/*/; + }, + + + join: function join() { + if (arguments.length === 0) + return '.'; + var joined; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + assertPath(arg); + if (arg.length > 0) { + if (joined === undefined) + joined = arg; + else + joined += '/' + arg; + } + } + if (joined === undefined) + return '.'; + return posix.normalize(joined); + }, + + + relative: function relative(from, to) { + assertPath(from); + assertPath(to); + + if (from === to) + return ''; + + from = posix.resolve(from); + to = posix.resolve(to); + + if (from === to) + return ''; + + // Trim any leading backslashes + var fromStart = 1; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== 47/*/*/) + break; + } + var fromEnd = from.length; + var fromLen = (fromEnd - fromStart); + + // Trim any leading backslashes + var toStart = 1; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== 47/*/*/) + break; + } + var toEnd = to.length; + var toLen = (toEnd - toStart); + + // Compare paths to find the longest common path from root + var length = (fromLen < toLen ? fromLen : toLen); + var lastCommonSep = -1; + var i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === 47/*/*/) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } else if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === 47/*/*/) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + break; + } + var fromCode = from.charCodeAt(fromStart + i); + var toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) + break; + else if (fromCode === 47/*/*/) + lastCommonSep = i; + } + + var out = ''; + // Generate the relative path based on the path difference between `to` + // and `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === 47/*/*/) { + if (out.length === 0) + out += '..'; + else + out += '/..'; + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) + return out + to.slice(toStart + lastCommonSep); + else { + toStart += lastCommonSep; + if (to.charCodeAt(toStart) === 47/*/*/) + ++toStart; + return to.slice(toStart); + } + }, + + + _makeLong: function _makeLong(path) { + return path; + }, + + + dirname: function dirname(path) { + assertPath(path); + if (path.length === 0) + return '.'; + var code = path.charCodeAt(0); + var hasRoot = (code === 47/*/*/); + var end = -1; + var matchedSlash = true; + for (var i = path.length - 1; i >= 1; --i) { + code = path.charCodeAt(i); + if (code === 47/*/*/) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) + return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) + return '//'; + return path.slice(0, end); + }, + + + basename: function basename(path, ext) { + if (ext !== undefined && typeof ext !== 'string') + throw new TypeError('"ext" argument must be a string'); + assertPath(path); + + var start = 0; + var end = -1; + var matchedSlash = true; + var i; + + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) + return ''; + var extIdx = ext.length - 1; + var firstNonSlashEnd = -1; + for (i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47/*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) + end = firstNonSlashEnd; + else if (end === -1) + end = path.length; + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === 47/*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) + return ''; + return path.slice(start, end); + } + }, + + + extname: function extname(path) { + assertPath(path); + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + for (var i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47/*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46/*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + return ''; + } + return path.slice(startDot, end); + }, + + + format: function format(pathObject) { + if (pathObject === null || typeof pathObject !== 'object') { + throw new TypeError( + 'Parameter "pathObject" must be an object, not ' + typeof(pathObject) + ); + } + return _format('/', pathObject); + }, + + + parse: function parse(path) { + assertPath(path); + + var ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) + return ret; + var code = path.charCodeAt(0); + var isAbsolute = (code === 47/*/*/); + var start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + var i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + code = path.charCodeAt(i); + if (code === 47/*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46/*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) + ret.base = ret.name = path.slice(1, end); + else + ret.base = ret.name = path.slice(startPart, end); + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path.slice(1, startDot); + ret.base = path.slice(1, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + } + ret.ext = path.slice(startDot, end); + } + + if (startPart > 0) + ret.dir = path.slice(0, startPart - 1); + else if (isAbsolute) + ret.dir = '/'; + + return ret; + }, + + + sep: '/', + delimiter: ':', + posix: null +}; + + +module.exports = posix; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.replaceBase = replaceBase; +exports.replaceCanonical = replaceCanonical; +exports.replaceMeta = replaceMeta; +exports.replaceLinks = replaceLinks; +exports.substitute = substitute; + +var _core = __webpack_require__(0); + +var _url = __webpack_require__(5); + +var _url2 = _interopRequireDefault(_url); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function replaceBase(doc, section) { + var base; + var head; + var url = section.url; + var absolute = url.indexOf("://") > -1; + + if (!doc) { + return; + } + + head = (0, _core.qs)(doc, "head"); + base = (0, _core.qs)(head, "base"); + + if (!base) { + base = doc.createElement("base"); + head.insertBefore(base, head.firstChild); + } + + // Fix for Safari crashing if the url doesn't have an origin + if (!absolute && window && window.location) { + url = window.location.origin + url; + } + + base.setAttribute("href", url); +} + +function replaceCanonical(doc, section) { + var head; + var link; + var url = section.canonical; + + if (!doc) { + return; + } + + head = (0, _core.qs)(doc, "head"); + link = (0, _core.qs)(head, "link[rel='canonical']"); + + if (link) { + link.setAttribute("href", url); + } else { + link = doc.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", url); + head.appendChild(link); + } +} + +function replaceMeta(doc, section) { + var head; + var meta; + var id = section.idref; + if (!doc) { + return; + } + + head = (0, _core.qs)(doc, "head"); + meta = (0, _core.qs)(head, "link[property='dc.identifier']"); + + if (meta) { + meta.setAttribute("content", id); + } else { + meta = doc.createElement("meta"); + meta.setAttribute("name", "dc.identifier"); + meta.setAttribute("content", id); + head.appendChild(meta); + } +} + +// TODO: move me to Contents +function replaceLinks(contents, fn) { + + var links = contents.querySelectorAll("a[href]"); + + if (!links.length) { + return; + } + + var base = (0, _core.qs)(contents.ownerDocument, "base"); + var location = base ? base.getAttribute("href") : undefined; + var replaceLink = function (link) { + var href = link.getAttribute("href"); + + if (href.indexOf("mailto:") === 0) { + return; + } + + var absolute = href.indexOf("://") > -1; + var linkUrl = new _url2.default(href, location); + + if (absolute) { + + link.setAttribute("target", "_blank"); + } else { + link.onclick = function () { + + if (linkUrl && linkUrl.hash) { + fn(linkUrl.Path.path + linkUrl.hash); + } else if (linkUrl) { + fn(linkUrl.Path.path); + } else { + fn(href); + } + + return false; + }; + } + }.bind(this); + + for (var i = 0; i < links.length; i++) { + replaceLink(links[i]); + } +} + +function substitute(content, urls, replacements) { + urls.forEach(function (url, i) { + if (url && replacements[i]) { + content = content.replace(new RegExp(url, "g"), replacements[i]); + } + }); + return content; +} + +/***/ }), +/* 8 */ +/***/ (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; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _undefined = __webpack_require__(34)(); // Support ES3 engines + +module.exports = function (val) { + return (val !== _undefined) && (val !== null); +}; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Hooks allow for injecting functions that must all complete in order before finishing + * They will execute in parallel but all must finish before continuing + * Functions may return a promise if they are asycn. + * @param {any} context scope of this + * @example this.content = new EPUBJS.Hook(this); + */ +var Hook = function () { + function Hook(context) { + _classCallCheck(this, Hook); + + this.context = context || this; + this.hooks = []; + } + + /** + * Adds a function to be run before a hook completes + * @example this.content.register(function(){...}); + */ + + + _createClass(Hook, [{ + key: "register", + value: 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(){...}); + */ + + }, { + key: "trigger", + value: function trigger() { + var args = arguments; + var context = this.context; + var promises = []; + + this.hooks.forEach(function (task) { + 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 + }); + + return Promise.all(promises); + } + + // Adds a function to be run before a hook completes + + }, { + key: "list", + value: function list() { + return this.hooks; + } + }, { + key: "clear", + value: function clear() { + return this.hooks = []; + } + }]); + + return Hook; +}(); + +exports.default = Hook; +module.exports = exports["default"]; + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _core = __webpack_require__(0); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +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 deferred = new _core.defer(); + + var xhr = new XMLHttpRequest(); + + //-- Check from PDF.js: + // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js + var xhrPrototype = XMLHttpRequest.prototype; + + var header; + + if (!("overrideMimeType" in xhrPrototype)) { + // IE10 might have response, but not overrideMimeType + Object.defineProperty(xhrPrototype, "overrideMimeType", { + value: function xmlHttpRequestOverrideMimeType() {} + }); + } + + if (withCredentials) { + xhr.withCredentials = true; + } + + xhr.onreadystatechange = handler; + xhr.onerror = err; + + xhr.open("GET", url, true); + + for (header in headers) { + xhr.setRequestHeader(header, headers[header]); + } + + if (type == "json") { + xhr.setRequestHeader("Accept", "application/json"); + } + + // If type isn"t set, determine it from the file extension + if (!type) { + type = new _path2.default(url).extension; + } + + if (type == "blob") { + xhr.responseType = BLOB_RESPONSE; + } + + if ((0, _core.isXml)(type)) { + // xhr.responseType = "document"; + xhr.overrideMimeType("text/xml"); // for OPF parsing + } + + if (type == "xhtml") { + // xhr.responseType = "document"; + } + + if (type == "html" || type == "htm") { + // xhr.responseType = "document"; + } + + if (type == "binary") { + xhr.responseType = "arraybuffer"; + } + + xhr.send(); + + function err(e) { + deferred.reject(e); + } + + function handler() { + if (this.readyState === XMLHttpRequest.DONE) { + var responseXML = false; + + if (this.responseType === "" || this.responseType === "document") { + responseXML = this.responseXML; + } + + if (this.status === 200 || responseXML) { + //-- Firefox is reporting 0 for blob urls + var r; + + if (!this.response && !responseXML) { + deferred.reject({ + status: this.status, + message: "Empty Response", + stack: new Error().stack + }); + return deferred.promise; + } + + if (this.status === 403) { + deferred.reject({ + status: this.status, + response: this.response, + message: "Forbidden", + stack: new Error().stack + }); + return deferred.promise; + } + if (responseXML) { + r = this.responseXML; + } else if ((0, _core.isXml)(type)) { + // xhr.overrideMimeType("text/xml"); // for OPF parsing + // If this.responseXML wasn't set, try to parse using a DOMParser from text + r = (0, _core.parse)(this.response, "text/xml"); + } else if (type == "xhtml") { + r = (0, _core.parse)(this.response, "application/xhtml+xml"); + } else if (type == "html" || type == "htm") { + r = (0, _core.parse)(this.response, "text/html"); + } else if (type == "json") { + r = JSON.parse(this.response); + } else if (type == "blob") { + + if (supportsURL) { + r = this.response; + } else { + //-- Safari doesn't support responseType blob, so create a blob from arraybuffer + r = new Blob([this.response]); + } + } else { + r = this.response; + } + + deferred.resolve(r); + } else { + + deferred.reject({ + status: this.status, + message: this.response, + stack: new Error().stack + }); + } + } + } + + return deferred.promise; +} + +exports.default = request; +module.exports = exports["default"]; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Task = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Queue for handling tasks one at a time + * @class + * @param {scope} context what this will resolve to in the tasks + */ +var Queue = function () { + function Queue(context) { + _classCallCheck(this, Queue); + + this._q = []; + this.context = context; + this.tick = _core.requestAnimationFrame; + this.running = false; + this.paused = false; + } + + /** + * Add an item to the queue + * @return {Promise} + */ + + + _createClass(Queue, [{ + key: "enqueue", + value: function 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) { + throw new Error("No Task Provided"); + } + + if (typeof task === "function") { + + deferred = new _core.defer(); + promise = deferred.promise; + + queued = { + "task": task, + "args": args, + //"context" : context, + "deferred": deferred, + "promise": promise + }; + } else { + // Task is a promise + queued = { + "promise": task + }; + } + + 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(); + } + + return queued.promise; + } + + /** + * Run one item + * @return {Promise} + */ + + }, { + key: "dequeue", + value: function dequeue() { + var inwait, task, result; + + if (this._q.length && !this.paused) { + inwait = this._q.shift(); + task = inwait.task; + if (task) { + // console.log(task) + + 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); + }.bind(this), function () { + 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 { + inwait = new _core.defer(); + inwait.deferred.resolve(); + return inwait.promise; + } + } + + // Run All Immediately + + }, { + key: "dump", + value: function dump() { + while (this._q.length) { + this.dequeue(); + } + } + + /** + * Run all tasks sequentially, at convince + * @return {Promise} + */ + + }, { + key: "run", + value: function run() { + var _this = this; + + 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; + } + }); + + // Unpause + if (this.paused == true) { + this.paused = false; + } + + return this.defered.promise; + } + + /** + * Flush all, as quickly as possible + * @return {Promise} + */ + + }, { + key: "flush", + value: function 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 + */ + + }, { + key: "clear", + value: function clear() { + this._q = []; + } + + /** + * Get the number of tasks in the queue + * @return {int} tasks + */ + + }, { + key: "length", + value: function length() { + return this._q.length; + } + + /** + * Pause a running queue + */ + + }, { + key: "pause", + value: function pause() { + this.paused = true; + } + + /** + * End the queue + */ + + }, { + key: "stop", + value: function stop() { + this._q = []; + this.running = false; + this.paused = true; + } + }]); + + return Queue; +}(); + +/** + * Create a new task from a callback + * @class + * @private + * @param {function} task + * @param {array} args + * @param {scope} context + * @return {function} task + */ + + +var Task = function Task(task, args, context) { + _classCallCheck(this, Task); + + return function () { + var _this2 = this; + + var toApply = arguments || []; + + return new Promise(function (resolve, reject) { + var callback = function callback(value, err) { + if (!value && err) { + reject(err); + } else { + resolve(value); + } + }; + // Add the callback to the arguments list + toApply.push(callback); + + // Apply all arguments to the functions + task.apply(context || _this2, toApply); + }); + }; +}; + +exports.default = Queue; +exports.Task = Task; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _core = __webpack_require__(0); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _mapping = __webpack_require__(19); + +var _mapping2 = _interopRequireDefault(_mapping); + +var _replacements = __webpack_require__(7); + +var _constants = __webpack_require__(3); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var isChrome = /Chrome/.test(navigator.userAgent); +var isWebkit = !isChrome && /AppleWebKit/.test(navigator.userAgent); + +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; + +/** + * Handles DOM manipulation, queries and events for View contents + * @class + * @param {document} doc Document + * @param {element} content Parent Element (typically Body) + * @param {string} cfiBase Section component of CFIs + * @param {number} sectionIndex Index in Spine of Conntent's Section + */ + +var Contents = function () { + function Contents(doc, content, cfiBase, sectionIndex) { + _classCallCheck(this, Contents); + + // Blank Cfi for Parsing + this.epubcfi = new _epubcfi2.default(); + + this.document = doc; + this.documentElement = this.document.documentElement; + this.content = content || this.document.body; + this.window = this.document.defaultView; + + this._size = { + width: 0, + height: 0 + }; + + this.sectionIndex = sectionIndex || 0; + this.cfiBase = cfiBase || ""; + + this.epubReadingSystem("epub.js", ePub.VERSION); + + this.listeners(); + } + + /** + * Get DOM events that are listened for and passed along + */ + + + _createClass(Contents, [{ + key: "width", + + + /** + * Get or Set width + * @param {number} [w] + * @returns {number} width + */ + value: function width(w) { + // var frame = this.documentElement; + var frame = this.content; + + if (w && (0, _core.isNumber)(w)) { + w = w + "px"; + } + + if (w) { + frame.style.width = w; + // this.content.style.width = w; + } + + return this.window.getComputedStyle(frame)["width"]; + } + + /** + * Get or Set height + * @param {number} [h] + * @returns {number} height + */ + + }, { + key: "height", + value: function height(h) { + // var frame = this.documentElement; + var frame = this.content; + + if (h && (0, _core.isNumber)(h)) { + h = h + "px"; + } + + if (h) { + frame.style.height = h; + // this.content.style.height = h; + } + + return this.window.getComputedStyle(frame)["height"]; + } + + /** + * Get or Set width of the contents + * @param {number} [w] + * @returns {number} width + */ + + }, { + key: "contentWidth", + value: function contentWidth(w) { + + var content = this.content || this.document.body; + + if (w && (0, _core.isNumber)(w)) { + w = w + "px"; + } + + if (w) { + content.style.width = w; + } + + return this.window.getComputedStyle(content)["width"]; + } + + /** + * Get or Set height of the contents + * @param {number} [h] + * @returns {number} height + */ + + }, { + key: "contentHeight", + value: function contentHeight(h) { + + var content = this.content || this.document.body; + + if (h && (0, _core.isNumber)(h)) { + h = h + "px"; + } + + if (h) { + content.style.height = h; + } + + return this.window.getComputedStyle(content)["height"]; + } + + /** + * Get the width of the text using Range + * @returns {number} width + */ + + }, { + key: "textWidth", + value: function textWidth() { + var width = void 0; + var range = this.document.createRange(); + var content = this.content || this.document.body; + var border = (0, _core.borders)(content); + + // Select the contents of frame + range.selectNodeContents(content); + + // get the width of the text content + width = range.getBoundingClientRect().width; + + if (border && border.width) { + width += border.width; + } + + return Math.round(width); + } + + /** + * Get the height of the text using Range + * @returns {number} height + */ + + }, { + key: "textHeight", + value: function textHeight() { + var height = void 0; + var range = this.document.createRange(); + var content = this.content || this.document.body; + var border = (0, _core.borders)(content); + + range.selectNodeContents(content); + + height = range.getBoundingClientRect().height; + + if (height && border.height) { + height += border.height; + } + + return Math.round(height); + } + + /** + * Get documentElement scrollWidth + * @returns {number} width + */ + + }, { + key: "scrollWidth", + value: function scrollWidth() { + var width = this.documentElement.scrollWidth; + + return width; + } + + /** + * Get documentElement scrollHeight + * @returns {number} height + */ + + }, { + key: "scrollHeight", + value: function scrollHeight() { + var height = this.documentElement.scrollHeight; + + return height; + } + + /** + * Set overflow css style of the contents + * @param {string} [overflow] + */ + + }, { + key: "overflow", + value: function overflow(_overflow) { + + if (_overflow) { + this.documentElement.style.overflow = _overflow; + } + + return this.window.getComputedStyle(this.documentElement)["overflow"]; + } + + /** + * Set overflowX css style of the documentElement + * @param {string} [overflow] + */ + + }, { + key: "overflowX", + value: function overflowX(overflow) { + + if (overflow) { + this.documentElement.style.overflowX = overflow; + } + + return this.window.getComputedStyle(this.documentElement)["overflowX"]; + } + + /** + * Set overflowY css style of the documentElement + * @param {string} [overflow] + */ + + }, { + key: "overflowY", + value: function overflowY(overflow) { + + if (overflow) { + this.documentElement.style.overflowY = overflow; + } + + return this.window.getComputedStyle(this.documentElement)["overflowY"]; + } + + /** + * Set Css styles on the contents element (typically Body) + * @param {string} property + * @param {string} value + * @param {boolean} [priority] set as "important" + */ + + }, { + key: "css", + value: function css(property, value, priority) { + var content = this.content || this.document.body; + + if (value) { + content.style.setProperty(property, value, priority ? "important" : ""); + } + + return this.window.getComputedStyle(content)[property]; + } + + /** + * Get or Set the viewport element + * @param {object} [options] + * @param {string} [options.width] + * @param {string} [options.height] + * @param {string} [options.scale] + * @param {string} [options.minimum] + * @param {string} [options.maximum] + * @param {string} [options.scalable] + */ + + }, { + key: "viewport", + value: function viewport(options) { + var _width, _height, _scale, _minimum, _maximum, _scalable; + // var width, height, scale, minimum, maximum, scalable; + var $viewport = this.document.querySelector("meta[name='viewport']"); + var parsed = { + "width": undefined, + "height": undefined, + "scale": undefined, + "minimum": undefined, + "maximum": undefined, + "scalable": undefined + }; + var newContent = []; + var settings = {}; + + /* + * check for the viewport size + * + */ + if ($viewport && $viewport.hasAttribute("content")) { + var content = $viewport.getAttribute("content"); + var _width2 = content.match(/width\s*=\s*([^,]*)/); + var _height2 = content.match(/height\s*=\s*([^,]*)/); + var _scale2 = content.match(/initial-scale\s*=\s*([^,]*)/); + var _minimum2 = content.match(/minimum-scale\s*=\s*([^,]*)/); + var _maximum2 = content.match(/maximum-scale\s*=\s*([^,]*)/); + var _scalable2 = content.match(/user-scalable\s*=\s*([^,]*)/); + + if (_width2 && _width2.length && typeof _width2[1] !== "undefined") { + parsed.width = _width2[1]; + } + if (_height2 && _height2.length && typeof _height2[1] !== "undefined") { + parsed.height = _height2[1]; + } + if (_scale2 && _scale2.length && typeof _scale2[1] !== "undefined") { + parsed.scale = _scale2[1]; + } + if (_minimum2 && _minimum2.length && typeof _minimum2[1] !== "undefined") { + parsed.minimum = _minimum2[1]; + } + if (_maximum2 && _maximum2.length && typeof _maximum2[1] !== "undefined") { + parsed.maximum = _maximum2[1]; + } + if (_scalable2 && _scalable2.length && typeof _scalable2[1] !== "undefined") { + parsed.scalable = _scalable2[1]; + } + } + + settings = (0, _core.defaults)(options || {}, parsed); + + if (options) { + if (settings.width) { + newContent.push("width=" + settings.width); + } + + if (settings.height) { + newContent.push("height=" + settings.height); + } + + if (settings.scale) { + newContent.push("initial-scale=" + settings.scale); + } + + if (settings.scalable === "no") { + newContent.push("minimum-scale=" + settings.scale); + newContent.push("maximum-scale=" + settings.scale); + newContent.push("user-scalable=" + settings.scalable); + } else { + + if (settings.scalable) { + newContent.push("user-scalable=" + settings.scalable); + } + + if (settings.minimum) { + newContent.push("minimum-scale=" + settings.minimum); + } + + if (settings.maximum) { + newContent.push("minimum-scale=" + settings.maximum); + } + } + + if (!$viewport) { + $viewport = this.document.createElement("meta"); + $viewport.setAttribute("name", "viewport"); + this.document.querySelector("head").appendChild($viewport); + } + + $viewport.setAttribute("content", newContent.join(", ")); + + this.window.scrollTo(0, 0); + } + + return settings; + } + + /** + * Event emitter for when the contents has expanded + * @private + */ + + }, { + key: "expand", + value: function expand() { + this.emit(_constants.EVENTS.CONTENTS.EXPAND); + } + + /** + * Add DOM listeners + * @private + */ + + }, { + key: "listeners", + value: function listeners() { + + this.imageLoadListeners(); + + this.mediaQueryListeners(); + + // this.fontLoadListeners(); + + this.addEventListeners(); + + this.addSelectionListeners(); + + // this.transitionListeners(); + + this.resizeListeners(); + + // this.resizeObservers(); + + this.linksHandler(); + } + + /** + * Remove DOM listeners + * @private + */ + + }, { + key: "removeListeners", + value: function removeListeners() { + + this.removeEventListeners(); + + this.removeSelectionListeners(); + + clearTimeout(this.expanding); + } + + /** + * Check if size of contents has changed and + * emit 'resize' event if it has. + * @private + */ + + }, { + key: "resizeCheck", + value: function resizeCheck() { + var width = this.textWidth(); + var height = this.textHeight(); + + if (width != this._size.width || height != this._size.height) { + + this._size = { + width: width, + height: height + }; + + this.onResize && this.onResize(this._size); + this.emit(_constants.EVENTS.CONTENTS.RESIZE, this._size); + } + } + + /** + * Poll for resize detection + * @private + */ + + }, { + key: "resizeListeners", + value: function resizeListeners() { + var width, height; + // Test size again + clearTimeout(this.expanding); + + requestAnimationFrame(this.resizeCheck.bind(this)); + + this.expanding = setTimeout(this.resizeListeners.bind(this), 350); + } + + /** + * Use css transitions to detect resize + * @private + */ + + }, { + key: "transitionListeners", + value: function transitionListeners() { + var body = this.content; + + body.style['transitionProperty'] = "font, font-size, font-size-adjust, font-stretch, font-variation-settings, font-weight, width, height"; + body.style['transitionDuration'] = "0.001ms"; + body.style['transitionTimingFunction'] = "linear"; + body.style['transitionDelay'] = "0"; + + this.document.addEventListener('transitionend', this.resizeCheck.bind(this)); + } + + /** + * Listen for media query changes and emit 'expand' event + * Adapted from: https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js + * @private + */ + + }, { + key: "mediaQueryListeners", + value: function mediaQueryListeners() { + var sheets = this.document.styleSheets; + var mediaChangeHandler = function (m) { + if (m.matches && !this._expanding) { + setTimeout(this.expand.bind(this), 1); + } + }.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; + } + } + } + } + + /** + * Use MutationObserver to listen for changes in the DOM and check for resize + * @private + */ + + }, { + key: "resizeObservers", + value: function resizeObservers() { + var _this = this; + + // create an observer instance + this.observer = new MutationObserver(function (mutations) { + _this.resizeCheck(); + }); + + // 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 + this.observer.observe(this.document, config); + } + }, { + key: "imageLoadListeners", + value: function 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); + } + } + } + + /** + * Listen for font load and check for resize when loaded + * @private + */ + + }, { + key: "fontLoadListeners", + value: function fontLoadListeners(target) { + if (!this.document || !this.document.fonts) { + return; + } + + this.document.fonts.ready.then(function () { + this.resizeCheck(); + }.bind(this)); + } + + /** + * Get the documentElement + * @returns {element} documentElement + */ + + }, { + key: "root", + value: function root() { + if (!this.document) return null; + return this.document.documentElement; + } + + /** + * Get the location offset of a EpubCFI or an #id + * @param {string | EpubCFI} target + * @param {string} [ignoreClass] for the cfi + * @returns { {left: Number, top: Number } + */ + + }, { + key: "locationOf", + value: function locationOf(target, ignoreClass) { + var position; + var targetPos = { "left": 0, "top": 0 }; + + if (!this.document) return targetPos; + + if (this.epubcfi.isCfiString(target)) { + var range = new _epubcfi2.default(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 + + // Construct a new non-collapsed range + if (isWebkit) { + var container = range.startContainer; + var newRange = new Range(); + try { + if (container.nodeType === ELEMENT_NODE) { + position = container.getBoundingClientRect(); + } else if (range.startOffset + 2 < container.length) { + newRange.setStart(container, range.startOffset); + newRange.setEnd(container, range.startOffset + 2); + position = newRange.getBoundingClientRect(); + } else if (range.startOffset - 2 > 0) { + newRange.setStart(container, range.startOffset - 2); + newRange.setEnd(container, range.startOffset); + position = newRange.getBoundingClientRect(); + } else { + // empty, return the parent element + position = container.parentNode.getBoundingClientRect(); + } + } catch (e) { + console.error(e, e.stack); + } + } else { + position = range.getBoundingClientRect(); + } + } + } + } else if (typeof target === "string" && target.indexOf("#") > -1) { + + var id = target.substring(target.indexOf("#") + 1); + var el = this.document.getElementById(id); + + if (el) { + position = el.getBoundingClientRect(); + } + } + + if (position) { + targetPos.left = position.left; + targetPos.top = position.top; + } + + return targetPos; + } + + /** + * Append a stylesheet link to the document head + * @param {string} src url + */ + + }, { + key: "addStylesheet", + value: function 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)); + } + + /** + * Append stylesheet rules to a generate stylesheet + * Array: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule + * Object: https://github.com/desirable-objects/json-to-css + * @param {array | object} rules + */ + + }, { + key: "addStylesheetRules", + value: function addStylesheetRules(rules) { + var styleEl; + var styleSheet; + var key = "epubjs-inserted-css"; + + if (!this.document || !rules || rules.length === 0) 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; + + if (Object.prototype.toString.call(rules) === "[object Array]") { + 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; + } + + for (var pl = rule.length; j < pl; j++) { + var prop = rule[j]; + propStr += prop[0] + ":" + prop[1] + (prop[2] ? " !important" : "") + ";\n"; + } + + // Insert CSS Rule + styleSheet.insertRule(selector + "{" + propStr + "}", styleSheet.cssRules.length); + } + } else { + var selectors = Object.keys(rules); + selectors.forEach(function (selector) { + var definition = rules[selector]; + if (Array.isArray(definition)) { + definition.forEach(function (item) { + var _rules = Object.keys(item); + var result = _rules.map(function (rule) { + return rule + ":" + item[rule]; + }).join(';'); + styleSheet.insertRule(selector + "{" + result + "}", styleSheet.cssRules.length); + }); + } else { + var _rules = Object.keys(definition); + var result = _rules.map(function (rule) { + return rule + ":" + definition[rule]; + }).join(';'); + styleSheet.insertRule(selector + "{" + result + "}", styleSheet.cssRules.length); + } + }); + } + } + + /** + * Append a script tag to the document head + * @param {string} src url + * @returns {Promise} loaded + */ + + }, { + key: "addScript", + value: function addScript(src) { + + return new Promise(function (resolve, reject) { + var $script; + var ready = false; + + if (!this.document) { + resolve(false); + return; + } + + $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)); + } + + /** + * Add a class to the contents container + * @param {string} className + */ + + }, { + key: "addClass", + value: function addClass(className) { + var content; + + if (!this.document) return; + + content = this.content || this.document.body; + + if (content) { + content.classList.add(className); + } + } + + /** + * Remove a class from the contents container + * @param {string} removeClass + */ + + }, { + key: "removeClass", + value: function removeClass(className) { + var content; + + if (!this.document) return; + + content = this.content || this.document.body; + + if (content) { + content.classList.remove(className); + } + } + + /** + * Add DOM event listeners + * @private + */ + + }, { + key: "addEventListeners", + value: function addEventListeners() { + if (!this.document) { + return; + } + + _constants.DOM_EVENTS.forEach(function (eventName) { + this.document.addEventListener(eventName, this.triggerEvent.bind(this), false); + }, this); + } + + /** + * Remove DOM event listeners + * @private + */ + + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + if (!this.document) { + return; + } + _constants.DOM_EVENTS.forEach(function (eventName) { + this.document.removeEventListener(eventName, this.triggerEvent, false); + }, this); + } + + /** + * Emit passed browser events + * @private + */ + + }, { + key: "triggerEvent", + value: function triggerEvent(e) { + this.emit(e.type, e); + } + + /** + * Add listener for text selection + * @private + */ + + }, { + key: "addSelectionListeners", + value: function addSelectionListeners() { + if (!this.document) { + return; + } + this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false); + } + + /** + * Remove listener for text selection + * @private + */ + + }, { + key: "removeSelectionListeners", + value: function removeSelectionListeners() { + if (!this.document) { + return; + } + this.document.removeEventListener("selectionchange", this.onSelectionChange, false); + } + + /** + * Handle getting text on selection + * @private + */ + + }, { + key: "onSelectionChange", + value: function onSelectionChange(e) { + if (this.selectionEndTimeout) { + clearTimeout(this.selectionEndTimeout); + } + this.selectionEndTimeout = setTimeout(function () { + var selection = this.window.getSelection(); + this.triggerSelectedEvent(selection); + }.bind(this), 250); + } + + /** + * Emit event on text selection + * @private + */ + + }, { + key: "triggerSelectedEvent", + value: function triggerSelectedEvent(selection) { + var range, cfirange; + + if (selection && selection.rangeCount > 0) { + range = selection.getRangeAt(0); + if (!range.collapsed) { + // cfirange = this.section.cfiFromRange(range); + cfirange = new _epubcfi2.default(range, this.cfiBase).toString(); + this.emit(_constants.EVENTS.CONTENTS.SELECTED, cfirange); + this.emit(_constants.EVENTS.CONTENTS.SELECTED_RANGE, range); + } + } + } + + /** + * Get a Dom Range from EpubCFI + * @param {EpubCFI} _cfi + * @param {string} [ignoreClass] + * @returns {Range} range + */ + + }, { + key: "range", + value: function range(_cfi, ignoreClass) { + var cfi = new _epubcfi2.default(_cfi); + return cfi.toRange(this.document, ignoreClass); + } + + /** + * Get an EpubCFI from a Dom Range + * @param {Range} range + * @param {string} [ignoreClass] + * @returns {EpubCFI} cfi + */ + + }, { + key: "cfiFromRange", + value: function cfiFromRange(range, ignoreClass) { + return new _epubcfi2.default(range, this.cfiBase, ignoreClass).toString(); + } + + /** + * Get an EpubCFI from a Dom node + * @param {node} node + * @param {string} [ignoreClass] + * @returns {EpubCFI} cfi + */ + + }, { + key: "cfiFromNode", + value: function cfiFromNode(node, ignoreClass) { + return new _epubcfi2.default(node, this.cfiBase, ignoreClass).toString(); + } + + // TODO: find where this is used - remove? + + }, { + key: "map", + value: function map(layout) { + var map = new _mapping2.default(layout); + return map.section(); + } + + /** + * Size the contents to a given width and height + * @param {number} [width] + * @param {number} [height] + */ + + }, { + key: "size", + value: function size(width, height) { + var viewport = { scale: 1.0, scalable: "no" }; + + this.layoutStyle("scrolling"); + + if (width >= 0) { + this.width(width); + viewport.width = width; + this.css("padding", "0 " + width / 12 + "px", true); + } + + if (height >= 0) { + this.height(height); + viewport.height = height; + } + + this.css("margin", "0"); + this.css("box-sizing", "border-box"); + + this.viewport(viewport); + } + + /** + * Apply columns to the contents for pagination + * @param {number} width + * @param {number} height + * @param {number} columnWidth + * @param {number} gap + */ + + }, { + key: "columns", + value: function columns(width, height, columnWidth, gap) { + var COLUMN_AXIS = (0, _core.prefixed)("column-axis"); + var COLUMN_GAP = (0, _core.prefixed)("column-gap"); + var COLUMN_WIDTH = (0, _core.prefixed)("column-width"); + var COLUMN_FILL = (0, _core.prefixed)("column-fill"); + + var writingMode = this.writingMode(); + var axis = writingMode.indexOf("vertical") === 0 ? "vertical" : "horizontal"; + + this.layoutStyle("paginated"); + + // Fix body width issues if rtl is only set on body element + if (this.content.dir === "rtl") { + this.direction("rtl"); + } + + this.width(width); + this.height(height); + + // Deal with Mobile trying to scale to viewport + this.viewport({ width: width, height: height, scale: 1.0, scalable: "no" }); + + // TODO: inline-block needs more testing + // Fixes Safari column cut offs, but causes RTL issues + // this.css("display", "inline-block"); + + this.css("overflow-y", "hidden"); + this.css("margin", "0", true); + + if (axis === "vertical") { + this.css("padding", gap / 2 + "px 20px", true); + } else { + this.css("padding", "20px " + gap / 2 + "px", true); + } + + this.css("box-sizing", "border-box"); + this.css("max-width", "inherit"); + + this.css(COLUMN_AXIS, "horizontal"); + this.css(COLUMN_FILL, "auto"); + + this.css(COLUMN_GAP, gap + "px"); + this.css(COLUMN_WIDTH, columnWidth + "px"); + } + + /** + * Scale contents from center + * @param {number} scale + * @param {number} offsetX + * @param {number} offsetY + */ + + }, { + key: "scaler", + value: function scaler(scale, offsetX, offsetY) { + var scaleStr = "scale(" + scale + ")"; + var translateStr = ""; + // this.css("position", "absolute")); + this.css("transform-origin", "top left"); + + if (offsetX >= 0 || offsetY >= 0) { + translateStr = " translate(" + (offsetX || 0) + "px, " + (offsetY || 0) + "px )"; + } + + this.css("transform", scaleStr + translateStr); + } + + /** + * Fit contents into a fixed width and height + * @param {number} width + * @param {number} height + */ + + }, { + key: "fit", + value: function fit(width, height) { + var viewport = this.viewport(); + var widthScale = width / parseInt(viewport.width); + var heightScale = height / parseInt(viewport.height); + var scale = widthScale < heightScale ? widthScale : heightScale; + + var offsetY = (height - viewport.height * scale) / 2; + + this.layoutStyle("paginated"); + + this.width(width); + this.height(height); + this.overflow("hidden"); + + // Scale to the correct size + this.scaler(scale, 0, offsetY); + + this.css("background-color", "transparent"); + } + + /** + * Set the direction of the text + * @param {string} [dir="ltr"] "rtl" | "ltr" + */ + + }, { + key: "direction", + value: function direction(dir) { + if (this.documentElement) { + this.documentElement.style["direction"] = dir; + } + } + }, { + key: "mapPage", + value: function mapPage(cfiBase, layout, start, end, dev) { + var mapping = new _mapping2.default(layout, dev); + + return mapping.page(this, cfiBase, start, end); + } + + /** + * Emit event when link in content is clicked + * @private + */ + + }, { + key: "linksHandler", + value: function linksHandler() { + var _this2 = this; + + (0, _replacements.replaceLinks)(this.content, function (href) { + _this2.emit(_constants.EVENTS.CONTENTS.LINK_CLICKED, href); + }); + } + + /** + * Set the writingMode of the text + * @param {string} [mode="horizontal-tb"] "horizontal-tb" | "vertical-rl" | "vertical-lr" + */ + + }, { + key: "writingMode", + value: function writingMode(mode) { + var WRITING_MODE = (0, _core.prefixed)("writing-mode"); + + if (mode && this.documentElement) { + this.documentElement.style[WRITING_MODE] = mode; + } + + return this.window.getComputedStyle(this.documentElement)[WRITING_MODE] || ''; + } + + /** + * Set the layoutStyle of the content + * @param {string} [style="paginated"] "scrolling" | "paginated" + * @private + */ + + }, { + key: "layoutStyle", + value: function layoutStyle(style) { + + if (style) { + this._layoutStyle = style; + navigator.epubReadingSystem.layoutStyle = this._layoutStyle; + } + + return this._layoutStyle || "paginated"; + } + + /** + * Add the epubReadingSystem object to the navigator + * @param {string} name + * @param {string} version + * @private + */ + + }, { + key: "epubReadingSystem", + value: function epubReadingSystem(name, version) { + navigator.epubReadingSystem = { + name: name, + version: version, + layoutStyle: this.layoutStyle(), + hasFeature: function hasFeature(feature) { + switch (feature) { + case "dom-manipulation": + return true; + case "layout-changes": + return true; + case "touch-events": + return true; + case "mouse-events": + return true; + case "keyboard-events": + return true; + case "spine-scripting": + return false; + default: + return false; + } + } + }; + return navigator.epubReadingSystem; + } + }, { + key: "destroy", + value: function destroy() { + // Stop observing + if (this.observer) { + this.observer.disconnect(); + } + + this.document.removeEventListener('transitionend', this.resizeCheck); + + this.removeListeners(); + } + }], [{ + key: "listenedEvents", + get: function get() { + return _constants.DOM_EVENTS; + } + }]); + + return Contents; +}(); + +(0, _eventEmitter2.default)(Contents.prototype); + +exports.default = Contents; +module.exports = exports["default"]; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _core = __webpack_require__(0); + +var _mapping = __webpack_require__(19); + +var _mapping2 = _interopRequireDefault(_mapping); + +var _queue = __webpack_require__(12); + +var _queue2 = _interopRequireDefault(_queue); + +var _stage = __webpack_require__(56); + +var _stage2 = _interopRequireDefault(_stage); + +var _views = __webpack_require__(66); + +var _views2 = _interopRequireDefault(_views); + +var _constants = __webpack_require__(3); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var DefaultViewManager = function () { + function DefaultViewManager(options) { + _classCallCheck(this, DefaultViewManager); + + this.name = "default"; + this.View = options.view; + this.request = options.request; + this.renditionQueue = options.queue; + this.q = new _queue2.default(this); + + this.settings = (0, _core.extend)(this.settings || {}, { + infinite: true, + hidden: false, + width: undefined, + height: undefined, + axis: undefined, + flow: "scrolled", + ignoreClass: "" + }); + + (0, _core.extend)(this.settings, options.settings || {}); + + this.viewSettings = { + ignoreClass: this.settings.ignoreClass, + axis: this.settings.axis, + flow: this.settings.flow, + layout: this.layout, + method: this.settings.method, // srcdoc, blobUrl, write + width: 0, + height: 0, + forceEvenPages: true + }; + + this.rendered = false; + } + + _createClass(DefaultViewManager, [{ + key: "render", + value: function render(element, size) { + var tag = element.tagName; + + if (tag && (tag.toLowerCase() == "body" || tag.toLowerCase() == "html")) { + this.fullsize = true; + } + + if (this.fullsize) { + this.settings.overflow = "visible"; + this.overflow = this.settings.overflow; + } + + this.settings.size = size; + + // Save the stage + this.stage = new _stage2.default({ + width: size.width, + height: size.height, + overflow: this.overflow, + hidden: this.settings.hidden, + axis: this.settings.axis, + fullsize: this.fullsize, + direction: this.settings.direction + }); + + this.stage.attachTo(element); + + // Get this stage container div + this.container = this.stage.getContainer(); + + // Views array methods + this.views = new _views2.default(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)); + + this.stage.onOrientationChange(this.onOrientationChange.bind(this)); + + // Add Event Listeners + this.addEventListeners(); + + // Add Layout method + // this.applyLayoutMethod(); + if (this.layout) { + this.updateLayout(); + } + + this.rendered = true; + } + }, { + key: "addEventListeners", + value: function addEventListeners() { + var scroller; + + window.addEventListener("unload", function (e) { + this.destroy(); + }.bind(this)); + + if (!this.fullsize) { + scroller = this.container; + } else { + scroller = window; + } + + scroller.addEventListener("scroll", this.onScroll.bind(this)); + } + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + var scroller; + + if (!this.fullsize) { + scroller = this.container; + } else { + scroller = window; + } + + scroller.removeEventListener("scroll", this.onScroll.bind(this)); + } + }, { + key: "destroy", + value: function destroy() { + clearTimeout(this.orientationTimeout); + clearTimeout(this.resizeTimeout); + clearTimeout(this.afterScrolled); + + this.clear(); + + this.removeEventListeners(); + + this.stage.destroy(); + + this.rendered = false; + + /* + clearTimeout(this.trimTimeout); + if(this.settings.hidden) { + this.element.removeChild(this.wrapper); + } else { + this.element.removeChild(this.container); + } + */ + } + }, { + key: "onOrientationChange", + value: function onOrientationChange(e) { + var _window = window, + orientation = _window.orientation; + + + this.resize(); + + // Per ampproject: + // In IOS 10.3, the measured size of an element is incorrect if the + // element size depends on window size directly and the measurement + // happens in window.resize event. Adding a timeout for correct + // measurement. See https://github.com/ampproject/amphtml/issues/8479 + clearTimeout(this.orientationTimeout); + this.orientationTimeout = setTimeout(function () { + this.orientationTimeout = undefined; + this.resize(); + this.emit(_constants.EVENTS.MANAGERS.ORIENTATION_CHANGE, orientation); + }.bind(this), 500); + } + }, { + key: "onResized", + value: function onResized(e) { + this.resize(); + } + }, { + key: "resize", + value: function resize(width, height) { + var stageSize = this.stage.size(width, height); + + // For Safari, wait for orientation to catch up + // if the window is a square + this.winBounds = (0, _core.windowBounds)(); + if (this.orientationTimeout && this.winBounds.width === this.winBounds.height) { + // reset the stage size for next resize + this._stageSize = undefined; + return; + } + + if (this._stageSize && this._stageSize.width === stageSize.width && this._stageSize.height === stageSize.height) { + // Size is the same, no need to resize + return; + } + + this._stageSize = stageSize; + + this._bounds = this.bounds(); + + // Clear current views + this.clear(); + + // Update for new views + this.viewSettings.width = this._stageSize.width; + this.viewSettings.height = this._stageSize.height; + + this.updateLayout(); + + this.emit(_constants.EVENTS.MANAGERS.RESIZED, { + width: this._stageSize.width, + height: this._stageSize.height + }); + } + }, { + key: "createView", + value: function createView(section) { + return new this.View(section, this.viewSettings); + } + }, { + key: "display", + value: function display(section, target) { + + var displaying = new _core.defer(); + var displayed = displaying.promise; + + // Check if moving to target is needed + if (target === section.href || (0, _core.isNumber)(target)) { + target = undefined; + } + + // 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 in view + if (visible && section) { + var offset = visible.offset(); + + if (this.settings.direction === "ltr") { + this.scrollTo(offset.left, offset.top, true); + } else { + var width = visible.width(); + this.scrollTo(offset.left + width, offset.top, true); + } + + if (target) { + var _offset = visible.locationOf(target); + this.moveTo(_offset); + } + + displaying.resolve(); + return displayed; + } + + // Hide all current views + this.clear(); + + this.add(section).then(function (view) { + + // Move to correct place within the section, if needed + if (target) { + var _offset2 = view.locationOf(target); + this.moveTo(_offset2); + } + }.bind(this), function (err) { + displaying.reject(err); + }).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; + } + }, { + key: "afterDisplayed", + value: function afterDisplayed(view) { + this.emit(_constants.EVENTS.MANAGERS.ADDED, view); + } + }, { + key: "afterResized", + value: function afterResized(view) { + this.emit(_constants.EVENTS.MANAGERS.RESIZE, view.section); + } + }, { + key: "moveTo", + value: function moveTo(offset) { + var distX = 0, + distY = 0; + + if (!this.isPaginated) { + 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, true); + } + }, { + key: "add", + value: function add(section) { + var _this = this; + + var view = this.createView(section); + + this.views.append(view); + + // view.on(EVENTS.VIEWS.SHOWN, this.afterDisplayed.bind(this)); + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(_constants.EVENTS.VIEWS.AXIS, function (axis) { + _this.updateAxis(axis); + }); + + return view.display(this.request); + } + }, { + key: "append", + value: function append(section) { + var _this2 = this; + + var view = this.createView(section); + this.views.append(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(_constants.EVENTS.VIEWS.AXIS, function (axis) { + _this2.updateAxis(axis); + }); + + return view.display(this.request); + } + }, { + key: "prepend", + value: function prepend(section) { + var _this3 = this; + + var view = this.createView(section); + + view.on(_constants.EVENTS.VIEWS.RESIZED, function (bounds) { + _this3.counter(bounds); + }); + + this.views.prepend(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(_constants.EVENTS.VIEWS.AXIS, function (axis) { + _this3.updateAxis(axis); + }); + + return view.display(this.request); + } + }, { + key: "counter", + value: function counter(bounds) { + if (this.settings.axis === "vertical") { + this.scrollBy(0, bounds.heightDelta, true); + } else { + this.scrollBy(bounds.widthDelta, 0, true); + } + } + + // 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); + // } + // + // }; + + }, { + key: "next", + value: function next() { + var next; + var left; + + var dir = this.settings.direction; + + if (!this.views.length) return; + + if (this.isPaginated && this.settings.axis === "horizontal" && (!dir || dir === "ltr")) { + + 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, true); + } else { + next = this.views.last().section.next(); + } + } else if (this.isPaginated && this.settings.axis === "horizontal" && dir === "rtl") { + + this.scrollLeft = this.container.scrollLeft; + + left = this.container.scrollLeft; + + if (left > 0) { + this.scrollBy(this.layout.delta, 0, true); + } else { + next = this.views.last().section.next(); + } + } else if (this.isPaginated && this.settings.axis === "vertical") { + + this.scrollTop = this.container.scrollTop; + + var top = this.container.scrollTop + this.container.offsetHeight; + + if (top < this.container.scrollHeight) { + this.scrollBy(0, this.layout.height, true); + } else { + next = this.views.last().section.next(); + } + } else { + next = this.views.last().section.next(); + } + + if (next) { + this.clear(); + + return this.append(next).then(function () { + var right; + if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) { + right = next.next(); + if (right) { + return this.append(right); + } + } + }.bind(this), function (err) { + displaying.reject(err); + }).then(function () { + this.views.show(); + }.bind(this)); + } + } + }, { + key: "prev", + value: function prev() { + var prev; + var left; + var dir = this.settings.direction; + + if (!this.views.length) return; + + if (this.isPaginated && this.settings.axis === "horizontal" && (!dir || dir === "ltr")) { + + this.scrollLeft = this.container.scrollLeft; + + left = this.container.scrollLeft; + + if (left > 0) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + } else if (this.isPaginated && this.settings.axis === "horizontal" && dir === "rtl") { + + 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, true); + } else { + prev = this.views.first().section.prev(); + } + } else if (this.isPaginated && this.settings.axis === "vertical") { + + this.scrollTop = this.container.scrollTop; + + var top = this.container.scrollTop; + + if (top > 0) { + this.scrollBy(0, -this.layout.height, true); + } else { + prev = this.views.first().section.prev(); + } + } else { + + prev = this.views.first().section.prev(); + } + + if (prev) { + this.clear(); + + return this.prepend(prev).then(function () { + var left; + if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) { + left = prev.prev(); + if (left) { + return this.prepend(left); + } + } + }.bind(this), function (err) { + displaying.reject(err); + }).then(function () { + if (this.isPaginated && this.settings.axis === "horizontal") { + if (this.settings.direction === "rtl") { + this.scrollTo(0, 0, true); + } else { + this.scrollTo(this.container.scrollWidth - this.layout.delta, 0, true); + } + } + this.views.show(); + }.bind(this)); + } + } + }, { + key: "current", + value: function current() { + var visible = this.visible(); + if (visible.length) { + // Current is the last visible view + return visible[visible.length - 1]; + } + return null; + } + }, { + key: "clear", + value: function clear() { + + // this.q.clear(); + + if (this.views) { + this.views.hide(); + this.scrollTo(0, 0, true); + this.views.clear(); + } + } + }, { + key: "currentLocation", + value: function currentLocation() { + + if (this.settings.axis === "vertical") { + this.location = this.scrolledLocation(); + } else { + this.location = this.paginatedLocation(); + } + return this.location; + } + }, { + key: "scrolledLocation", + value: function scrolledLocation() { + var _this4 = this; + + var visible = this.visible(); + var container = this.container.getBoundingClientRect(); + var pageHeight = container.height < window.innerHeight ? container.height : window.innerHeight; + + var offset = 0; + var used = 0; + + if (this.fullsize) { + offset = window.scrollY; + } + + var sections = visible.map(function (view) { + var _view$section = view.section, + index = _view$section.index, + href = _view$section.href; + + var position = view.position(); + var height = view.height(); + + var startPos = offset + container.top - position.top + used; + var endPos = startPos + pageHeight - used; + if (endPos > height) { + endPos = height; + used = endPos - startPos; + } + + var totalPages = _this4.layout.count(height, pageHeight).pages; + + var currPage = Math.ceil(startPos / pageHeight); + var pages = []; + var endPage = Math.ceil(endPos / pageHeight); + + pages = []; + for (var i = currPage; i <= endPage; i++) { + var pg = i + 1; + pages.push(pg); + } + + var mapping = _this4.mapping.page(view.contents, view.section.cfiBase, startPos, endPos); + + return { + index: index, + href: href, + pages: pages, + totalPages: totalPages, + mapping: mapping + }; + }); + + return sections; + } + }, { + key: "paginatedLocation", + value: function paginatedLocation() { + var _this5 = this; + + var visible = this.visible(); + var container = this.container.getBoundingClientRect(); + + var left = 0; + var used = 0; + + if (this.fullsize) { + left = window.scrollX; + } + + var sections = visible.map(function (view) { + var _view$section2 = view.section, + index = _view$section2.index, + href = _view$section2.href; + + var offset = view.offset().left; + var position = view.position().left; + var width = view.width(); + + // Find mapping + var start = left + container.left - position + used; + var end = start + _this5.layout.width - used; + + var mapping = _this5.mapping.page(view.contents, view.section.cfiBase, start, end); + + // Find displayed pages + //console.log("pre", end, offset + width); + // if (end > offset + width) { + // end = offset + width; + // used = this.layout.pageWidth; + // } + // console.log("post", end); + + var totalPages = _this5.layout.count(width).pages; + var startPage = Math.floor(start / _this5.layout.pageWidth); + var pages = []; + var endPage = Math.floor(end / _this5.layout.pageWidth); + + // start page should not be negative + if (startPage < 0) { + startPage = 0; + endPage = endPage + 1; + } + + // Reverse page counts for rtl + if (_this5.settings.direction === "rtl") { + var tempStartPage = startPage; + startPage = totalPages - endPage; + endPage = totalPages - tempStartPage; + } + + for (var i = startPage + 1; i <= endPage; i++) { + var pg = i; + pages.push(pg); + } + + return { + index: index, + href: href, + pages: pages, + totalPages: totalPages, + mapping: mapping + }; + }); + + return sections; + } + }, { + key: "isVisible", + value: function 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; + } + }, { + key: "visible", + value: function visible() { + 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; + } + }, { + key: "scrollBy", + value: function scrollBy(x, y, silent) { + var dir = this.settings.direction === "rtl" ? -1 : 1; + + if (silent) { + this.ignore = true; + } + + if (!this.fullsize) { + if (x) this.container.scrollLeft += x * dir; + if (y) this.container.scrollTop += y; + } else { + window.scrollBy(x * dir, y * dir); + } + this.scrolled = true; + } + }, { + key: "scrollTo", + value: function scrollTo(x, y, silent) { + if (silent) { + this.ignore = true; + } + + if (!this.fullsize) { + this.container.scrollLeft = x; + this.container.scrollTop = y; + } else { + window.scrollTo(x, y); + } + this.scrolled = true; + } + }, { + key: "onScroll", + value: function onScroll() { + var scrollTop = void 0; + var scrollLeft = void 0; + + if (!this.fullsize) { + scrollTop = this.container.scrollTop; + scrollLeft = this.container.scrollLeft; + } else { + scrollTop = window.scrollY; + scrollLeft = window.scrollX; + } + + this.scrollTop = scrollTop; + this.scrollLeft = scrollLeft; + + if (!this.ignore) { + this.emit(_constants.EVENTS.MANAGERS.SCROLL, { + top: scrollTop, + left: scrollLeft + }); + + clearTimeout(this.afterScrolled); + this.afterScrolled = setTimeout(function () { + this.emit(_constants.EVENTS.MANAGERS.SCROLLED, { + top: this.scrollTop, + left: this.scrollLeft + }); + }.bind(this), 20); + } else { + this.ignore = false; + } + } + }, { + key: "bounds", + value: function bounds() { + var bounds; + + bounds = this.stage.bounds(); + + return bounds; + } + }, { + key: "applyLayout", + value: function applyLayout(layout) { + + this.layout = layout; + this.updateLayout(); + // this.manager.layout(this.layout.format); + } + }, { + key: "updateLayout", + value: function updateLayout() { + + if (!this.stage) { + return; + } + + this._stageSize = this.stage.size(); + + if (!this.isPaginated) { + 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); + } + }, { + key: "setLayout", + value: function setLayout(layout) { + + this.viewSettings.layout = layout; + + this.mapping = new _mapping2.default(layout.props, this.settings.direction, this.settings.axis); + + if (this.views) { + + this.views.forEach(function (view) { + if (view) { + view.setLayout(layout); + } + }); + } + } + }, { + key: "updateAxis", + value: function updateAxis(axis, forceUpdate) { + + if (!this.isPaginated) { + axis = "vertical"; + } + + if (!forceUpdate && axis === this.settings.axis) { + return; + } + + this.settings.axis = axis; + + this.stage && this.stage.axis(axis); + + this.viewSettings.axis = axis; + + if (this.mapping) { + this.mapping = new _mapping2.default(this.layout.props, this.settings.direction, this.settings.axis); + } + + if (this.layout) { + if (axis === "vertical") { + this.layout.spread("none"); + } else { + this.layout.spread(this.layout.settings.spread); + } + } + } + }, { + key: "updateFlow", + value: function updateFlow(flow) { + var isPaginated = flow === "paginated" || flow === "auto"; + + this.isPaginated = isPaginated; + + if (flow === "scrolled-doc" || flow === "scrolled-continuous" || flow === "scrolled") { + this.updateAxis("vertical"); + } + + this.viewSettings.flow = flow; + + if (!this.settings.overflow) { + this.overflow = isPaginated ? "hidden" : "auto"; + } else { + this.overflow = this.settings.overflow; + } + // this.views.forEach(function(view){ + // view.setAxis(axis); + // }); + + this.updateLayout(); + } + }, { + key: "getContents", + value: function getContents() { + var contents = []; + if (!this.views) { + return contents; + } + this.views.forEach(function (view) { + var viewContents = view && view.contents; + if (viewContents) { + contents.push(viewContents); + } + }); + return contents; + } + }, { + key: "direction", + value: function direction() { + var dir = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "ltr"; + + this.settings.direction = dir; + + this.stage && this.stage.direction(dir); + + this.viewSettings.direction = dir; + + this.updateLayout(); + } + }, { + key: "isRendered", + value: function isRendered() { + return this.rendered; + } + }]); + + return DefaultViewManager; +}(); + +//-- Enable binding events to Manager + + +(0, _eventEmitter2.default)(DefaultViewManager.prototype); + +exports.default = DefaultViewManager; +module.exports = exports["default"]; + +/***/ }), +/* 15 */ +/***/ (function(module, exports) { + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +module.exports = isObject; + + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE_16__; + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* + From Zip.js, by Gildas Lormeau +edited down + */ + +var table = { + "application": { + "ecmascript": ["es", "ecma"], + "javascript": "js", + "ogg": "ogx", + "pdf": "pdf", + "postscript": ["ps", "ai", "eps", "epsi", "epsf", "eps2", "eps3"], + "rdf+xml": "rdf", + "smil": ["smi", "smil"], + "xhtml+xml": ["xhtml", "xht"], + "xml": ["xml", "xsl", "xsd", "opf", "ncx"], + "zip": "zip", + "x-httpd-eruby": "rhtml", + "x-latex": "latex", + "x-maker": ["frm", "maker", "frame", "fm", "fb", "book", "fbdoc"], + "x-object": "o", + "x-shockwave-flash": ["swf", "swfl"], + "x-silverlight": "scr", + "epub+zip": "epub", + "font-tdpfr": "pfr", + "inkml+xml": ["ink", "inkml"], + "json": "json", + "jsonml+json": "jsonml", + "mathml+xml": "mathml", + "metalink+xml": "metalink", + "mp4": "mp4s", + // "oebps-package+xml" : "opf", + "omdoc+xml": "omdoc", + "oxps": "oxps", + "vnd.amazon.ebook": "azw", + "widget": "wgt", + // "x-dtbncx+xml" : "ncx", + "x-dtbook+xml": "dtb", + "x-dtbresource+xml": "res", + "x-font-bdf": "bdf", + "x-font-ghostscript": "gsf", + "x-font-linux-psf": "psf", + "x-font-otf": "otf", + "x-font-pcf": "pcf", + "x-font-snf": "snf", + "x-font-ttf": ["ttf", "ttc"], + "x-font-type1": ["pfa", "pfb", "pfm", "afm"], + "x-font-woff": "woff", + "x-mobipocket-ebook": ["prc", "mobi"], + "x-mspublisher": "pub", + "x-nzb": "nzb", + "x-tgif": "obj", + "xaml+xml": "xaml", + "xml-dtd": "dtd", + "xproc+xml": "xpl", + "xslt+xml": "xslt", + "internet-property-stream": "acx", + "x-compress": "z", + "x-compressed": "tgz", + "x-gzip": "gz" + }, + "audio": { + "flac": "flac", + "midi": ["mid", "midi", "kar", "rmi"], + "mpeg": ["mpga", "mpega", "mp2", "mp3", "m4a", "mp2a", "m2a", "m3a"], + "mpegurl": "m3u", + "ogg": ["oga", "ogg", "spx"], + "x-aiff": ["aif", "aiff", "aifc"], + "x-ms-wma": "wma", + "x-wav": "wav", + "adpcm": "adp", + "mp4": "mp4a", + "webm": "weba", + "x-aac": "aac", + "x-caf": "caf", + "x-matroska": "mka", + "x-pn-realaudio-plugin": "rmp", + "xm": "xm", + "mid": ["mid", "rmi"] + }, + "image": { + "gif": "gif", + "ief": "ief", + "jpeg": ["jpeg", "jpg", "jpe"], + "pcx": "pcx", + "png": "png", + "svg+xml": ["svg", "svgz"], + "tiff": ["tiff", "tif"], + "x-icon": "ico", + "bmp": "bmp", + "webp": "webp", + "x-pict": ["pic", "pct"], + "x-tga": "tga", + "cis-cod": "cod" + }, + "text": { + "cache-manifest": ["manifest", "appcache"], + "css": "css", + "csv": "csv", + "html": ["html", "htm", "shtml", "stm"], + "mathml": "mml", + "plain": ["txt", "text", "brf", "conf", "def", "list", "log", "in", "bas"], + "richtext": "rtx", + "tab-separated-values": "tsv", + "x-bibtex": "bib" + }, + "video": { + "mpeg": ["mpeg", "mpg", "mpe", "m1v", "m2v", "mp2", "mpa", "mpv2"], + "mp4": ["mp4", "mp4v", "mpg4"], + "quicktime": ["qt", "mov"], + "ogg": "ogv", + "vnd.mpegurl": ["mxu", "m4u"], + "x-flv": "flv", + "x-la-asf": ["lsf", "lsx"], + "x-mng": "mng", + "x-ms-asf": ["asf", "asx", "asr"], + "x-ms-wm": "wm", + "x-ms-wmv": "wmv", + "x-ms-wmx": "wmx", + "x-ms-wvx": "wvx", + "x-msvideo": "avi", + "x-sgi-movie": "movie", + "x-matroska": ["mpv", "mkv", "mk3d", "mks"], + "3gpp2": "3g2", + "h261": "h261", + "h263": "h263", + "h264": "h264", + "jpeg": "jpgv", + "jpm": ["jpm", "jpgm"], + "mj2": ["mj2", "mjp2"], + "vnd.ms-playready.media.pyv": "pyv", + "vnd.uvvu.mp4": ["uvu", "uvvu"], + "vnd.vivo": "viv", + "webm": "webm", + "x-f4v": "f4v", + "x-m4v": "m4v", + "x-ms-vob": "vob", + "x-smv": "smv" + } +}; + +var mimeTypes = function () { + var type, + subtype, + val, + index, + mimeTypes = {}; + for (type in table) { + if (table.hasOwnProperty(type)) { + for (subtype in table[type]) { + if (table[type].hasOwnProperty(subtype)) { + val = table[type][subtype]; + if (typeof val == "string") { + mimeTypes[val] = type + "/" + subtype; + } else { + for (index = 0; index < val.length; index++) { + mimeTypes[val[index]] = type + "/" + subtype; + } + } + } + } + } + } + return mimeTypes; +}(); + +var defaultValue = "text/plain"; //"application/octet-stream"; + +function lookup(filename) { + return filename && mimeTypes[filename.split(".").pop().toLowerCase()] || defaultValue; +}; + +module.exports = { + 'lookup': lookup +}; + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +// import Mapping from "./mapping"; + + +// Default Views + + +// Default View Managers + + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _core = __webpack_require__(0); + +var _hook = __webpack_require__(10); + +var _hook2 = _interopRequireDefault(_hook); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _queue = __webpack_require__(12); + +var _queue2 = _interopRequireDefault(_queue); + +var _layout = __webpack_require__(50); + +var _layout2 = _interopRequireDefault(_layout); + +var _themes = __webpack_require__(51); + +var _themes2 = _interopRequireDefault(_themes); + +var _contents = __webpack_require__(13); + +var _contents2 = _interopRequireDefault(_contents); + +var _annotations = __webpack_require__(52); + +var _annotations2 = _interopRequireDefault(_annotations); + +var _constants = __webpack_require__(3); + +var _iframe = __webpack_require__(20); + +var _iframe2 = _interopRequireDefault(_iframe); + +var _index = __webpack_require__(14); + +var _index2 = _interopRequireDefault(_index); + +var _index3 = __webpack_require__(24); + +var _index4 = _interopRequireDefault(_index3); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Displays an Epub as a series of Views for each Section. + * Requires Manager and View class to handle specifics of rendering + * the section contetn. + * @class + * @param {Book} book + * @param {object} [options] + * @param {number} [options.width] + * @param {number} [options.height] + * @param {string} [options.ignoreClass] class for the cfi parser to ignore + * @param {string | function | object} [options.manager='default'] + * @param {string | function} [options.view='iframe'] + * @param {string} [options.layout] layout to force + * @param {string} [options.spread] force spread value + * @param {number} [options.minSpreadWidth] overridden by spread: none (never) / both (always) + * @param {string} [options.stylesheet] url of stylesheet to be injected + * @param {string} [options.script] url of script to be injected + */ +var Rendition = function () { + function Rendition(book, options) { + _classCallCheck(this, Rendition); + + this.settings = (0, _core.extend)(this.settings || {}, { + width: null, + height: null, + ignoreClass: "", + manager: "default", + view: "iframe", + flow: null, + layout: null, + spread: null, + minSpreadWidth: 800, + stylesheet: null, + script: null + }); + + (0, _core.extend)(this.settings, options); + + if (_typeof(this.settings.manager) === "object") { + this.manager = this.settings.manager; + } + + this.book = book; + + /** + * Adds Hook methods to the Rendition prototype + * @member {object} hooks + * @property {Hook} hooks.content + * @memberof Rendition + */ + this.hooks = {}; + this.hooks.display = new _hook2.default(this); + this.hooks.serialize = new _hook2.default(this); + this.hooks.content = new _hook2.default(this); + this.hooks.unloaded = new _hook2.default(this); + this.hooks.layout = new _hook2.default(this); + this.hooks.render = new _hook2.default(this); + this.hooks.show = new _hook2.default(this); + + this.hooks.content.register(this.handleLinks.bind(this)); + this.hooks.content.register(this.passEvents.bind(this)); + this.hooks.content.register(this.adjustImages.bind(this)); + + this.book.spine.hooks.content.register(this.injectIdentifier.bind(this)); + + if (this.settings.stylesheet) { + this.book.spine.hooks.content.register(this.injectStylesheet.bind(this)); + } + + if (this.settings.script) { + this.book.spine.hooks.content.register(this.injectScript.bind(this)); + } + + /** + * @member {Themes} themes + * @memberof Rendition + */ + this.themes = new _themes2.default(this); + + /** + * @member {Annotations} annotations + * @memberof Rendition + */ + this.annotations = new _annotations2.default(this); + + this.epubcfi = new _epubcfi2.default(); + + this.q = new _queue2.default(this); + + /** + * A Rendered Location Range + * @typedef location + * @type {Object} + * @property {object} start + * @property {string} start.index + * @property {string} start.href + * @property {object} start.displayed + * @property {EpubCFI} start.cfi + * @property {number} start.location + * @property {number} start.percentage + * @property {number} start.displayed.page + * @property {number} start.displayed.total + * @property {object} end + * @property {string} end.index + * @property {string} end.href + * @property {object} end.displayed + * @property {EpubCFI} end.cfi + * @property {number} end.location + * @property {number} end.percentage + * @property {number} end.displayed.page + * @property {number} end.displayed.total + * @property {boolean} atStart + * @property {boolean} atEnd + * @memberof Rendition + */ + this.location = undefined; + + // Hold queue until book is opened + this.q.enqueue(this.book.opened); + + this.starting = new _core.defer(); + /** + * @member {promise} started returns after the rendition has started + * @memberof Rendition + */ + this.started = this.starting.promise; + // Block the queue until rendering is started + this.q.enqueue(this.start); + } + + /** + * Set the manager function + * @param {function} manager + */ + + + _createClass(Rendition, [{ + key: "setManager", + value: function setManager(manager) { + this.manager = manager; + } + + /** + * Require the manager from passed string, or as a class function + * @param {string|object} manager [description] + * @return {method} + */ + + }, { + key: "requireManager", + value: function requireManager(manager) { + var viewManager; + + // If manager is a string, try to load from imported managers + if (typeof manager === "string" && manager === "default") { + viewManager = _index2.default; + } else if (typeof manager === "string" && manager === "continuous") { + viewManager = _index4.default; + } else { + // otherwise, assume we were passed a class function + viewManager = manager; + } + + return viewManager; + } + + /** + * Require the view from passed string, or as a class function + * @param {string|object} view + * @return {view} + */ + + }, { + key: "requireView", + value: function requireView(view) { + var View; + + // If view is a string, try to load from imported views, + if (typeof view == "string" && view === "iframe") { + View = _iframe2.default; + } else { + // otherwise, assume we were passed a class function + View = view; + } + + return View; + } + + /** + * Start the rendering + * @return {Promise} rendering has started + */ + + }, { + key: "start", + value: function start() { + + 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 + }); + } + + this.direction(this.book.package.metadata.direction); + + // 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(_constants.EVENTS.MANAGERS.ADDED, this.afterDisplayed.bind(this)); + this.manager.on(_constants.EVENTS.MANAGERS.REMOVED, this.afterRemoved.bind(this)); + + // Listen for resizing + this.manager.on(_constants.EVENTS.MANAGERS.RESIZED, this.onResized.bind(this)); + + // Listen for rotation + this.manager.on(_constants.EVENTS.MANAGERS.ORIENTATION_CHANGE, this.onOrientationChange.bind(this)); + + // Listen for scroll changes + this.manager.on(_constants.EVENTS.MANAGERS.SCROLLED, this.reportLocation.bind(this)); + + /** + * Emit that rendering has started + * @event started + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.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} + */ + + }, { + key: "attachTo", + value: function attachTo(element) { + + return this.q.enqueue(function () { + + // Start rendering + this.manager.render(element, { + "width": this.settings.width, + "height": this.settings.height + }); + + /** + * Emit that rendering has attached to an element + * @event attached + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.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} + */ + + }, { + key: "display", + value: function display(target) { + if (this.displaying) { + this.displaying.resolve(); + } + return this.q.enqueue(this._display, target); + } + + /** + * Tells the manager what to display immediately + * @private + * @param {string} target Url or EpubCFI + * @return {Promise} + */ + + }, { + key: "_display", + value: function _display(target) { + var _this = this; + + if (!this.book) { + return; + } + var isCfiString = this.epubcfi.isCfiString(target); + var displaying = new _core.defer(); + var displayed = displaying.promise; + var section; + var moveTo; + + this.displaying = displaying; + + // Check if this is a book percentage + if (this.book.locations.length() && ((0, _core.isFloat)(target) || target === "1.0") // Handle 1.0 + ) { + target = this.book.locations.cfiFromPercentage(parseFloat(target)); + } + + section = this.book.spine.get(target); + + if (!section) { + displaying.reject(new Error("No Section Found")); + return displayed; + } + + this.manager.display(section, target).then(function () { + displaying.resolve(section); + _this.displaying = undefined; + + /** + * Emit that a section has been displayed + * @event displayed + * @param {Section} section + * @memberof Rendition + */ + _this.emit(_constants.EVENTS.RENDITION.DISPLAYED, section); + _this.reportLocation(); + }, function (err) { + /** + * Emit that has been an error displaying + * @event displayError + * @param {Section} section + * @memberof Rendition + */ + _this.emit(_constants.EVENTS.RENDITION.DISPLAY_ERROR, err); + }); + + return displayed; + } + + /* + render(view, show) { + // view.onLayout = this.layout.format.bind(this.layout); + view.create(); + // Fit to size of the container, apply padding + this.manager.resizeView(view); + // Render Chain + return view.section.render(this.book.request) + .then(function(contents){ + return view.load(contents); + }.bind(this)) + .then(function(doc){ + return this.hooks.content.trigger(view, this); + }.bind(this)) + .then(function(){ + this.layout.format(view.contents); + return this.hooks.layout.trigger(view, this); + }.bind(this)) + .then(function(){ + return view.display(); + }.bind(this)) + .then(function(){ + return this.hooks.render.trigger(view, this); + }.bind(this)) + .then(function(){ + if(show !== false) { + this.q.enqueue(function(view){ + view.show(); + }, view); + } + // this.map = new Map(view, this.layout); + this.hooks.show.trigger(view, this); + this.trigger("rendered", view.section); + }.bind(this)) + .catch(function(e){ + this.trigger("loaderror", e); + }.bind(this)); + } + */ + + /** + * Report what section has been displayed + * @private + * @param {*} view + */ + + }, { + key: "afterDisplayed", + value: function afterDisplayed(view) { + var _this2 = this; + + view.on(_constants.EVENTS.VIEWS.MARK_CLICKED, function (cfiRange, data) { + return _this2.triggerMarkEvent(cfiRange, data, view); + }); + + this.hooks.render.trigger(view, this).then(function () { + if (view.contents) { + _this2.hooks.content.trigger(view.contents, _this2).then(function () { + /** + * Emit that a section has been rendered + * @event rendered + * @param {Section} section + * @param {View} view + * @memberof Rendition + */ + _this2.emit(_constants.EVENTS.RENDITION.RENDERED, view.section, view); + }); + } else { + _this2.emit(_constants.EVENTS.RENDITION.RENDERED, view.section, view); + } + }); + } + + /** + * Report what has been removed + * @private + * @param {*} view + */ + + }, { + key: "afterRemoved", + value: function afterRemoved(view) { + var _this3 = this; + + this.hooks.unloaded.trigger(view, this).then(function () { + /** + * Emit that a section has been removed + * @event removed + * @param {Section} section + * @param {View} view + * @memberof Rendition + */ + _this3.emit(_constants.EVENTS.RENDITION.REMOVED, view.section, view); + }); + } + + /** + * Report resize events and display the last seen location + * @private + */ + + }, { + key: "onResized", + value: function onResized(size) { + + /** + * Emit that the rendition has been resized + * @event resized + * @param {number} width + * @param {height} height + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.RESIZED, { + width: size.width, + height: size.height + }); + + if (this.location && this.location.start) { + this.display(this.location.start.cfi); + } + } + + /** + * Report orientation events and display the last seen location + * @private + */ + + }, { + key: "onOrientationChange", + value: function onOrientationChange(orientation) { + /** + * Emit that the rendition has been rotated + * @event orientationchange + * @param {string} orientation + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.ORIENTATION_CHANGE, orientation); + } + + /** + * Move the Rendition to a specific offset + * Usually you would be better off calling display() + * @param {object} offset + */ + + }, { + key: "moveTo", + value: function moveTo(offset) { + this.manager.moveTo(offset); + } + + /** + * Trigger a resize of the views + * @param {number} [width] + * @param {number} [height] + */ + + }, { + key: "resize", + value: function resize(width, height) { + if (width) { + this.settings.width = width; + } + if (height) { + this.settings.height = height; + } + this.manager.resize(width, height); + } + + /** + * Clear all rendered views + */ + + }, { + key: "clear", + value: function clear() { + this.manager.clear(); + } + + /** + * Go to the next "page" in the rendition + * @return {Promise} + */ + + }, { + key: "next", + value: function 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} + */ + + }, { + key: "prev", + value: function 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 + */ + + }, { + key: "determineLayoutProperties", + value: function 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; + var direction = this.settings.direction || metadata.direction || "ltr"; + + if ((this.settings.width === 0 || this.settings.width > 0) && (this.settings.height === 0 || this.settings.height > 0)) { + // viewport = "width="+this.settings.width+", height="+this.settings.height+""; + } + + properties = { + layout: layout, + spread: spread, + orientation: orientation, + flow: flow, + viewport: viewport, + minSpreadWidth: minSpreadWidth, + direction: direction + }; + + return properties; + } + + /** + * Adjust the flow of the rendition to paginated or scrolled + * (scrolled-continuous vs scrolled-doc are handled by different view managers) + * @param {string} flow + */ + + }, { + key: "flow", + value: function flow(_flow2) { + var _flow = _flow2; + if (_flow2 === "scrolled" || _flow2 === "scrolled-doc" || _flow2 === "scrolled-continuous") { + _flow = "scrolled"; + } + + if (_flow2 === "auto" || _flow2 === "paginated") { + _flow = "paginated"; + } + + this.settings.flow = _flow2; + + if (this._layout) { + this._layout.flow(_flow); + } + + if (this.manager && this._layout) { + this.manager.applyLayout(this._layout); + } + + if (this.manager) { + this.manager.updateFlow(_flow); + } + + if (this.manager && this.manager.isRendered() && this.location) { + this.manager.clear(); + this.display(this.location.start.cfi); + } + } + + /** + * Adjust the layout of the rendition to reflowable or pre-paginated + * @param {object} settings + */ + + }, { + key: "layout", + value: function layout(settings) { + var _this4 = this; + + if (settings) { + this._layout = new _layout2.default(settings); + this._layout.spread(settings.spread, this.settings.minSpreadWidth); + + // this.mapping = new Mapping(this._layout.props); + + this._layout.on(_constants.EVENTS.LAYOUT.UPDATED, function (props, changed) { + _this4.emit(_constants.EVENTS.RENDITION.LAYOUT, props, changed); + }); + } + + 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 + */ + + }, { + key: "spread", + value: function spread(_spread, min) { + + this._layout.spread(_spread, min); + + if (this.manager.isRendered()) { + this.manager.updateLayout(); + } + } + + /** + * Adjust the direction of the rendition + * @param {string} dir + */ + + }, { + key: "direction", + value: function direction(dir) { + + this.settings.direction = dir || "ltr"; + + if (this.manager) { + this.manager.direction(this.settings.direction); + } + + if (this.manager && this.manager.isRendered() && this.location) { + this.manager.clear(); + this.display(this.location.start.cfi); + } + } + + /** + * Report the current location + * @fires relocated + * @fires locationChanged + */ + + }, { + key: "reportLocation", + value: function reportLocation() { + return this.q.enqueue(function reportedLocation() { + requestAnimationFrame(function reportedLocationAfterRAF() { + var location = this.manager.currentLocation(); + if (location && location.then && typeof location.then === "function") { + location.then(function (result) { + var located = this.located(result); + + if (!located || !located.start || !located.end) { + return; + } + + this.location = located; + + this.emit(_constants.EVENTS.RENDITION.LOCATION_CHANGED, { + index: this.location.start.index, + href: this.location.start.href, + start: this.location.start.cfi, + end: this.location.end.cfi, + percentage: this.location.start.percentage + }); + + this.emit(_constants.EVENTS.RENDITION.RELOCATED, this.location); + }.bind(this)); + } else if (location) { + var located = this.located(location); + + if (!located || !located.start || !located.end) { + return; + } + + this.location = located; + + /** + * @event locationChanged + * @deprecated + * @type {object} + * @property {number} index + * @property {string} href + * @property {EpubCFI} start + * @property {EpubCFI} end + * @property {number} percentage + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.LOCATION_CHANGED, { + index: this.location.start.index, + href: this.location.start.href, + start: this.location.start.cfi, + end: this.location.end.cfi, + percentage: this.location.start.percentage + }); + + /** + * @event relocated + * @type {displayedLocation} + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.RELOCATED, this.location); + } + }.bind(this)); + }.bind(this)); + } + + /** + * Get the Current Location object + * @return {displayedLocation | promise} location (may be a promise) + */ + + }, { + key: "currentLocation", + value: function currentLocation() { + var location = this.manager.currentLocation(); + if (location && location.then && typeof location.then === "function") { + location.then(function (result) { + var located = this.located(result); + return located; + }.bind(this)); + } else if (location) { + var located = this.located(location); + return located; + } + } + + /** + * Creates a Rendition#locationRange from location + * passed by the Manager + * @returns {displayedLocation} + * @private + */ + + }, { + key: "located", + value: function located(location) { + if (!location.length) { + return {}; + } + var start = location[0]; + var end = location[location.length - 1]; + + var located = { + start: { + index: start.index, + href: start.href, + cfi: start.mapping.start, + displayed: { + page: start.pages[0] || 1, + total: start.totalPages + } + }, + end: { + index: end.index, + href: end.href, + cfi: end.mapping.end, + displayed: { + page: end.pages[end.pages.length - 1] || 1, + total: end.totalPages + } + } + }; + + var locationStart = this.book.locations.locationFromCfi(start.mapping.start); + var locationEnd = this.book.locations.locationFromCfi(end.mapping.end); + + if (locationStart != null) { + located.start.location = locationStart; + located.start.percentage = this.book.locations.percentageFromLocation(locationStart); + } + if (locationEnd != null) { + located.end.location = locationEnd; + located.end.percentage = this.book.locations.percentageFromLocation(locationEnd); + } + + var pageStart = this.book.pageList.pageFromCfi(start.mapping.start); + var pageEnd = this.book.pageList.pageFromCfi(end.mapping.end); + + if (pageStart != -1) { + located.start.page = pageStart; + } + if (pageEnd != -1) { + located.end.page = pageEnd; + } + + if (end.index === this.book.spine.last().index && located.end.displayed.page >= located.end.displayed.total) { + located.atEnd = true; + } + + if (start.index === this.book.spine.first().index && located.start.displayed.page === 1) { + located.atStart = true; + } + + return located; + } + + /** + * Remove and Clean Up the Rendition + */ + + }, { + key: "destroy", + value: function destroy() { + // Clear the queue + // this.q.clear(); + // this.q = undefined; + + this.manager && this.manager.destroy(); + + this.book = undefined; + + // this.views = null; + + // this.hooks.display.clear(); + // this.hooks.serialize.clear(); + // this.hooks.content.clear(); + // this.hooks.layout.clear(); + // this.hooks.render.clear(); + // this.hooks.show.clear(); + // this.hooks = {}; + + // this.themes.destroy(); + // this.themes = undefined; + + // this.epubcfi = undefined; + + // this.starting = undefined; + // this.started = undefined; + + } + + /** + * Pass the events from a view's Contents + * @private + * @param {View} view + */ + + }, { + key: "passEvents", + value: function passEvents(contents) { + var _this5 = this; + + var listenedEvents = _contents2.default.listenedEvents; + + listenedEvents.forEach(function (e) { + contents.on(e, function (ev) { + return _this5.triggerViewEvent(ev, contents); + }); + }); + + contents.on(_constants.EVENTS.CONTENTS.SELECTED, function (e) { + return _this5.triggerSelectedEvent(e, contents); + }); + } + + /** + * Emit events passed by a view + * @private + * @param {event} e + */ + + }, { + key: "triggerViewEvent", + value: function triggerViewEvent(e, contents) { + this.emit(e.type, e, contents); + } + + /** + * Emit a selection event's CFI Range passed from a a view + * @private + * @param {EpubCFI} cfirange + */ + + }, { + key: "triggerSelectedEvent", + value: function triggerSelectedEvent(cfirange, contents) { + /** + * Emit that a text selection has occured + * @event selected + * @param {EpubCFI} cfirange + * @param {Contents} contents + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.SELECTED, cfirange, contents); + } + + /** + * Emit a markClicked event with the cfiRange and data from a mark + * @private + * @param {EpubCFI} cfirange + */ + + }, { + key: "triggerMarkEvent", + value: function triggerMarkEvent(cfiRange, data, contents) { + /** + * Emit that a mark was clicked + * @event markClicked + * @param {EpubCFI} cfirange + * @param {object} data + * @param {Contents} contents + * @memberof Rendition + */ + this.emit(_constants.EVENTS.RENDITION.MARK_CLICKED, cfiRange, data, contents); + } + + /** + * Get a Range from a Visible CFI + * @param {string} cfi EpubCfi String + * @param {string} ignoreClass + * @return {range} + */ + + }, { + key: "getRange", + value: function getRange(cfi, ignoreClass) { + var _cfi = new _epubcfi2.default(cfi); + var found = this.manager.visible().filter(function (view) { + if (_cfi.spinePos === view.index) return true; + }); + + // Should only every return 1 item + if (found.length) { + return found[0].contents.range(_cfi, ignoreClass); + } + } + + /** + * Hook to adjust images to fit in columns + * @param {Contents} contents + * @private + */ + + }, { + key: "adjustImages", + value: function adjustImages(contents) { + + if (this._layout.name === "pre-paginated") { + return new Promise(function (resolve) { + resolve(); + }); + } + + contents.addStylesheetRules({ + "img": { + "max-width": (this._layout.columnWidth ? this._layout.columnWidth + "px" : "100%") + "!important", + "max-height": (this._layout.height ? this._layout.height * 0.6 + "px" : "60%") + "!important", + "object-fit": "contain", + "page-break-inside": "avoid" + }, + "svg": { + "max-width": (this._layout.columnWidth ? this._layout.columnWidth + "px" : "100%") + "!important", + "max-height": (this._layout.height ? this._layout.height * 0.6 + "px" : "60%") + "!important", + "page-break-inside": "avoid" + } + }); + + return new Promise(function (resolve, reject) { + // Wait to apply + setTimeout(function () { + resolve(); + }, 1); + }); + } + + /** + * Get the Contents object of each rendered view + * @returns {Contents[]} + */ + + }, { + key: "getContents", + value: function getContents() { + return this.manager ? this.manager.getContents() : []; + } + + /** + * Get the views member from the manager + * @returns {Views} + */ + + }, { + key: "views", + value: function views() { + var views = this.manager ? this.manager.views : undefined; + return views || []; + } + + /** + * Hook to handle link clicks in rendered content + * @param {Contents} contents + * @private + */ + + }, { + key: "handleLinks", + value: function handleLinks(contents) { + var _this6 = this; + + if (contents) { + contents.on(_constants.EVENTS.CONTENTS.LINK_CLICKED, function (href) { + var relative = _this6.book.path.relative(href); + _this6.display(relative); + }); + } + } + + /** + * Hook to handle injecting stylesheet before + * a Section is serialized + * @param {document} doc + * @param {Section} section + * @private + */ + + }, { + key: "injectStylesheet", + value: function injectStylesheet(doc, section) { + var style = doc.createElement("link"); + style.setAttribute("type", "text/css"); + style.setAttribute("rel", "stylesheet"); + style.setAttribute("href", this.settings.stylesheet); + doc.getElementsByTagName("head")[0].appendChild(style); + } + + /** + * Hook to handle injecting scripts before + * a Section is serialized + * @param {document} doc + * @param {Section} section + * @private + */ + + }, { + key: "injectScript", + value: function injectScript(doc, section) { + var script = doc.createElement("script"); + script.setAttribute("type", "text/javascript"); + script.setAttribute("src", this.settings.script); + script.textContent = " "; // Needed to prevent self closing tag + doc.getElementsByTagName("head")[0].appendChild(script); + } + + /** + * Hook to handle the document identifier before + * a Section is serialized + * @param {document} doc + * @param {Section} section + * @private + */ + + }, { + key: "injectIdentifier", + value: function injectIdentifier(doc, section) { + var ident = this.book.package.metadata.identifier; + var meta = doc.createElement("meta"); + meta.setAttribute("name", "dc.relation.ispartof"); + if (ident) { + meta.setAttribute("content", ident); + } + doc.getElementsByTagName("head")[0].appendChild(meta); + } + }]); + + return Rendition; +}(); + +//-- Enable binding events to Renderer + + +(0, _eventEmitter2.default)(Rendition.prototype); + +exports.default = Rendition; +module.exports = exports["default"]; + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Map text locations to CFI ranges + * @class + */ +var Mapping = function () { + function Mapping(layout, direction, axis, dev) { + _classCallCheck(this, Mapping); + + this.layout = layout; + this.horizontal = axis === "horizontal" ? true : false; + this.direction = direction || "ltr"; + this._dev = dev; + } + + /** + * Find CFI pairs for entire section at once + */ + + + _createClass(Mapping, [{ + key: "section", + value: function section(view) { + var ranges = this.findRanges(view); + var map = this.rangeListToCfiList(view.section.cfiBase, ranges); + + return map; + } + + /** + * Find CFI pairs for a page + */ + + }, { + key: "page", + value: function page(contents, cfiBase, start, end) { + var root = contents && contents.document ? contents.document.body : false; + var result; + + if (!root) { + return; + } + + result = this.rangePairToCfiPair(cfiBase, { + start: this.findStart(root, start, end), + end: this.findEnd(root, start, end) + }); + + if (this._dev === true) { + var doc = contents.document; + var startRange = new _epubcfi2.default(result.start).toRange(doc); + var endRange = new _epubcfi2.default(result.end).toRange(doc); + + var selection = doc.defaultView.getSelection(); + var r = doc.createRange(); + selection.removeAllRanges(); + r.setStart(startRange.startContainer, startRange.startOffset); + r.setEnd(endRange.endContainer, endRange.endOffset); + selection.addRange(r); + } + + return result; + } + }, { + key: "walk", + value: function walk(root, func) { + // IE11 has strange issue, if root is text node IE throws exception on + // calling treeWalker.nextNode(), saying + // Unexpected call to method or property access instead of returing null value + if (root && root.nodeType === Node.TEXT_NODE) { + return; + } + // safeFilter is required so that it can work in IE as filter is a function for IE + // and for other browser filter is an object. + var filter = { + acceptNode: function acceptNode(node) { + if (node.data.trim().length > 0) { + return NodeFilter.FILTER_ACCEPT; + } else { + return NodeFilter.FILTER_REJECT; + } + } + }; + var safeFilter = filter.acceptNode; + safeFilter.acceptNode = filter.acceptNode; + + var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, safeFilter, false); + var node; + var result; + while (node = treeWalker.nextNode()) { + result = func(node); + if (result) break; + } + + return result; + } + }, { + key: "findRanges", + value: function findRanges(view) { + var columns = []; + var scrollWidth = view.contents.scrollWidth(); + var spreads = Math.ceil(scrollWidth / this.layout.spreadWidth); + var count = spreads * this.layout.divisor; + var columnWidth = this.layout.columnWidth; + var gap = this.layout.gap; + var start, end; + + for (var i = 0; i < count.pages; i++) { + start = (columnWidth + gap) * i; + end = columnWidth * (i + 1) + gap * i; + columns.push({ + start: this.findStart(view.document.body, start, end), + end: this.findEnd(view.document.body, start, end) + }); + } + + return columns; + } + }, { + key: "findStart", + value: function findStart(root, start, end) { + var _this = this; + + 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, top, bottom; + var elPos; + var elRange; + + elPos = _this.getBounds(node); + + if (_this.horizontal && _this.direction === "ltr") { + + left = _this.horizontal ? elPos.left : elPos.top; + right = _this.horizontal ? elPos.right : elPos.bottom; + + if (left >= start && left <= end) { + return node; + } else if (right > start) { + return node; + } else { + $prev = node; + stack.push(node); + } + } else if (_this.horizontal && _this.direction === "rtl") { + + left = elPos.left; + right = elPos.right; + + if (right <= end && right >= start) { + return node; + } else if (left < end) { + return node; + } else { + $prev = node; + stack.push(node); + } + } else { + + top = elPos.top; + bottom = elPos.bottom; + + if (top >= start && top <= end) { + return node; + } else if (bottom > 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); + } + }, { + key: "findEnd", + value: function findEnd(root, start, end) { + var _this2 = this; + + 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, top, bottom; + var elPos; + var elRange; + + elPos = _this2.getBounds(node); + + if (_this2.horizontal && _this2.direction === "ltr") { + + left = Math.round(elPos.left); + right = Math.round(elPos.right); + + if (left > end && $prev) { + return $prev; + } else if (right > end) { + return node; + } else { + $prev = node; + stack.push(node); + } + } else if (_this2.horizontal && _this2.direction === "rtl") { + + left = Math.round(_this2.horizontal ? elPos.left : elPos.top); + right = Math.round(_this2.horizontal ? elPos.right : elPos.bottom); + + if (right < start && $prev) { + return $prev; + } else if (left < start) { + return node; + } else { + $prev = node; + stack.push(node); + } + } else { + + top = Math.round(elPos.top); + bottom = Math.round(elPos.bottom); + + if (top > end && $prev) { + return $prev; + } else if (bottom > 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); + } + }, { + key: "findTextStartRange", + value: function findTextStartRange(node, start, end) { + var ranges = this.splitTextNodeIntoRanges(node); + var range; + var pos; + var left, top, right; + + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; + + pos = range.getBoundingClientRect(); + + if (this.horizontal && this.direction === "ltr") { + + left = pos.left; + if (left >= start) { + return range; + } + } else if (this.horizontal && this.direction === "rtl") { + + right = pos.right; + if (right <= end) { + return range; + } + } else { + + top = pos.top; + if (top >= start) { + return range; + } + } + + // prev = range; + } + + return ranges[0]; + } + }, { + key: "findTextEndRange", + value: function findTextEndRange(node, start, end) { + var ranges = this.splitTextNodeIntoRanges(node); + var prev; + var range; + var pos; + var left, right, top, bottom; + + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; + + pos = range.getBoundingClientRect(); + + if (this.horizontal && this.direction === "ltr") { + + left = pos.left; + right = pos.right; + + if (left > end && prev) { + return prev; + } else if (right > end) { + return range; + } + } else if (this.horizontal && this.direction === "rtl") { + + left = pos.left; + right = pos.right; + + if (right < start && prev) { + return prev; + } else if (left < start) { + return range; + } + } else { + + top = pos.top; + bottom = pos.bottom; + + if (top > end && prev) { + return prev; + } else if (bottom > end) { + return range; + } + } + + prev = range; + } + + // Ends before limit + return ranges[ranges.length - 1]; + } + }, { + key: "splitTextNodeIntoRanges", + value: function splitTextNodeIntoRanges(node, _splitter) { + var ranges = []; + var textContent = node.textContent || ""; + var text = textContent.trim(); + var range; + 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; + } + }, { + key: "rangePairToCfiPair", + value: function rangePairToCfiPair(cfiBase, rangePair) { + + var startRange = rangePair.start; + var endRange = rangePair.end; + + startRange.collapse(true); + endRange.collapse(false); + + var startCfi = new _epubcfi2.default(startRange, cfiBase).toString(); + var endCfi = new _epubcfi2.default(endRange, cfiBase).toString(); + + return { + start: startCfi, + end: endCfi + }; + } + }, { + key: "rangeListToCfiList", + value: function rangeListToCfiList(cfiBase, columns) { + var map = []; + var cifPair; + + for (var i = 0; i < columns.length; i++) { + cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); + + map.push(cifPair); + } + + return map; + } + }, { + key: "getBounds", + value: function getBounds(node) { + var elPos = void 0; + if (node.nodeType == Node.TEXT_NODE) { + var elRange = document.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } + return elPos; + } + }, { + key: "axis", + value: function axis(_axis) { + if (_axis) { + this.horizontal = _axis === "horizontal" ? true : false; + } + return this.horizontal; + } + }]); + + return Mapping; +}(); + +exports.default = Mapping; +module.exports = exports["default"]; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _core = __webpack_require__(0); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _contents = __webpack_require__(13); + +var _contents2 = _interopRequireDefault(_contents); + +var _constants = __webpack_require__(3); + +var _marksPane = __webpack_require__(53); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var IframeView = function () { + function IframeView(section, options) { + _classCallCheck(this, IframeView); + + this.settings = (0, _core.extend)({ + ignoreClass: "", + axis: options.layout && options.layout.props.flow === "scrolled" ? "vertical" : "horizontal", + direction: undefined, + width: 0, + height: 0, + layout: undefined, + globalLayoutProperties: {}, + method: undefined + }, options || {}); + + this.id = "epubjs-view-" + (0, _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 _epubcfi2.default(); + + this.layout = this.settings.layout; + // Dom events to listen for + // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + + this.pane = undefined; + this.highlights = {}; + this.underlines = {}; + this.marks = {}; + } + + _createClass(IframeView, [{ + key: "container", + value: function container(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"; + element.style.position = "relative"; + element.style.display = "block"; + + if (axis && axis == "horizontal") { + element.style.flex = "none"; + } else { + element.style.flex = "initial"; + } + + return element; + } + }, { + key: "create", + value: function 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.iframe.setAttribute("enable-annotation", "true"); + + 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.setAttribute("ref", this.index); + + this.element.appendChild(this.iframe); + this.added = true; + + this.elementBounds = (0, _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 = bounds(this.iframe); + // } + + + if ("srcdoc" in this.iframe) { + this.supportsSrcdoc = true; + } else { + this.supportsSrcdoc = false; + } + + if (!this.settings.method) { + this.settings.method = this.supportsSrcdoc ? "srcdoc" : "write"; + } + + return this.iframe; + } + }, { + key: "render", + value: function 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 () { + var _this = this; + + // apply the layout function to the contents + this.layout.format(this.contents); + + // find and report the writingMode axis + var writingMode = this.contents.writingMode(); + var axis = writingMode.indexOf("vertical") === 0 ? "vertical" : "horizontal"; + + this.setAxis(axis); + this.emit(_constants.EVENTS.VIEWS.AXIS, axis); + + // Listen for events that require an expansion of the iframe + this.addListeners(); + + return new Promise(function (resolve, reject) { + // Expand the iframe to the full size of the content + _this.expand(); + resolve(); + }); + }.bind(this), function (e) { + this.emit(_constants.EVENTS.VIEWS.LOAD_ERROR, e); + return new Promise(function (resolve, reject) { + reject(e); + }); + }.bind(this)).then(function () { + this.emit(_constants.EVENTS.VIEWS.RENDERED, this.section); + }.bind(this)); + } + }, { + key: "reset", + value: function reset() { + if (this.iframe) { + this.iframe.style.width = "0"; + this.iframe.style.height = "0"; + this._width = 0; + this._height = 0; + this._textWidth = undefined; + this._contentWidth = undefined; + this._textHeight = undefined; + this._contentHeight = undefined; + } + this._needsReframe = true; + } + + // Determine locks base on settings + + }, { + key: "size", + value: function 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); + } + + this.settings.width = width; + this.settings.height = height; + } + + // Lock an axis to element dimensions, taking borders into account + + }, { + key: "lock", + value: function lock(what, width, height) { + var elBorders = (0, _core.borders)(this.element); + var iframeBorders; + + if (this.iframe) { + iframeBorders = (0, _core.borders)(this.iframe); + } else { + iframeBorders = { width: 0, height: 0 }; + } + + if (what == "width" && (0, _core.isNumber)(width)) { + this.lockedWidth = width - elBorders.width - iframeBorders.width; + // this.resize(this.lockedWidth, width); // width keeps ratio correct + } + + if (what == "height" && (0, _core.isNumber)(height)) { + this.lockedHeight = height - elBorders.height - iframeBorders.height; + // this.resize(width, this.lockedHeight); + } + + if (what === "both" && (0, _core.isNumber)(width) && (0, _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 + + }, { + key: "expand", + value: function expand(force) { + var width = this.lockedWidth; + var height = this.lockedHeight; + var columns; + + var textWidth, textHeight; + + if (!this.iframe || this._expanding) return; + + this._expanding = true; + + if (this.layout.name === "pre-paginated") { + width = this.layout.columnWidth; + height = this.layout.height; + } + // Expand Horizontally + else if (this.settings.axis === "horizontal") { + // Get the width of the text + width = this.contents.textWidth(); + + if (width % this.layout.pageWidth > 0) { + width = Math.ceil(width / this.layout.pageWidth) * this.layout.pageWidth; + } + + if (this.settings.forceEvenPages) { + columns = width / this.layout.delta; + if (this.layout.divisor > 1 && this.layout.name === "reflowable" && columns % 2 > 0) { + // add a blank page + width += this.layout.gap + this.layout.columnWidth; + } + } + } // Expand Vertically + else if (this.settings.axis === "vertical") { + height = this.contents.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.reframe(width, height); + } + + this._expanding = false; + } + }, { + key: "reframe", + value: function reframe(width, height) { + var size; + + if ((0, _core.isNumber)(width)) { + this.element.style.width = width + "px"; + this.iframe.style.width = width + "px"; + this._width = width; + } + + if ((0, _core.isNumber)(height)) { + this.element.style.height = height + "px"; + this.iframe.style.height = height + "px"; + this._height = height; + } + + var widthDelta = this.prevBounds ? width - this.prevBounds.width : width; + var heightDelta = this.prevBounds ? height - this.prevBounds.height : height; + + size = { + width: width, + height: height, + widthDelta: widthDelta, + heightDelta: heightDelta + }; + + this.pane && this.pane.render(); + + this.onResize(this, size); + + this.emit(_constants.EVENTS.VIEWS.RESIZED, size); + + this.prevBounds = size; + + this.elementBounds = (0, _core.bounds)(this.element); + } + }, { + key: "load", + value: function load(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) { + + this.onLoad(event, loading); + }.bind(this); + + if (this.settings.method === "blobUrl") { + this.blobUrl = (0, _core.createBlobUrl)(contents, "application/xhtml+xml"); + this.iframe.src = this.blobUrl; + } else if (this.settings.method === "srcdoc") { + this.iframe.srcdoc = contents; + } else { + + 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(); + } + + return loaded; + } + }, { + key: "onLoad", + value: function onLoad(event, promise) { + var _this2 = this; + + this.window = this.iframe.contentWindow; + this.document = this.iframe.contentDocument; + + this.contents = new _contents2.default(this.document, this.document.body, this.section.cfiBase, this.section.index); + + this.rendering = false; + + var link = this.document.querySelector("link[rel='canonical']"); + if (link) { + link.setAttribute("href", this.section.canonical); + } else { + link = this.document.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", this.section.canonical); + this.document.querySelector("head").appendChild(link); + } + + this.contents.on(_constants.EVENTS.CONTENTS.EXPAND, function () { + if (_this2.displayed && _this2.iframe) { + _this2.expand(); + if (_this2.contents) { + _this2.layout.format(_this2.contents); + } + } + }); + + this.contents.on(_constants.EVENTS.CONTENTS.RESIZE, function (e) { + if (_this2.displayed && _this2.iframe) { + _this2.expand(); + if (_this2.contents) { + _this2.layout.format(_this2.contents); + } + } + }); + + promise.resolve(this.contents); + } + }, { + key: "setLayout", + value: function setLayout(layout) { + this.layout = layout; + + if (this.contents) { + this.layout.format(this.contents); + this.expand(); + } + } + }, { + key: "setAxis", + value: function setAxis(axis) { + + // Force vertical for scrolled + if (this.layout.props.flow === "scrolled") { + axis = "vertical"; + } + + this.settings.axis = axis; + + if (axis == "horizontal") { + this.element.style.flex = "none"; + } else { + this.element.style.flex = "initial"; + } + + this.size(); + } + }, { + key: "addListeners", + value: function addListeners() { + //TODO: Add content listeners for expanding + } + }, { + key: "removeListeners", + value: function removeListeners(layoutFunc) { + //TODO: remove content listeners for expanding + } + }, { + key: "display", + value: function display(request) { + var displayed = new _core.defer(); + + if (!this.displayed) { + + this.render(request).then(function () { + + this.emit(_constants.EVENTS.VIEWS.DISPLAYED, this); + this.onDisplayed(this); + + this.displayed = true; + displayed.resolve(this); + }.bind(this), function (err) { + displayed.reject(err, this); + }); + } else { + displayed.resolve(this); + } + + return displayed.promise; + } + }, { + key: "show", + value: function show() { + + this.element.style.visibility = "visible"; + + if (this.iframe) { + this.iframe.style.visibility = "visible"; + } + + this.emit(_constants.EVENTS.VIEWS.SHOWN, this); + } + }, { + key: "hide", + value: function hide() { + // this.iframe.style.display = "none"; + this.element.style.visibility = "hidden"; + this.iframe.style.visibility = "hidden"; + + this.stopExpanding = true; + this.emit(_constants.EVENTS.VIEWS.HIDDEN, this); + } + }, { + key: "offset", + value: function offset() { + return { + top: this.element.offsetTop, + left: this.element.offsetLeft + }; + } + }, { + key: "width", + value: function width() { + return this._width; + } + }, { + key: "height", + value: function height() { + return this._height; + } + }, { + key: "position", + value: function position() { + return this.element.getBoundingClientRect(); + } + }, { + key: "locationOf", + value: function locationOf(target) { + var parentPos = this.iframe.getBoundingClientRect(); + var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); + + return { + "left": targetPos.left, + "top": targetPos.top + }; + } + }, { + key: "onDisplayed", + value: function onDisplayed(view) { + // Stub, override with a custom functions + } + }, { + key: "onResize", + value: function onResize(view, e) { + // Stub, override with a custom functions + } + }, { + key: "bounds", + value: function bounds(force) { + if (force || !this.elementBounds) { + this.elementBounds = (0, _core.bounds)(this.element); + } + + return this.elementBounds; + } + }, { + key: "highlight", + value: function highlight(cfiRange) { + var _this3 = this; + + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var cb = arguments[2]; + + if (!this.contents) { + return; + } + var range = this.contents.range(cfiRange); + + var emitter = function emitter() { + _this3.emit(_constants.EVENTS.VIEWS.MARK_CLICKED, cfiRange, data); + }; + + data["epubcfi"] = cfiRange; + + if (!this.pane) { + this.pane = new _marksPane.Pane(this.iframe, this.element); + } + + var m = new _marksPane.Highlight(range, "epubjs-hl", data, { 'fill': 'yellow', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply' }); + var h = this.pane.addMark(m); + + this.highlights[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] }; + + h.element.setAttribute("ref", "epubjs-hl"); + h.element.addEventListener("click", emitter); + h.element.addEventListener("touchstart", emitter); + + if (cb) { + h.element.addEventListener("click", cb); + h.element.addEventListener("touchstart", cb); + } + return h; + } + }, { + key: "underline", + value: function underline(cfiRange) { + var _this4 = this; + + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var cb = arguments[2]; + + if (!this.contents) { + return; + } + var range = this.contents.range(cfiRange); + var emitter = function emitter() { + _this4.emit(_constants.EVENTS.VIEWS.MARK_CLICKED, cfiRange, data); + }; + + data["epubcfi"] = cfiRange; + + if (!this.pane) { + this.pane = new _marksPane.Pane(this.iframe, this.element); + } + + var m = new _marksPane.Underline(range, "epubjs-ul", data, { 'stroke': 'black', 'stroke-opacity': '0.3', 'mix-blend-mode': 'multiply' }); + var h = this.pane.addMark(m); + + this.underlines[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] }; + + h.element.setAttribute("ref", "epubjs-ul"); + h.element.addEventListener("click", emitter); + h.element.addEventListener("touchstart", emitter); + + if (cb) { + h.element.addEventListener("click", cb); + h.element.addEventListener("touchstart", cb); + } + return h; + } + }, { + key: "mark", + value: function mark(cfiRange) { + var _this5 = this; + + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var cb = arguments[2]; + + + if (!this.contents) { + return; + } + + if (cfiRange in this.marks) { + var item = this.marks[cfiRange]; + return item; + } + + var range = this.contents.range(cfiRange); + if (!range) { + return; + } + var container = range.commonAncestorContainer; + var parent = container.nodeType === 1 ? container : container.parentNode; + + var emitter = function emitter(e) { + _this5.emit(_constants.EVENTS.VIEWS.MARK_CLICKED, cfiRange, data); + }; + + if (range.collapsed && container.nodeType === 1) { + range = new Range(); + range.selectNodeContents(container); + } else if (range.collapsed) { + // Webkit doesn't like collapsed ranges + range = new Range(); + range.selectNodeContents(parent); + } + + var top = void 0, + right = void 0, + left = void 0; + + if (this.layout.name === "pre-paginated" || this.settings.axis !== "horizontal") { + var pos = range.getBoundingClientRect(); + top = pos.top; + right = pos.right; + } else { + // Element might break columns, so find the left most element + var rects = range.getClientRects(); + var rect = void 0; + for (var i = 0; i != rects.length; i++) { + rect = rects[i]; + if (!left || rect.left < left) { + left = rect.left; + right = left + this.layout.columnWidth - this.layout.gap; + top = rect.top; + } + } + } + + var mark = this.document.createElement('a'); + mark.setAttribute("ref", "epubjs-mk"); + mark.style.position = "absolute"; + mark.style.top = top + "px"; + mark.style.left = right + "px"; + + mark.dataset["epubcfi"] = cfiRange; + + if (data) { + Object.keys(data).forEach(function (key) { + mark.dataset[key] = data[key]; + }); + } + + if (cb) { + mark.addEventListener("click", cb); + mark.addEventListener("touchstart", cb); + } + + mark.addEventListener("click", emitter); + mark.addEventListener("touchstart", emitter); + + this.element.appendChild(mark); + + this.marks[cfiRange] = { "element": mark, "listeners": [emitter, cb] }; + + return parent; + } + }, { + key: "unhighlight", + value: function unhighlight(cfiRange) { + var item = void 0; + if (cfiRange in this.highlights) { + item = this.highlights[cfiRange]; + + this.pane.removeMark(item.mark); + item.listeners.forEach(function (l) { + if (l) { + item.element.removeEventListener("click", l); + }; + }); + delete this.highlights[cfiRange]; + } + } + }, { + key: "ununderline", + value: function ununderline(cfiRange) { + var item = void 0; + if (cfiRange in this.underlines) { + item = this.underlines[cfiRange]; + this.pane.removeMark(item.mark); + item.listeners.forEach(function (l) { + if (l) { + item.element.removeEventListener("click", l); + }; + }); + delete this.underlines[cfiRange]; + } + } + }, { + key: "unmark", + value: function unmark(cfiRange) { + var item = void 0; + if (cfiRange in this.marks) { + item = this.marks[cfiRange]; + this.element.removeChild(item.element); + item.listeners.forEach(function (l) { + if (l) { + item.element.removeEventListener("click", l); + }; + }); + delete this.marks[cfiRange]; + } + } + }, { + key: "destroy", + value: function destroy() { + + for (var cfiRange in this.highlights) { + this.unhighlight(cfiRange); + } + + for (var _cfiRange in this.underlines) { + this.ununderline(_cfiRange); + } + + for (var _cfiRange2 in this.marks) { + this.unmark(_cfiRange2); + } + + if (this.blobUrl) { + (0, _core.revokeBlobUrl)(this.blobUrl); + } + + if (this.displayed) { + this.displayed = false; + + this.removeListeners(); + + this.stopExpanding = true; + this.element.removeChild(this.iframe); + + this.iframe = undefined; + this.contents = undefined; + + this._textWidth = null; + this._textHeight = null; + this._width = null; + this._height = null; + } + + // this.element.style.height = "0px"; + // this.element.style.width = "0px"; + } + }]); + + return IframeView; +}(); + +(0, _eventEmitter2.default)(IframeView.prototype); + +exports.default = IframeView; +module.exports = exports["default"]; + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(15), + now = __webpack_require__(58), + toNumber = __webpack_require__(60); + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max, + nativeMin = Math.min; + +/** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ +function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; +} + +module.exports = debounce; + + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +var freeGlobal = __webpack_require__(59); + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +module.exports = root; + + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +var root = __webpack_require__(22); + +/** Built-in value references. */ +var Symbol = root.Symbol; + +module.exports = Symbol; + + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _default = __webpack_require__(14); + +var _default2 = _interopRequireDefault(_default); + +var _constants = __webpack_require__(3); + +var _debounce = __webpack_require__(21); + +var _debounce2 = _interopRequireDefault(_debounce); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ContinuousViewManager = function (_DefaultViewManager) { + _inherits(ContinuousViewManager, _DefaultViewManager); + + function ContinuousViewManager(options) { + _classCallCheck(this, ContinuousViewManager); + + var _this = _possibleConstructorReturn(this, (ContinuousViewManager.__proto__ || Object.getPrototypeOf(ContinuousViewManager)).call(this, options)); + + _this.name = "continuous"; + + _this.settings = (0, _core.extend)(_this.settings || {}, { + infinite: true, + overflow: undefined, + axis: undefined, + flow: "scrolled", + offset: 500, + offsetDelta: 250, + width: undefined, + height: undefined + }); + + (0, _core.extend)(_this.settings, options.settings || {}); + + // Gap can be 0, but defaults doesn't handle that + if (options.settings.gap != "undefined" && options.settings.gap === 0) { + _this.settings.gap = options.settings.gap; + } + + _this.viewSettings = { + ignoreClass: _this.settings.ignoreClass, + axis: _this.settings.axis, + flow: _this.settings.flow, + layout: _this.layout, + width: 0, + height: 0, + forceEvenPages: false + }; + + _this.scrollTop = 0; + _this.scrollLeft = 0; + return _this; + } + + _createClass(ContinuousViewManager, [{ + key: "display", + value: function display(section, target) { + return _default2.default.prototype.display.call(this, section, target).then(function () { + return this.fill(); + }.bind(this)); + } + }, { + key: "fill", + value: function fill(_full) { + var _this2 = this; + + var full = _full || new _core.defer(); + + this.q.enqueue(function () { + return _this2.check(); + }).then(function (result) { + if (result) { + _this2.fill(full); + } else { + full.resolve(); + } + }); + + return full.promise; + } + }, { + key: "moveTo", + value: function moveTo(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.isPaginated) { + 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; + } + + if (distX > 0 || distY > 0) { + this.scrollBy(distX, distY, true); + } + } + }, { + key: "afterResized", + value: function afterResized(view) { + this.emit(_constants.EVENTS.MANAGERS.RESIZE, view.section); + } + + // Remove Previous Listeners if present + + }, { + key: "removeShownListeners", + value: function removeShownListeners(view) { + + // view.off("shown", this.afterDisplayed); + // view.off("shown", this.afterDisplayedAbove); + view.onDisplayed = function () {}; + } + }, { + key: "add", + value: function add(section) { + var _this3 = this; + + var view = this.createView(section); + + this.views.append(view); + + view.on(_constants.EVENTS.VIEWS.RESIZED, function (bounds) { + view.expanded = true; + }); + + view.on(_constants.EVENTS.VIEWS.AXIS, function (axis) { + _this3.updateAxis(axis); + }); + + // view.on(EVENTS.VIEWS.SHOWN, this.afterDisplayed.bind(this)); + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + return view.display(this.request); + } + }, { + key: "append", + value: function append(section) { + var view = this.createView(section); + + view.on(_constants.EVENTS.VIEWS.RESIZED, function (bounds) { + view.expanded = true; + }); + + /* + view.on(EVENTS.VIEWS.AXIS, (axis) => { + this.updateAxis(axis); + }); + */ + + this.views.append(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + + return view; + } + }, { + key: "prepend", + value: function prepend(section) { + var _this4 = this; + + var view = this.createView(section); + + view.on(_constants.EVENTS.VIEWS.RESIZED, function (bounds) { + _this4.counter(bounds); + view.expanded = true; + }); + + /* + view.on(EVENTS.VIEWS.AXIS, (axis) => { + this.updateAxis(axis); + }); + */ + + this.views.prepend(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + + return view; + } + }, { + key: "counter", + value: function counter(bounds) { + if (this.settings.axis === "vertical") { + this.scrollBy(0, bounds.heightDelta, true); + } else { + this.scrollBy(bounds.widthDelta, 0, true); + } + } + }, { + key: "update", + value: function 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 _core.defer(); + var promises = []; + for (var i = 0; i < viewsLength; i++) { + view = views[i]; + + isVisible = this.isVisible(view, offset, offset, container); + + if (isVisible === true) { + // console.log("visible " + view.index); + + if (!view.displayed) { + var displayed = view.display(this.request).then(function (view) { + view.show(); + }, function (err) { + view.hide(); + }); + promises.push(displayed); + } else { + view.show(); + } + visible.push(view); + } else { + this.q.enqueue(view.destroy.bind(view)); + // console.log("hidden " + view.index); + + clearTimeout(this.trimTimeout); + this.trimTimeout = setTimeout(function () { + this.q.enqueue(this.trim.bind(this)); + }.bind(this), 250); + } + } + + if (promises.length) { + return Promise.all(promises).catch(function (err) { + updating.reject(err); + }); + } else { + updating.resolve(); + return updating.promise; + } + } + }, { + key: "check", + value: function check(_offsetLeft, _offsetTop) { + var _this5 = this; + + 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 rtl = this.settings.direction === "rtl"; + var dir = horizontal && rtl ? -1 : 1; //RTL reverses scrollTop + + var offset = horizontal ? this.scrollLeft : this.scrollTop * dir; + var visibleLength = horizontal ? bounds.width : bounds.height; + var contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight; + + var prepend = function prepend() { + var first = _this5.views.first(); + var prev = first && first.section.prev(); + + if (prev) { + newViews.push(_this5.prepend(prev)); + } + }; + + var append = function append() { + var last = _this5.views.last(); + var next = last && last.section.next(); + + if (next) { + newViews.push(_this5.append(next)); + } + }; + + if (offset + visibleLength + delta >= contentLength) { + if (horizontal && rtl) { + prepend(); + } else { + append(); + } + } + + if (offset - delta < 0) { + if (horizontal && rtl) { + append(); + } else { + prepend(); + } + } + + var promises = newViews.map(function (view) { + return view.displayed; + }); + + if (newViews.length) { + return Promise.all(promises).then(function () { + if (_this5.layout.name === "pre-paginated" && _this5.layout.props.spread) { + return _this5.check(); + } + }).then(function () { + // Check to see if anything new is on screen after rendering + return _this5.update(delta); + }, function (err) { + return err; + }); + } else { + this.q.enqueue(function () { + this.update(); + }.bind(this)); + checking.resolve(false); + return checking.promise; + } + } + }, { + key: "trim", + value: function trim() { + 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; + } + }, { + key: "erase", + value: function erase(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) { + if (this.settings.axis === "vertical") { + this.scrollTo(0, prevTop - bounds.height, true); + } else { + this.scrollTo(prevLeft - bounds.width, 0, true); + } + } + } + }, { + key: "addEventListeners", + value: function addEventListeners(stage) { + + window.addEventListener("unload", function (e) { + this.ignore = true; + // this.scrollTo(0,0); + this.destroy(); + }.bind(this)); + + this.addScrollListeners(); + } + }, { + key: "addScrollListeners", + value: function addScrollListeners() { + var scroller; + + 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; + } + + 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._scrolled = (0, _debounce2.default)(this.scrolled.bind(this), 30); + // this.tick.call(window, this.onScroll.bind(this)); + + this.didScroll = false; + } + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + var scroller; + + if (this.settings.height) { + scroller = this.container; + } else { + scroller = window; + } + + scroller.removeEventListener("scroll", this.onScroll.bind(this)); + } + }, { + key: "onScroll", + value: function onScroll() { + var scrollTop = void 0; + var scrollLeft = void 0; + var dir = this.settings.direction === "rtl" ? -1 : 1; + + if (this.settings.height) { + scrollTop = this.container.scrollTop; + scrollLeft = this.container.scrollLeft; + } else { + scrollTop = window.scrollY * dir; + scrollLeft = window.scrollX * dir; + } + + this.scrollTop = scrollTop; + this.scrollLeft = scrollLeft; + + if (!this.ignore) { + + this._scrolled(); + } else { + this.ignore = false; + } + + this.scrollDeltaVert += Math.abs(scrollTop - this.prevScrollTop); + this.scrollDeltaHorz += Math.abs(scrollLeft - this.prevScrollLeft); + + this.prevScrollTop = scrollTop; + this.prevScrollLeft = scrollLeft; + + clearTimeout(this.scrollTimeout); + this.scrollTimeout = setTimeout(function () { + this.scrollDeltaVert = 0; + this.scrollDeltaHorz = 0; + }.bind(this), 150); + + this.didScroll = false; + } + }, { + key: "scrolled", + value: function scrolled() { + this.q.enqueue(function () { + this.check(); + }.bind(this)); + + this.emit(_constants.EVENTS.MANAGERS.SCROLL, { + top: this.scrollTop, + left: this.scrollLeft + }); + + clearTimeout(this.afterScrolled); + this.afterScrolled = setTimeout(function () { + this.emit(_constants.EVENTS.MANAGERS.SCROLLED, { + top: this.scrollTop, + left: this.scrollLeft + }); + }.bind(this)); + } + }, { + key: "next", + value: function next() { + + var dir = this.settings.direction; + var delta = this.layout.props.name === "pre-paginated" && this.layout.props.spread ? this.layout.props.delta * 2 : this.layout.props.delta; + + if (!this.views.length) return; + + if (this.isPaginated && this.settings.axis === "horizontal") { + + this.scrollBy(delta, 0, true); + } else { + + this.scrollBy(0, this.layout.height, true); + } + + this.q.enqueue(function () { + this.check(); + }.bind(this)); + } + }, { + key: "prev", + value: function prev() { + + var dir = this.settings.direction; + var delta = this.layout.props.name === "pre-paginated" && this.layout.props.spread ? this.layout.props.delta * 2 : this.layout.props.delta; + + if (!this.views.length) return; + + if (this.isPaginated && this.settings.axis === "horizontal") { + + this.scrollBy(-delta, 0, true); + } else { + + this.scrollBy(0, -this.layout.height, true); + } + + this.q.enqueue(function () { + this.check(); + }.bind(this)); + } + }, { + key: "updateAxis", + value: function updateAxis(axis, forceUpdate) { + + if (!this.isPaginated) { + axis = "vertical"; + } + + if (!forceUpdate && axis === this.settings.axis) { + return; + } + + this.settings.axis = axis; + + this.stage && this.stage.axis(axis); + + this.viewSettings.axis = axis; + + if (this.mapping) { + this.mapping.axis(axis); + } + + if (this.layout) { + if (axis === "vertical") { + this.layout.spread("none"); + } else { + this.layout.spread(this.layout.settings.spread); + } + } + + if (axis === "vertical") { + this.settings.infinite = true; + } else { + this.settings.infinite = false; + } + } + }]); + + return ContinuousViewManager; +}(_default2.default); + +exports.default = ContinuousViewManager; +module.exports = exports["default"]; + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _book = __webpack_require__(26); + +var _book2 = _interopRequireDefault(_book); + +var _rendition = __webpack_require__(18); + +var _rendition2 = _interopRequireDefault(_rendition); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _contents = __webpack_require__(13); + +var _contents2 = _interopRequireDefault(_contents); + +var _core = __webpack_require__(0); + +var utils = _interopRequireWildcard(_core); + +__webpack_require__(69); + +var _iframe = __webpack_require__(20); + +var _iframe2 = _interopRequireDefault(_iframe); + +var _default = __webpack_require__(14); + +var _default2 = _interopRequireDefault(_default); + +var _continuous = __webpack_require__(24); + +var _continuous2 = _interopRequireDefault(_continuous); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Creates a new Book + * @param {string|ArrayBuffer} url URL, Path or ArrayBuffer + * @param {object} options to pass to the book + * @returns {Book} a new Book object + * @example ePub("/path/to/book.epub", {}) + */ +function ePub(url, options) { + return new _book2.default(url, options); +} + +ePub.VERSION = "0.3"; + +if (typeof global !== "undefined") { + global.EPUBJS_VERSION = ePub.VERSION; +} + +ePub.Book = _book2.default; +ePub.Rendition = _rendition2.default; +ePub.Contents = _contents2.default; +ePub.CFI = _epubcfi2.default; +ePub.utils = utils; + +exports.default = ePub; +module.exports = exports["default"]; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(8))) + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _core = __webpack_require__(0); + +var _url = __webpack_require__(5); + +var _url2 = _interopRequireDefault(_url); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +var _spine = __webpack_require__(42); + +var _spine2 = _interopRequireDefault(_spine); + +var _locations = __webpack_require__(44); + +var _locations2 = _interopRequireDefault(_locations); + +var _container = __webpack_require__(45); + +var _container2 = _interopRequireDefault(_container); + +var _packaging = __webpack_require__(46); + +var _packaging2 = _interopRequireDefault(_packaging); + +var _navigation = __webpack_require__(47); + +var _navigation2 = _interopRequireDefault(_navigation); + +var _resources = __webpack_require__(48); + +var _resources2 = _interopRequireDefault(_resources); + +var _pagelist = __webpack_require__(49); + +var _pagelist2 = _interopRequireDefault(_pagelist); + +var _rendition = __webpack_require__(18); + +var _rendition2 = _interopRequireDefault(_rendition); + +var _archive = __webpack_require__(67); + +var _archive2 = _interopRequireDefault(_archive); + +var _request2 = __webpack_require__(11); + +var _request3 = _interopRequireDefault(_request2); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _constants = __webpack_require__(3); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var CONTAINER_PATH = "META-INF/container.xml"; +var EPUBJS_VERSION = "0.3"; + +var INPUT_TYPE = { + BINARY: "binary", + BASE64: "base64", + EPUB: "epub", + OPF: "opf", + MANIFEST: "json", + DIRECTORY: "directory" +}; + +/** + * An Epub representation with methods for the loading, parsing and manipulation + * of its contents. + * @class + * @param {string} [url] + * @param {object} [options] + * @param {method} [options.requestMethod] a request function to use instead of the default + * @param {boolean} [options.requestCredentials=undefined] send the xhr request withCredentials + * @param {object} [options.requestHeaders=undefined] send the xhr request headers + * @param {string} [options.encoding=binary] optional to pass 'binary' or base64' for archived Epubs + * @param {string} [options.replacements=none] use base64, blobUrl, or none for replacing assets in archived Epubs + * @param {method} [options.canonical] optional function to determine canonical urls for a path + * @returns {Book} + * @example new Book("/path/to/book.epub", {}) + * @example new Book({ replacements: "blobUrl" }) + */ + +var Book = function () { + function Book(url, options) { + var _this = this; + + _classCallCheck(this, Book); + + // Allow passing just options to the Book + if (typeof options === "undefined" && (typeof url === "undefined" ? "undefined" : _typeof(url)) === "object") { + options = url; + url = undefined; + } + + this.settings = (0, _core.extend)(this.settings || {}, { + requestMethod: undefined, + requestCredentials: undefined, + requestHeaders: undefined, + encoding: undefined, + replacements: undefined, + canonical: undefined + }); + + (0, _core.extend)(this.settings, options); + + // Promises + this.opening = new _core.defer(); + /** + * @member {promise} opened returns after the book is loaded + * @memberof Book + */ + this.opened = this.opening.promise; + this.isOpen = false; + + this.loading = { + manifest: new _core.defer(), + spine: new _core.defer(), + metadata: new _core.defer(), + cover: new _core.defer(), + navigation: new _core.defer(), + pageList: new _core.defer(), + resources: new _core.defer() + }; + + 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 + }; + + /** + * @member {promise} ready returns after the book is loaded and parsed + * @memberof Book + * @private + */ + this.ready = Promise.all([this.loaded.manifest, this.loaded.spine, this.loaded.metadata, this.loaded.cover, this.loaded.navigation, this.loaded.resources]); + + // Queue for methods used before opening + this.isRendered = false; + // this._q = queue(this); + + /** + * @member {method} request + * @memberof Book + * @private + */ + this.request = this.settings.requestMethod || _request3.default; + + /** + * @member {Spine} spine + * @memberof Book + */ + this.spine = new _spine2.default(); + + /** + * @member {Locations} locations + * @memberof Book + */ + this.locations = new _locations2.default(this.spine, this.load.bind(this)); + + /** + * @member {Navigation} navigation + * @memberof Book + */ + this.navigation = undefined; + + /** + * @member {PageList} pagelist + * @memberof Book + */ + this.pageList = undefined; + + /** + * @member {Url} url + * @memberof Book + * @private + */ + this.url = undefined; + + /** + * @member {Path} path + * @memberof Book + * @private + */ + this.path = undefined; + + /** + * @member {boolean} archived + * @memberof Book + * @private + */ + this.archived = false; + + /** + * @member {Archive} archive + * @memberof Book + * @private + */ + this.archive = undefined; + + /** + * @member {Resources} resources + * @memberof Book + * @private + */ + this.resources = undefined; + + /** + * @member {Rendition} rendition + * @memberof Book + * @private + */ + this.rendition = undefined; + + /** + * @member {Container} container + * @memberof Book + * @private + */ + this.container = undefined; + + /** + * @member {Packaging} packaging + * @memberof Book + * @private + */ + this.packaging = undefined; + + // this.toc = undefined; + + if (url) { + this.open(url).catch(function (error) { + var err = new Error("Cannot load book at " + url); + _this.emit(_constants.EVENTS.BOOK.OPEN_FAILED, err); + }); + } + } + + /** + * Open a epub or url + * @param {string | ArrayBuffer} input Url, Path or ArrayBuffer + * @param {string} [what="binary", "base64", "epub", "opf", "json", "directory"] force opening as a certain type + * @returns {Promise} of when the book has been loaded + * @example book.open("/path/to/book.epub") + */ + + + _createClass(Book, [{ + key: "open", + value: function open(input, what) { + var opening; + var type = what || this.determineType(input); + + if (type === INPUT_TYPE.BINARY) { + this.archived = true; + this.url = new _url2.default("/", ""); + opening = this.openEpub(input); + } else if (type === INPUT_TYPE.BASE64) { + this.archived = true; + this.url = new _url2.default("/", ""); + opening = this.openEpub(input, type); + } else if (type === INPUT_TYPE.EPUB) { + this.archived = true; + this.url = new _url2.default("/", ""); + opening = this.request(input, "binary").then(this.openEpub.bind(this)); + } else if (type == INPUT_TYPE.OPF) { + this.url = new _url2.default(input); + opening = this.openPackaging(this.url.Path.toString()); + } else if (type == INPUT_TYPE.MANIFEST) { + this.url = new _url2.default(input); + opening = this.openManifest(this.url.Path.toString()); + } else { + this.url = new _url2.default(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} + */ + + }, { + key: "openEpub", + value: function openEpub(data, encoding) { + var _this2 = this; + + return this.unarchive(data, encoding || this.settings.encoding).then(function () { + return _this2.openContainer(CONTAINER_PATH); + }).then(function (packagePath) { + return _this2.openPackaging(packagePath); + }); + } + + /** + * Open the epub container + * @private + * @param {string} url + * @return {string} packagePath + */ + + }, { + key: "openContainer", + value: function openContainer(url) { + var _this3 = this; + + return this.load(url).then(function (xml) { + _this3.container = new _container2.default(xml); + return _this3.resolve(_this3.container.packagePath); + }); + } + + /** + * Open the Open Packaging Format Xml + * @private + * @param {string} url + * @return {Promise} + */ + + }, { + key: "openPackaging", + value: function openPackaging(url) { + var _this4 = this; + + this.path = new _path2.default(url); + return this.load(url).then(function (xml) { + _this4.packaging = new _packaging2.default(xml); + return _this4.unpack(_this4.packaging); + }); + } + + /** + * Open the manifest JSON + * @private + * @param {string} url + * @return {Promise} + */ + + }, { + key: "openManifest", + value: function openManifest(url) { + var _this5 = this; + + this.path = new _path2.default(url); + return this.load(url).then(function (json) { + _this5.packaging = new _packaging2.default(); + _this5.packaging.load(json); + return _this5.unpack(_this5.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 + */ + + }, { + key: "load", + value: function 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 + */ + + }, { + key: "resolve", + value: function resolve(path, absolute) { + if (!path) { + return; + } + 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; + } + + /** + * Get a canonical link to a path + * @param {string} path + * @return {string} the canonical path string + */ + + }, { + key: "canonical", + value: function canonical(path) { + var url = path; + + if (!path) { + return ""; + } + + if (this.settings.canonical) { + url = this.settings.canonical(path); + } else { + url = this.resolve(path, true); + } + + return url; + } + + /** + * Determine the type of they input passed to open + * @private + * @param {string} input + * @return {string} binary | directory | epub | opf + */ + + }, { + key: "determineType", + value: function determineType(input) { + var url; + var path; + var extension; + + if (this.settings.encoding === "base64") { + return INPUT_TYPE.BASE64; + } + + if (typeof input != "string") { + return INPUT_TYPE.BINARY; + } + + url = new _url2.default(input); + path = url.path(); + extension = path.extension; + + if (!extension) { + return INPUT_TYPE.DIRECTORY; + } + + if (extension === "epub") { + return INPUT_TYPE.EPUB; + } + + if (extension === "opf") { + return INPUT_TYPE.OPF; + } + + if (extension === "json") { + return INPUT_TYPE.MANIFEST; + } + } + + /** + * unpack the contents of the Books packageXml + * @private + * @param {document} packageXml XML Document + */ + + }, { + key: "unpack", + value: function unpack(opf) { + var _this6 = this; + + this.package = opf; + + this.spine.unpack(this.package, this.resolve.bind(this), this.canonical.bind(this)); + + this.resources = new _resources2.default(this.package.manifest, { + archive: this.archive, + resolver: this.resolve.bind(this), + request: this.request.bind(this), + replacements: this.settings.replacements || (this.archived ? "blobUrl" : "base64") + }); + + this.loadNavigation(this.package).then(function () { + // this.toc = this.navigation.toc; + _this6.loading.navigation.resolve(_this6.navigation); + }); + + if (this.package.coverPath) { + 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.settings.replacements && this.settings.replacements != "none") { + this.replacements().then(function () { + _this6.opening.resolve(_this6); + }).catch(function (err) { + console.error(err); + }); + } else { + // Resolve book opened promise + this.opening.resolve(this); + } + } + + /** + * Load Navigation and PageList from package + * @private + * @param {document} opf XML Document + */ + + }, { + key: "loadNavigation", + value: function loadNavigation(opf) { + var _this7 = this; + + var navPath = opf.navPath || opf.ncxPath; + var toc = opf.toc; + + // From json manifest + if (toc) { + return new Promise(function (resolve, reject) { + _this7.navigation = new _navigation2.default(toc); + + if (opf.pageList) { + _this7.pageList = new _pagelist2.default(opf.pageList); // TODO: handle page lists from Manifest + } + + resolve(_this7.navigation); + }); + } + + if (!navPath) { + return new Promise(function (resolve, reject) { + _this7.navigation = new _navigation2.default(); + _this7.pageList = new _pagelist2.default(); + + resolve(_this7.navigation); + }); + } + + return this.load(navPath, "xml").then(function (xml) { + _this7.navigation = new _navigation2.default(xml); + _this7.pageList = new _pagelist2.default(xml); + return _this7.navigation; + }); + } + + /** + * Gets a Section of the Book from the Spine + * Alias for `book.spine.get` + * @param {string} target + * @return {Section} + */ + + }, { + key: "section", + value: function section(target) { + return this.spine.get(target); + } + + /** + * Sugar to render a book to an element + * @param {element | string} element element or string to add a rendition to + * @param {object} [options] + * @return {Rendition} + */ + + }, { + key: "renderTo", + value: function renderTo(element, options) { + this.rendition = new _rendition2.default(this, options); + this.rendition.attachTo(element); + + return this.rendition; + } + + /** + * Set if request should use withCredentials + * @param {boolean} credentials + */ + + }, { + key: "setRequestCredentials", + value: function setRequestCredentials(credentials) { + this.settings.requestCredentials = credentials; + } + + /** + * Set headers request should use + * @param {object} headers + */ + + }, { + key: "setRequestHeaders", + value: function setRequestHeaders(headers) { + this.settings.requestHeaders = headers; + } + + /** + * Unarchive a zipped epub + * @private + * @param {binary} input epub data + * @param {string} [encoding] + * @return {Archive} + */ + + }, { + key: "unarchive", + value: function unarchive(input, encoding) { + this.archive = new _archive2.default(); + return this.archive.open(input, encoding); + } + + /** + * Get the cover url + * @return {string} coverUrl + */ + + }, { + key: "coverUrl", + value: function coverUrl() { + var _this8 = this; + + var retrieved = this.loaded.cover.then(function (url) { + if (_this8.archived) { + // return this.archive.createUrl(this.cover); + return _this8.resources.get(_this8.cover); + } else { + return _this8.cover; + } + }); + + return retrieved; + } + + /** + * Load replacement urls + * @private + * @return {Promise} completed loading urls + */ + + }, { + key: "replacements", + value: function replacements() { + var _this9 = this; + + this.spine.hooks.serialize.register(function (output, section) { + section.output = _this9.resources.substitute(output, section.url); + }); + + return this.resources.replacements().then(function () { + return _this9.resources.replaceCss(); + }); + } + + /** + * Find a DOM Range for a given CFI Range + * @param {EpubCFI} cfiRange a epub cfi range + * @return {Range} + */ + + }, { + key: "getRange", + value: function getRange(cfiRange) { + var cfi = new _epubcfi2.default(cfiRange); + var item = this.spine.get(cfi.spinePos); + var _request = this.load.bind(this); + if (!item) { + return new Promise(function (resolve, reject) { + reject("CFI could not be found"); + }); + } + return item.load(_request).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 + */ + + }, { + key: "key", + value: function key(identifier) { + var ident = identifier || this.package.metadata.identifier || this.url.filename; + return "epubjs:" + EPUBJS_VERSION + ":" + ident; + } + + /** + * Destroy the Book and all associated objects + */ + + }, { + key: "destroy", + value: function destroy() { + this.opened = undefined; + this.loading = undefined; + this.loaded = undefined; + this.ready = undefined; + + this.isOpen = false; + this.isRendered = false; + + this.spine && this.spine.destroy(); + this.locations && this.locations.destroy(); + this.pageList && this.pageList.destroy(); + this.archive && this.archive.destroy(); + this.resources && this.resources.destroy(); + this.container && this.container.destroy(); + this.packaging && this.packaging.destroy(); + this.rendition && this.rendition.destroy(); + + this.spine = undefined; + this.locations = undefined; + this.pageList = undefined; + this.archive = undefined; + this.resources = undefined; + this.container = undefined; + this.packaging = undefined; + this.rendition = undefined; + + this.navigation = undefined; + this.url = undefined; + this.path = undefined; + this.archived = false; + } + }]); + + return Book; +}(); + +//-- Enable binding events to book + + +(0, _eventEmitter2.default)(Book.prototype); + +exports.default = Book; +module.exports = exports["default"]; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var assign = __webpack_require__(28) + , normalizeOpts = __webpack_require__(36) + , isCallable = __webpack_require__(37) + , contains = __webpack_require__(38) + + , d; + +d = module.exports = function (dscr, value/*, options*/) { + var c, e, w, options, desc; + if ((arguments.length < 2) || (typeof dscr !== 'string')) { + options = value; + value = dscr; + dscr = null; + } else { + options = arguments[2]; + } + if (dscr == null) { + c = w = true; + e = false; + } else { + c = contains.call(dscr, 'c'); + e = contains.call(dscr, 'e'); + w = contains.call(dscr, 'w'); + } + + desc = { value: value, configurable: c, enumerable: e, writable: w }; + return !options ? desc : assign(normalizeOpts(options), desc); +}; + +d.gs = function (dscr, get, set/*, options*/) { + var c, e, options, desc; + if (typeof dscr !== 'string') { + options = set; + set = get; + get = dscr; + dscr = null; + } else { + options = arguments[3]; + } + if (get == null) { + get = undefined; + } else if (!isCallable(get)) { + options = get; + get = set = undefined; + } else if (set == null) { + set = undefined; + } else if (!isCallable(set)) { + options = set; + set = undefined; + } + if (dscr == null) { + c = true; + e = false; + } else { + c = contains.call(dscr, 'c'); + e = contains.call(dscr, 'e'); + } + + desc = { get: get, set: set, configurable: c, enumerable: e }; + return !options ? desc : assign(normalizeOpts(options), desc); +}; + + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = __webpack_require__(29)() + ? Object.assign + : __webpack_require__(30); + + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function () { + var assign = Object.assign, obj; + if (typeof assign !== "function") return false; + obj = { foo: "raz" }; + assign(obj, { bar: "dwa" }, { trzy: "trzy" }); + return (obj.foo + obj.bar + obj.trzy) === "razdwatrzy"; +}; + + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var keys = __webpack_require__(31) + , value = __webpack_require__(35) + , max = Math.max; + +module.exports = function (dest, src /*, …srcn*/) { + var error, i, length = max(arguments.length, 2), assign; + dest = Object(value(dest)); + assign = function (key) { + try { + dest[key] = src[key]; + } catch (e) { + if (!error) error = e; + } + }; + for (i = 1; i < length; ++i) { + src = arguments[i]; + keys(src).forEach(assign); + } + if (error !== undefined) throw error; + return dest; +}; + + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = __webpack_require__(32)() + ? Object.keys + : __webpack_require__(33); + + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function () { + try { + Object.keys("primitive"); + return true; + } catch (e) { + return false; +} +}; + + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isValue = __webpack_require__(9); + +var keys = Object.keys; + +module.exports = function (object) { + return keys(isValue(object) ? Object(object) : object); +}; + + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +// eslint-disable-next-line no-empty-function +module.exports = function () {}; + + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isValue = __webpack_require__(9); + +module.exports = function (value) { + if (!isValue(value)) throw new TypeError("Cannot use null or undefined"); + return value; +}; + + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isValue = __webpack_require__(9); + +var forEach = Array.prototype.forEach, create = Object.create; + +var process = function (src, obj) { + var key; + for (key in src) obj[key] = src[key]; +}; + +// eslint-disable-next-line no-unused-vars +module.exports = function (opts1 /*, …options*/) { + var result = create(null); + forEach.call(arguments, function (options) { + if (!isValue(options)) return; + process(Object(options), result); + }); + return result; +}; + + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +// Deprecated + + + +module.exports = function (obj) { + return typeof obj === "function"; +}; + + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = __webpack_require__(39)() + ? String.prototype.contains + : __webpack_require__(40); + + +/***/ }), +/* 39 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var str = "razdwatrzy"; + +module.exports = function () { + if (typeof str.contains !== "function") return false; + return (str.contains("dwa") === true) && (str.contains("foo") === false); +}; + + +/***/ }), +/* 40 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var indexOf = String.prototype.indexOf; + +module.exports = function (searchString/*, position*/) { + return indexOf.call(this, searchString, arguments[1]) > -1; +}; + + +/***/ }), +/* 41 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function (fn) { + if (typeof fn !== "function") throw new TypeError(fn + " is not a function"); + return fn; +}; + + +/***/ }), +/* 42 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _hook = __webpack_require__(10); + +var _hook2 = _interopRequireDefault(_hook); + +var _section = __webpack_require__(43); + +var _section2 = _interopRequireDefault(_section); + +var _replacements = __webpack_require__(7); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * A collection of Spine Items + */ +var Spine = function () { + function Spine() { + _classCallCheck(this, Spine); + + this.spineItems = []; + this.spineByHref = {}; + this.spineById = {}; + + this.hooks = {}; + this.hooks.serialize = new _hook2.default(); + this.hooks.content = new _hook2.default(); + + // Register replacements + this.hooks.content.register(_replacements.replaceBase); + this.hooks.content.register(_replacements.replaceCanonical); + this.hooks.content.register(_replacements.replaceMeta); + + this.epubcfi = new _epubcfi2.default(); + + this.loaded = false; + + this.items = undefined; + this.manifest = undefined; + this.spineNodeIndex = undefined; + this.baseUrl = undefined; + this.length = undefined; + } + + /** + * Unpack items from a opf into spine items + * @param {Package} _package + * @param {method} resolver URL resolver + */ + + + _createClass(Spine, [{ + key: "unpack", + value: function unpack(_package, resolver, canonical) { + var _this = this; + + 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 manifestItem = _this.manifest[item.idref]; + var spineItem; + + item.index = index; + item.cfiBase = _this.epubcfi.generateChapterComponent(_this.spineNodeIndex, item.index, item.idref); + + if (item.href) { + item.url = resolver(item.href, true); + item.canonical = canonical(item.href); + } + + if (manifestItem) { + item.href = manifestItem.href; + item.url = resolver(item.href, true); + item.canonical = canonical(item.href); + + if (manifestItem.properties.length) { + item.properties.push.apply(item.properties, manifestItem.properties); + } + } + + if (item.linear === "yes") { + item.prev = function () { + var prevIndex = item.index; + while (prevIndex > 0) { + var prev = this.get(prevIndex - 1); + if (prev && prev.linear) { + return prev; + } + prevIndex -= 1; + } + return; + }.bind(_this); + item.next = function () { + var nextIndex = item.index; + while (nextIndex < this.spineItems.length - 1) { + var next = this.get(nextIndex + 1); + if (next && next.linear) { + return next; + } + nextIndex += 1; + } + return; + }.bind(_this); + } else { + item.prev = function () { + return; + }; + item.next = function () { + return; + }; + } + + spineItem = new _section2.default(item, _this.hooks); + + _this.append(spineItem); + }); + + 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"); + */ + + }, { + key: "get", + value: function get(target) { + var index = 0; + + if (typeof target === "undefined") { + while (index < this.spineItems.length) { + var next = this.spineItems[index]; + if (next && next.linear) { + break; + } + index += 1; + } + } else if (this.epubcfi.isCfiString(target)) { + var cfi = new _epubcfi2.default(target); + index = cfi.spinePos; + } else if (typeof target === "number" || isNaN(target) === false) { + index = target; + } else if (typeof target === "string" && target.indexOf("#") === 0) { + index = this.spineById[target.substring(1)]; + } else if (typeof target === "string") { + // Remove fragments + target = target.split("#")[0]; + index = this.spineByHref[target] || this.spineByHref[encodeURI(target)]; + } + + return this.spineItems[index] || null; + } + + /** + * Append a Section to the Spine + * @private + * @param {Section} section + */ + + }, { + key: "append", + value: function append(section) { + var index = this.spineItems.length; + section.index = index; + + this.spineItems.push(section); + + // Encode and Decode href lookups + // see pr for details: https://github.com/futurepress/epub.js/pull/358 + this.spineByHref[decodeURI(section.href)] = index; + this.spineByHref[encodeURI(section.href)] = index; + this.spineByHref[section.href] = index; + + this.spineById[section.idref] = index; + + return index; + } + + /** + * Prepend a Section to the Spine + * @private + * @param {Section} section + */ + + }, { + key: "prepend", + value: function prepend(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; + } + + // insert(section, index) { + // + // }; + + /** + * Remove a Section from the Spine + * @private + * @param {Section} section + */ + + }, { + key: "remove", + value: function remove(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 + */ + + }, { + key: "each", + value: function each() { + return this.spineItems.forEach.apply(this.spineItems, arguments); + } + }, { + key: "first", + value: function first() { + var index = 0; + + do { + var next = this.get(index); + + if (next && next.linear) { + return next; + } + index += 1; + } while (index < this.spineItems.length); + } + }, { + key: "last", + value: function last() { + var index = this.spineItems.length - 1; + + do { + var prev = this.get(index); + if (prev && prev.linear) { + return prev; + } + index -= 1; + } while (index >= 0); + } + }, { + key: "destroy", + value: function destroy() { + this.each(function (section) { + return section.destroy(); + }); + + this.spineItems = undefined; + this.spineByHref = undefined; + this.spineById = undefined; + + this.hooks.serialize.clear(); + this.hooks.content.clear(); + this.hooks = undefined; + + this.epubcfi = undefined; + + this.loaded = false; + + this.items = undefined; + this.manifest = undefined; + this.spineNodeIndex = undefined; + this.baseUrl = undefined; + this.length = undefined; + } + }]); + + return Spine; +}(); + +exports.default = Spine; +module.exports = exports["default"]; + +/***/ }), +/* 43 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _hook = __webpack_require__(10); + +var _hook2 = _interopRequireDefault(_hook); + +var _replacements = __webpack_require__(7); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Represents a Section of the Book + * + * In most books this is equivelent to a Chapter + * @param {object} item The spine item representing the section + * @param {object} hooks hooks for serialize and content + */ +var Section = function () { + function Section(item, hooks) { + _classCallCheck(this, Section); + + this.idref = item.idref; + this.linear = item.linear === "yes"; + this.properties = item.properties; + this.index = item.index; + this.href = item.href; + this.url = item.url; + this.canonical = item.canonical; + this.next = item.next; + this.prev = item.prev; + + this.cfiBase = item.cfiBase; + + if (hooks) { + this.hooks = hooks; + } else { + this.hooks = {}; + this.hooks.serialize = new _hook2.default(this); + this.hooks.content = new _hook2.default(this); + } + + this.document = undefined; + this.contents = undefined; + this.output = undefined; + } + + /** + * Load the section from its url + * @param {method} _request a request method to use for loading + * @return {document} a promise with the xml document + */ + + + _createClass(Section, [{ + key: "load", + value: function load(_request) { + var request = _request || this.request || __webpack_require__(11); + var loading = new _core.defer(); + var loaded = loading.promise; + + if (this.contents) { + loading.resolve(this.contents); + } else { + request(this.url).then(function (xml) { + // 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 + */ + + }, { + key: "base", + value: function base() { + return (0, _replacements.replaceBase)(this.document, this); + } + + /** + * Render the contents of a section + * @param {method} _request a request method to use for loading + * @return {string} output a serialized XML Document + */ + + }, { + key: "render", + value: function render(_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 userAgent = typeof navigator !== 'undefined' && navigator.userAgent || ''; + var isIE = userAgent.indexOf('Trident') >= 0; + var Serializer; + if (typeof XMLSerializer === "undefined" || isIE) { + Serializer = __webpack_require__(16).XMLSerializer; + } else { + Serializer = XMLSerializer; + } + var serializer = new Serializer(); + 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 + * @param {string} _query The query string to find + * @return {object[]} A list of matches, with form {cfi, excerpt} + */ + + }, { + key: "find", + value: function find(_query) { + var section = this; + var matches = []; + var query = _query.toLowerCase(); + var find = function find(node) { + var text = node.textContent.toLowerCase(); + var range = section.document.createRange(); + var cfi; + var pos; + var last = -1; + var excerpt; + var limit = 150; + + while (pos != -1) { + // Search for the query + pos = text.indexOf(query, last + 1); + + if (pos != -1) { + // We found it! Generate a CFI + range = section.document.createRange(); + range.setStart(node, pos); + range.setEnd(node, pos + query.length); + + cfi = section.cfiFromRange(range); + + // Generate the excerpt + if (node.textContent.length < limit) { + excerpt = node.textContent; + } else { + excerpt = node.textContent.substring(pos - limit / 2, pos + limit / 2); + excerpt = "..." + excerpt + "..."; + } + + // Add the CFI to the matches list + matches.push({ + cfi: cfi, + excerpt: excerpt + }); + } + + last = pos; + } + }; + + (0, _core.sprint)(section.document, function (node) { + find(node); + }); + + return matches; + } + }, { + key: "reconcileLayoutSettings", + + + /** + * 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 + */ + value: function 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 + */ + + }, { + key: "cfiFromRange", + value: function cfiFromRange(_range) { + return new _epubcfi2.default(_range, this.cfiBase).toString(); + } + + /** + * Get a CFI from an Element in the Section + * @param {element} el + * @return {string} cfi an EpubCFI string + */ + + }, { + key: "cfiFromElement", + value: function cfiFromElement(el) { + return new _epubcfi2.default(el, this.cfiBase).toString(); + } + + /** + * Unload the section document + */ + + }, { + key: "unload", + value: function unload() { + this.document = undefined; + this.contents = undefined; + this.output = undefined; + } + }, { + key: "destroy", + value: function destroy() { + this.unload(); + this.hooks.serialize.clear(); + this.hooks.content.clear(); + + this.hooks = undefined; + this.idref = undefined; + this.linear = undefined; + this.properties = undefined; + this.index = undefined; + this.href = undefined; + this.url = undefined; + this.next = undefined; + this.prev = undefined; + + this.cfiBase = undefined; + } + }]); + + return Section; +}(); + +exports.default = Section; +module.exports = exports["default"]; + +/***/ }), +/* 44 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _queue = __webpack_require__(12); + +var _queue2 = _interopRequireDefault(_queue); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _constants = __webpack_require__(3); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Find Locations for a Book + * @param {Spine} spine + * @param {request} request + */ +var Locations = function () { + function Locations(spine, request, pause) { + _classCallCheck(this, Locations); + + this.spine = spine; + this.request = request; + this.pause = pause || 100; + + this.q = new _queue2.default(this); + this.epubcfi = new _epubcfi2.default(); + + this._locations = []; + this.total = 0; + + this.break = 150; + + this._current = 0; + + this.currentLocation = ''; + this._currentCfi = ''; + this.processingTimeout = undefined; + } + + /** + * Load all of sections in the book to generate locations + * @param {int} chars how many chars to split on + * @return {object} locations + */ + + + _createClass(Locations, [{ + key: "generate", + value: function generate(chars) { + + if (chars) { + this.break = chars; + } + + this.q.pause(); + + this.spine.each(function (section) { + if (section.linear) { + 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)); + } + }, { + key: "createRange", + value: function createRange() { + return { + startContainer: undefined, + startOffset: undefined, + endContainer: undefined, + endOffset: undefined + }; + } + }, { + key: "process", + value: function process(section) { + + return section.load(this.request).then(function (contents) { + var completed = new _core.defer(); + var locations = this.parse(contents, section.cfiBase); + this._locations = this._locations.concat(locations); + + section.unload(); + + this.processingTimeout = setTimeout(function () { + return completed.resolve(locations); + }, this.pause); + return completed.promise; + }.bind(this)); + } + }, { + key: "parse", + value: function parse(contents, cfiBase, chars) { + var locations = []; + var range; + var doc = contents.ownerDocument; + var body = (0, _core.qs)(doc, "body"); + var counter = 0; + var prev; + var _break = chars || this.break; + var parser = function parser(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) { + dist = _break - counter; + + if (counter === 0) { + // Start new range + pos += 1; + range = this.createRange(); + range.startContainer = node; + range.startOffset = pos; + } + + // pos += dist; + + // Gone over + if (pos + dist >= len) { + // Continue counter for next node + counter += len - pos; + // break + pos = len; + // At End + } else { + // Advance pos + pos += dist; + + // End the previous range + range.endContainer = node; + range.endOffset = pos; + // cfi = section.cfiFromRange(range); + var cfi = new _epubcfi2.default(range, cfiBase).toString(); + locations.push(cfi); + counter = 0; + } + } + prev = node; + }; + + (0, _core.sprint)(body, parser.bind(this)); + + // Close remaining + if (range && range.startContainer && prev) { + range.endContainer = prev; + range.endOffset = prev.length; + var cfi = new _epubcfi2.default(range, cfiBase).toString(); + locations.push(cfi); + counter = 0; + } + + return locations; + } + + /** + * Get a location from an EpubCFI + * @param {EpubCFI} cfi + * @return {number} + */ + + }, { + key: "locationFromCfi", + value: function locationFromCfi(cfi) { + var loc = void 0; + if (_epubcfi2.default.prototype.isCfiString(cfi)) { + cfi = new _epubcfi2.default(cfi); + } + // Check if the location has not been set yet + if (this._locations.length === 0) { + return -1; + } + + loc = (0, _core.locationOf)(cfi, this._locations, this.epubcfi.compare); + + if (loc > this.total) { + return this.total; + } + + return loc; + } + + /** + * Get a percentage position in locations from an EpubCFI + * @param {EpubCFI} cfi + * @return {number} + */ + + }, { + key: "percentageFromCfi", + value: function 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); + } + + /** + * Get a percentage position from a location index + * @param {number} location + * @return {number} + */ + + }, { + key: "percentageFromLocation", + value: function percentageFromLocation(loc) { + if (!loc || !this.total) { + return 0; + } + + return loc / this.total; + } + + /** + * Get an EpubCFI from location index + * @param {number} loc + * @return {EpubCFI} cfi + */ + + }, { + key: "cfiFromLocation", + value: function cfiFromLocation(loc) { + var cfi = -1; + // check that pg is an int + if (typeof loc != "number") { + loc = parseInt(loc); + } + + if (loc >= 0 && loc < this._locations.length) { + cfi = this._locations[loc]; + } + + return cfi; + } + + /** + * Get an EpubCFI from location percentage + * @param {number} percentage + * @return {EpubCFI} cfi + */ + + }, { + key: "cfiFromPercentage", + value: function cfiFromPercentage(percentage) { + var loc = void 0; + if (percentage > 1) { + console.warn("Normalize cfiFromPercentage value to between 0 - 1"); + } + + // Make sure 1 goes to very end + if (percentage >= 1) { + var cfi = new _epubcfi2.default(this._locations[this.total]); + cfi.collapse(); + return cfi.toString(); + } + + loc = Math.ceil(this.total * percentage); + return this.cfiFromLocation(loc); + } + + /** + * Load locations from JSON + * @param {json} locations + */ + + }, { + key: "load", + value: function load(locations) { + if (typeof locations === "string") { + this._locations = JSON.parse(locations); + } else { + this._locations = locations; + } + this.total = this._locations.length - 1; + return this._locations; + } + + /** + * Save locations to JSON + * @return {json} + */ + + }, { + key: "save", + value: function save() { + return JSON.stringify(this._locations); + } + }, { + key: "getCurrent", + value: function getCurrent() { + return this._current; + } + }, { + key: "setCurrent", + value: function 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(_constants.EVENTS.LOCATIONS.CHANGED, { + percentage: this.percentageFromLocation(loc) + }); + } + + /** + * Get the current location + */ + + }, { + key: "length", + + + /** + * Locations length + */ + value: function length() { + return this._locations.length; + } + }, { + key: "destroy", + value: function destroy() { + this.spine = undefined; + this.request = undefined; + this.pause = undefined; + + this.q.stop(); + this.q = undefined; + this.epubcfi = undefined; + + this._locations = undefined; + this.total = undefined; + + this.break = undefined; + this._current = undefined; + + this.currentLocation = undefined; + this._currentCfi = undefined; + clearTimeout(this.processingTimeout); + } + }, { + key: "currentLocation", + get: function get() { + return this._current; + } + + /** + * Set the current location + */ + , + set: function set(curr) { + this.setCurrent(curr); + } + }]); + + return Locations; +}(); + +(0, _eventEmitter2.default)(Locations.prototype); + +exports.default = Locations; +module.exports = exports["default"]; + +/***/ }), +/* 45 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _pathWebpack = __webpack_require__(6); + +var _pathWebpack2 = _interopRequireDefault(_pathWebpack); + +var _core = __webpack_require__(0); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles Parsing and Accessing an Epub Container + * @class + * @param {document} [containerDocument] xml document + */ +var Container = function () { + function Container(containerDocument) { + _classCallCheck(this, Container); + + this.packagePath = ''; + this.directory = ''; + this.encoding = ''; + + if (containerDocument) { + this.parse(containerDocument); + } + } + + /** + * Parse the Container XML + * @param {document} containerDocument + */ + + + _createClass(Container, [{ + key: "parse", + value: function parse(containerDocument) { + //-- + var rootfile; + + if (!containerDocument) { + throw new Error("Container File Not Found"); + } + + rootfile = (0, _core.qs)(containerDocument, "rootfile"); + + if (!rootfile) { + throw new Error("No RootFile Found"); + } + + this.packagePath = rootfile.getAttribute("full-path"); + this.directory = _pathWebpack2.default.dirname(this.packagePath); + this.encoding = containerDocument.xmlEncoding; + } + }, { + key: "destroy", + value: function destroy() { + this.packagePath = undefined; + this.directory = undefined; + this.encoding = undefined; + } + }]); + + return Container; +}(); + +exports.default = Container; +module.exports = exports["default"]; + +/***/ }), +/* 46 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Open Packaging Format Parser + * @class + * @param {document} packageDocument OPF XML + */ +var Packaging = function () { + function Packaging(packageDocument) { + _classCallCheck(this, Packaging); + + this.manifest = {}; + this.navPath = ''; + this.ncxPath = ''; + this.coverPath = ''; + this.spineNodeIndex = 0; + this.spine = []; + this.metadata = {}; + + if (packageDocument) { + this.parse(packageDocument); + } + } + + /** + * Parse OPF XML + * @param {document} packageDocument OPF XML + * @return {object} parsed package parts + */ + + + _createClass(Packaging, [{ + key: 'parse', + value: function parse(packageDocument) { + var metadataNode, manifestNode, spineNode; + + if (!packageDocument) { + throw new Error("Package File Not Found"); + } + + metadataNode = (0, _core.qs)(packageDocument, "metadata"); + if (!metadataNode) { + throw new Error("No Metadata Found"); + } + + manifestNode = (0, _core.qs)(packageDocument, "manifest"); + if (!manifestNode) { + throw new Error("No Manifest Found"); + } + + spineNode = (0, _core.qs)(packageDocument, "spine"); + if (!spineNode) { + throw new Error("No Spine Found"); + } + + this.manifest = this.parseManifest(manifestNode); + this.navPath = this.findNavPath(manifestNode); + this.ncxPath = this.findNcxPath(manifestNode, spineNode); + this.coverPath = this.findCoverPath(packageDocument); + + this.spineNodeIndex = (0, _core.indexOfElementNode)(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 + */ + + }, { + key: 'parseMetadata', + value: function 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 + */ + + }, { + key: 'parseManifest', + value: function parseManifest(manifestXml) { + var manifest = {}; + + //-- Turn items into an array + // var selected = manifestXml.querySelectorAll("item"); + var selected = (0, _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 + */ + + }, { + key: 'parseSpine', + value: function parseSpine(spineXml, manifest) { + var spine = []; + + var selected = (0, _core.qsa)(spineXml, "itemref"); + var 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") || "yes", + "properties": propArray, + // "href" : manifest[Id].href, + // "url" : manifest[Id].url, + "index": index + // "cfiBase" : cfiBase + }; + spine.push(itemref); + }); + + return spine; + } + + /** + * Find TOC NAV + * @private + */ + + }, { + key: 'findNavPath', + value: function 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 = (0, _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 + */ + + }, { + key: 'findNcxPath', + value: function findNcxPath(manifestNode, spineNode) { + // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); + var node = (0, _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); + } + } + + return node ? node.getAttribute("href") : false; + } + + /** + * Find the Cover Path + * + * Fallback for Epub 2.0 + * @param {document} packageXml + * @return {string} href + */ + + }, { + key: 'findCoverPath', + value: function findCoverPath(packageXml) { + var pkg = (0, _core.qs)(packageXml, "package"); + var epubVersion = pkg.getAttribute("version"); + + if (epubVersion === "2.0") { + var metaCover = (0, _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") : ""; + } else { + return false; + } + } else { + // var node = packageXml.querySelector("item[properties='cover-image']"); + var node = (0, _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 + */ + + }, { + key: 'getElementText', + value: function getElementText(xml, tag) { + var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag); + var el; + + if (!found || found.length === 0) return ""; + + el = found[0]; + + if (el.childNodes.length) { + return el.childNodes[0].nodeValue; + } + + return ""; + } + + /** + * Get text by property + * @private + * @param {document} xml + * @param {string} property + * @return {string} text + */ + + }, { + key: 'getPropertyText', + value: function getPropertyText(xml, property) { + var el = (0, _core.qsp)(xml, "meta", { "property": property }); + + if (el && el.childNodes.length) { + return el.childNodes[0].nodeValue; + } + + return ""; + } + + /** + * Load JSON Manifest + * @param {document} packageDocument OPF XML + * @return {object} parsed package parts + */ + + }, { + key: 'load', + value: function load(json) { + var _this = this; + + this.metadata = json.metadata; + + this.spine = json.spine.map(function (item, index) { + item.index = index; + return item; + }); + + json.resources.forEach(function (item, index) { + _this.manifest[index] = item; + + if (item.rel && item.rel[0] === "cover") { + _this.coverPath = item.href; + } + }); + + this.spineNodeIndex = 0; + + this.toc = json.toc.map(function (item, index) { + item.label = item.title; + return item; + }); + + return { + "metadata": this.metadata, + "spine": this.spine, + "manifest": this.manifest, + "navPath": this.navPath, + "ncxPath": this.ncxPath, + "coverPath": this.coverPath, + "spineNodeIndex": this.spineNodeIndex, + "toc": this.toc + }; + } + }, { + key: 'destroy', + value: function destroy() { + this.manifest = undefined; + this.navPath = undefined; + this.ncxPath = undefined; + this.coverPath = undefined; + this.spineNodeIndex = undefined; + this.spine = undefined; + this.metadata = undefined; + } + }]); + + return Packaging; +}(); + +exports.default = Packaging; +module.exports = exports['default']; + +/***/ }), +/* 47 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Navigation Parser + * @param {document} xml navigation html / xhtml / ncx + */ +var Navigation = function () { + function Navigation(xml) { + _classCallCheck(this, Navigation); + + this.toc = []; + this.tocByHref = {}; + this.tocById = {}; + + this.landmarks = []; + this.landmarksByType = {}; + + this.length = 0; + if (xml) { + this.parse(xml); + } + } + + /** + * Parse out the navigation items + * @param {document} xml navigation html / xhtml / ncx + */ + + + _createClass(Navigation, [{ + key: "parse", + value: function parse(xml) { + var isXml = xml.nodeType; + var html = void 0; + var ncx = void 0; + + if (isXml) { + html = (0, _core.qs)(xml, "html"); + ncx = (0, _core.qs)(xml, "ncx"); + } + + if (!isXml) { + this.toc = this.load(xml); + } else if (html) { + this.toc = this.parseNav(xml); + this.landmarks = this.parseLandmarks(xml); + } else if (ncx) { + this.toc = this.parseNcx(xml); + } + + this.length = 0; + + this.unpack(this.toc); + } + + /** + * Unpack navigation items + * @private + * @param {array} toc + */ + + }, { + key: "unpack", + value: function unpack(toc) { + var item; + + for (var i = 0; i < toc.length; i++) { + item = toc[i]; + + if (item.href) { + this.tocByHref[item.href] = i; + } + + if (item.id) { + this.tocById[item.id] = i; + } + + this.length++; + + if (item.subitems.length) { + this.unpack(item.subitems); + } + } + } + + /** + * Get an item from the navigation + * @param {string} target + * @return {object} navItems + */ + + }, { + key: "get", + value: function 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]; + } + + /** + * Get a landmark by type + * List of types: https://idpf.github.io/epub-vocabs/structure/ + * @param {string} type + * @return {object} landmarkItems + */ + + }, { + key: "landmark", + value: function landmark(type) { + var index; + + if (!type) { + return this.landmarks; + } + + index = this.landmarksByType[type]; + + return this.landmarks[index]; + } + + /** + * Parse toc from a Epub > 3.0 Nav + * @private + * @param {document} navHtml + * @return {array} navigation list + */ + + }, { + key: "parseNav", + value: function parseNav(navHtml) { + var navElement = (0, _core.querySelectorByType)(navHtml, "nav", "toc"); + var navItems = navElement ? (0, _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]); + if (item) { + 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 + */ + + }, { + key: "navItem", + value: function navItem(item) { + var id = item.getAttribute("id") || undefined; + var content = (0, _core.filterChildren)(item, "a", true); + + if (!content) { + return; + } + + var src = content.getAttribute("href") || ""; + var text = content.textContent || ""; + var subitems = []; + var parentItem = (0, _core.getParentByTagName)(item, "li"); + var parent = void 0; + + if (parentItem) { + parent = parentItem.getAttribute("id"); + } + + while (!parent && parentItem) { + parentItem = (0, _core.getParentByTagName)(parentItem, "li"); + if (parentItem) { + parent = parentItem.getAttribute("id"); + } + } + + return { + "id": id, + "href": src, + "label": text, + "subitems": subitems, + "parent": parent + }; + } + + /** + * Parse landmarks from a Epub > 3.0 Nav + * @private + * @param {document} navHtml + * @return {array} landmarks list + */ + + }, { + key: "parseLandmarks", + value: function parseLandmarks(navHtml) { + var navElement = (0, _core.querySelectorByType)(navHtml, "nav", "landmarks"); + var navItems = navElement ? (0, _core.qsa)(navElement, "li") : []; + var length = navItems.length; + var i; + var list = []; + var item; + + if (!navItems || length === 0) return list; + + for (i = 0; i < length; ++i) { + item = this.landmarkItem(navItems[i]); + if (item) { + list.push(item); + this.landmarksByType[item.type] = i; + } + } + + return list; + } + + /** + * Create a landmarkItem + * @private + * @param {element} item + * @return {object} landmarkItem + */ + + }, { + key: "landmarkItem", + value: function landmarkItem(item) { + var content = (0, _core.filterChildren)(item, "a", true); + + if (!content) { + return; + } + + var type = content.getAttributeNS("http://www.idpf.org/2007/ops", "type") || undefined; + var href = content.getAttribute("href") || ""; + var text = content.textContent || ""; + + return { + "href": href, + "label": text, + "type": type + }; + } + + /** + * Parse from a Epub > 3.0 NC + * @private + * @param {document} navHtml + * @return {array} navigation list + */ + + }, { + key: "parseNcx", + value: function parseNcx(tocXml) { + var navPoints = (0, _core.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 + */ + + }, { + key: "ncxItem", + value: function ncxItem(item) { + var id = item.getAttribute("id") || false, + content = (0, _core.qs)(item, "content"), + src = content.getAttribute("src"), + navLabel = (0, _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 + }; + } + + /** + * Load Spine Items + * @param {object} json the items to be loaded + */ + + }, { + key: "load", + value: function load(json) { + var _this = this; + + return json.map(function (item) { + item.label = item.title; + if (item.children) { + item.subitems = _this.load(item.children); + } + return item; + }); + } + + /** + * forEach pass through + * @param {Function} fn function to run on each item + * @return {method} forEach loop + */ + + }, { + key: "forEach", + value: function forEach(fn) { + return this.toc.forEach(fn); + } + }]); + + return Navigation; +}(); + +exports.default = Navigation; +module.exports = exports["default"]; + +/***/ }), +/* 48 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _replacements = __webpack_require__(7); + +var _core = __webpack_require__(0); + +var _url = __webpack_require__(5); + +var _url2 = _interopRequireDefault(_url); + +var _mime = __webpack_require__(17); + +var _mime2 = _interopRequireDefault(_mime); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +var _pathWebpack = __webpack_require__(6); + +var _pathWebpack2 = _interopRequireDefault(_pathWebpack); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handle Package Resources + * @class + * @param {Manifest} manifest + * @param {[object]} options + * @param {[string="base64"]} options.replacements + * @param {[Archive]} options.archive + * @param {[method]} options.resolver + */ +var Resources = function () { + function Resources(manifest, options) { + _classCallCheck(this, Resources); + + this.settings = { + replacements: options && options.replacements || "base64", + archive: options && options.archive, + resolver: options && options.resolver, + request: options && options.request + }; + this.manifest = manifest; + this.resources = Object.keys(manifest).map(function (key) { + return manifest[key]; + }); + + this.replacementUrls = []; + + this.html = []; + this.assets = []; + this.css = []; + + this.urls = []; + this.cssUrls = []; + + this.split(); + this.splitUrls(); + } + + /** + * Split resources by type + * @private + */ + + + _createClass(Resources, [{ + key: "split", + value: function split() { + + // 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 + */ + + }, { + key: "splitUrls", + value: function splitUrls() { + + // 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; + }); + } + }, { + key: "createUrl", + value: function createUrl(url) { + var parsedUrl = new _url2.default(url); + var mimeType = _mime2.default.lookup(parsedUrl.filename); + + if (this.settings.archive) { + return this.settings.archive.createUrl(url, { "base64": this.settings.replacements === "base64" }); + } else { + if (this.settings.replacements === "base64") { + return this.settings.request(url, 'blob').then(function (blob) { + return (0, _core.blob2base64)(blob); + }).then(function (blob) { + return (0, _core.createBase64Url)(blob, mimeType); + }); + } else { + return this.settings.request(url, 'blob').then(function (blob) { + return (0, _core.createBlobUrl)(blob, mimeType); + }); + } + } + } + + /** + * Create blob urls for all the assets + * @return {Promise} returns replacement urls + */ + + }, { + key: "replacements", + value: function replacements() { + var _this = this; + + if (this.settings.replacements === "none") { + return new Promise(function (resolve) { + resolve(this.urls); + }.bind(this)); + } + + var replacements = this.urls.map(function (url) { + var absolute = _this.settings.resolver(url); + + return _this.createUrl(absolute).catch(function (err) { + console.error(err); + return null; + }); + }); + + return Promise.all(replacements).then(function (replacementUrls) { + _this.replacementUrls = replacementUrls.filter(function (url) { + return typeof url === "string"; + }); + return replacementUrls; + }); + } + + /** + * Replace URLs in CSS resources + * @private + * @param {Archive} [archive] + * @param {method} [resolver] + * @return {Promise} + */ + + }, { + key: "replaceCss", + value: function 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)); + + 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 + * @return {Promise} returns a BlobUrl to the new CSS file or a data url + */ + + }, { + key: "createCssFile", + value: function createCssFile(href) { + var _this2 = this; + + var newUrl; + + if (_pathWebpack2.default.isAbsolute(href)) { + return new Promise(function (resolve) { + resolve(); + }); + } + + var absolute = this.settings.resolver(href); + + // Get the text of the css file from the archive + var textResponse; + + if (this.settings.archive) { + textResponse = this.settings.archive.getText(absolute); + } else { + textResponse = this.settings.request(absolute, "text"); + } + + // Get asset links relative to css file + var relUrls = this.urls.map(function (assetHref) { + var resolved = _this2.settings.resolver(assetHref); + var relative = new _path2.default(absolute).relative(resolved); + + return relative; + }); + + if (!textResponse) { + // file not found, don't replace + return new Promise(function (resolve) { + resolve(); + }); + } + + return textResponse.then(function (text) { + // Replacements in the css text + text = (0, _replacements.substitute)(text, relUrls, _this2.replacementUrls); + + // Get the new url + if (_this2.settings.replacements === "base64") { + newUrl = (0, _core.createBase64Url)(text, "text/css"); + } else { + newUrl = (0, _core.createBlobUrl)(text, "text/css"); + } + + return newUrl; + }, function (err) { + // handle response errors + return new Promise(function (resolve) { + resolve(); + }); + }); + } + + /** + * 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 + */ + + }, { + key: "relativeTo", + value: function 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 _path2.default(absolute).relative(resolved); + return relative; + }.bind(this)); + } + + /** + * Get a URL for a resource + * @param {string} path + * @return {string} url + */ + + }, { + key: "get", + value: function 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 this.createUrl(path); + } + } + + /** + * 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 + */ + + }, { + key: "substitute", + value: function substitute(content, url) { + var relUrls; + if (url) { + relUrls = this.relativeTo(url); + } else { + relUrls = this.urls; + } + return (0, _replacements.substitute)(content, relUrls, this.replacementUrls); + } + }, { + key: "destroy", + value: function destroy() { + this.settings = undefined; + this.manifest = undefined; + this.resources = undefined; + this.replacementUrls = undefined; + this.html = undefined; + this.assets = undefined; + this.css = undefined; + + this.urls = undefined; + this.cssUrls = undefined; + } + }]); + + return Resources; +}(); + +exports.default = Resources; +module.exports = exports["default"]; + +/***/ }), +/* 49 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +var _core = __webpack_require__(0); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Page List Parser + * @param {document} [xml] + */ +var PageList = function () { + function PageList(xml) { + _classCallCheck(this, PageList); + + this.pages = []; + this.locations = []; + this.epubcfi = new _epubcfi2.default(); + + this.firstPage = 0; + this.lastPage = 0; + this.totalPages = 0; + + this.toc = undefined; + this.ncx = undefined; + + if (xml) { + this.pageList = this.parse(xml); + } + + if (this.pageList && this.pageList.length) { + this.process(this.pageList); + } + } + + /** + * Parse PageList Xml + * @param {document} xml + */ + + + _createClass(PageList, [{ + key: "parse", + value: function parse(xml) { + var html = (0, _core.qs)(xml, "html"); + var ncx = (0, _core.qs)(xml, "ncx"); + + if (html) { + return this.parseNav(xml); + } else if (ncx) { + // Not supported + // return this.parseNcx(xml); + return; + } + } + + /** + * Parse a Nav PageList + * @private + * @param {document} navHtml + * @return {PageList.item[]} list + */ + + }, { + key: "parseNav", + value: function parseNav(navHtml) { + var navElement = (0, _core.querySelectorByType)(navHtml, "nav", "page-list"); + var navItems = navElement ? (0, _core.qsa)(navElement, "li") : []; + var length = navItems.length; + var i; + 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 + */ + + }, { + key: "item", + value: function item(_item) { + var content = (0, _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 + */ + + }, { + key: "process", + value: function 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; + } + + /** + * Get a PageList result from a EpubCFI + * @param {string} cfi EpubCFI String + * @return {string} page + */ + + }, { + key: "pageFromCfi", + value: function 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 = (0, _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 = (0, _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 + */ + + }, { + key: "cfiFromPage", + value: function 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 + */ + + }, { + key: "pageFromPercentage", + value: function 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 + */ + + }, { + key: "percentageFromPage", + value: function 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 + */ + + }, { + key: "percentageFromCfi", + value: function percentageFromCfi(cfi) { + var pg = this.pageFromCfi(cfi); + var percentage = this.percentageFromPage(pg); + return percentage; + } + }, { + key: "destroy", + value: function destroy() { + this.pages = undefined; + this.locations = undefined; + this.epubcfi = undefined; + + this.pageList = undefined; + + this.toc = undefined; + this.ncx = undefined; + } + }]); + + return PageList; +}(); + +exports.default = PageList; +module.exports = exports["default"]; + +/***/ }), +/* 50 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _constants = __webpack_require__(3); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Figures out the CSS values to apply for a layout + * @class + * @param {object} settings + * @param {string} [settings.layout='reflowable'] + * @param {string} [settings.spread] + * @param {int} [settings.minSpreadWidth=800] + * @param {boolean} [settings.evenSpreads=false] + */ +var Layout = function () { + function Layout(settings) { + _classCallCheck(this, Layout); + + this.settings = 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" || 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.columnWidth = 0; + this.gap = 0; + this.divisor = 1; + + this.props = { + name: this.name, + spread: this._spread, + flow: this._flow, + width: 0, + height: 0, + spreadWidth: 0, + delta: 0, + columnWidth: 0, + gap: 0, + divisor: 1 + }; + } + + /** + * Switch the flow between paginated and scrolled + * @param {string} flow paginated | scrolled + */ + + + _createClass(Layout, [{ + key: "flow", + value: function flow(_flow) { + if (typeof _flow != "undefined") { + if (_flow === "scrolled" || _flow === "scrolled-continuous" || _flow === "scrolled-doc") { + this._flow = "scrolled"; + } else { + this._flow = "paginated"; + } + // this.props.flow = this._flow; + this.update({ flow: this._flow }); + } + return this._flow; + } + + /** + * 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 + */ + + }, { + key: "spread", + value: function spread(_spread, min) { + + if (_spread) { + this._spread = _spread === "none" ? false : true; + // this.props.spread = this._spread; + this.update({ spread: this._spread }); + } + + if (min >= 0) { + this._minSpreadWidth = min; + } + + return this._spread; + } + + /** + * Calculate the dimensions of the pagination + * @param {number} _width [description] + * @param {number} _height [description] + * @param {number} _gap [description] + */ + + }, { + key: "calculate", + value: function 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 height = _height; + + var section = Math.floor(width / 12); + + var columnWidth; + var spreadWidth; + var pageWidth; + 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) { + // width = width - gap; + // columnWidth = (width - gap) / divisor; + // gap = gap / divisor; + columnWidth = width / divisor - gap; + pageWidth = columnWidth + gap; + } else { + columnWidth = width; + pageWidth = width; + } + + if (this.name === "pre-paginated" && divisor > 1) { + width = columnWidth; + } + + spreadWidth = columnWidth * divisor + gap; + + delta = width; + + this.width = width; + this.height = height; + this.spreadWidth = spreadWidth; + this.pageWidth = pageWidth; + this.delta = delta; + + this.columnWidth = columnWidth; + this.gap = gap; + this.divisor = divisor; + + // this.props.width = width; + // this.props.height = _height; + // this.props.spreadWidth = spreadWidth; + // this.props.pageWidth = pageWidth; + // this.props.delta = delta; + // + // this.props.columnWidth = colWidth; + // this.props.gap = gap; + // this.props.divisor = divisor; + + this.update({ + width: width, + height: height, + spreadWidth: spreadWidth, + pageWidth: pageWidth, + delta: delta, + columnWidth: columnWidth, + gap: gap, + divisor: divisor + }); + } + + /** + * Apply Css to a Document + * @param {Contents} contents + * @return {Promise} + */ + + }, { + key: "format", + value: function 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} totalLength + * @param {number} pageLength + * @return {{spreads: Number, pages: Number}} + */ + + }, { + key: "count", + value: function count(totalLength, pageLength) { + + var spreads = void 0, + pages = void 0; + + if (this.name === "pre-paginated") { + spreads = 1; + pages = 1; + } else if (this._flow === "paginated") { + pageLength = pageLength || this.delta; + spreads = Math.ceil(totalLength / pageLength); + pages = spreads * this.divisor; + } else { + // scrolled + pageLength = pageLength || this.height; + spreads = Math.ceil(totalLength / pageLength); + pages = spreads; + } + + return { + spreads: spreads, + pages: pages + }; + } + }, { + key: "update", + value: function update(props) { + var _this = this; + + // Remove props that haven't changed + Object.keys(props).forEach(function (propName) { + if (_this.props[propName] === props[propName]) { + delete props[propName]; + } + }); + + if (Object.keys(props).length > 0) { + var newProps = (0, _core.extend)(this.props, props); + this.emit(_constants.EVENTS.LAYOUT.UPDATED, newProps, props); + } + } + }]); + + return Layout; +}(); + +(0, _eventEmitter2.default)(Layout.prototype); + +exports.default = Layout; +module.exports = exports["default"]; + +/***/ }), +/* 51 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _url = __webpack_require__(5); + +var _url2 = _interopRequireDefault(_url); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Themes to apply to displayed content + * @class + * @param {Rendition} rendition + */ +var Themes = function () { + function Themes(rendition) { + _classCallCheck(this, Themes); + + 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)); + } + + /** + * Add themes to be used by a rendition + * @param {object | string} + * @example themes.register("light", "http://example.com/light.css") + * @example themes.register("light", { "body": { "color": "purple"}}) + * @example themes.register({ "light" : {...}, "dark" : {...}}) + */ + + + _createClass(Themes, [{ + key: "register", + value: function 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]); + } + } + + /** + * Add a default theme to be used by a rendition + * @param {object | string} theme + * @example themes.register("http://example.com/default.css") + * @example themes.register({ "body": { "color": "purple"}}) + */ + + }, { + key: "default", + value: function _default(theme) { + if (!theme) { + return; + } + if (typeof theme === "string") { + return this.registerUrl("default", theme); + } + if ((typeof theme === "undefined" ? "undefined" : _typeof(theme)) === "object") { + return this.registerRules("default", theme); + } + } + }, { + key: "registerThemes", + value: function 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]); + } + } + } + } + }, { + key: "registerUrl", + value: function registerUrl(name, input) { + var url = new _url2.default(input); + this._themes[name] = { "url": url.toString() }; + if (this._injected[name]) { + this.update(name); + } + } + }, { + key: "registerRules", + value: function registerRules(name, rules) { + this._themes[name] = { "rules": rules }; + // TODO: serialize css rules + if (this._injected[name]) { + this.update(name); + } + } + }, { + key: "select", + value: function select(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); + }); + } + }, { + key: "update", + value: function update(name) { + var _this = this; + + var contents = this.rendition.getContents(); + contents.forEach(function (content) { + _this.add(name, content); + }); + } + }, { + key: "inject", + value: function inject(contents) { + var links = []; + var themes = this._themes; + var theme; + + for (var name in themes) { + if (themes.hasOwnProperty(name) && (name === this._current || name === "default")) { + theme = themes[name]; + if (theme.rules && Object.keys(theme.rules).length > 0 || theme.url && links.indexOf(theme.url) === -1) { + this.add(name, contents); + } + this._injected.push(name); + } + } + + if (this._current != "default") { + contents.addClass(this._current); + } + } + }, { + key: "add", + value: function add(name, contents) { + var theme = this._themes[name]; + + if (!theme || !contents) { + return; + } + + if (theme.url) { + contents.addStylesheet(theme.url); + } else if (theme.serialized) { + // TODO: handle serialized + } else if (theme.rules) { + contents.addStylesheetRules(theme.rules); + theme.injected = true; + } + } + }, { + key: "override", + value: function override(name, value) { + var _this2 = this; + + var contents = this.rendition.getContents(); + + this._overrides[name] = value; + + contents.forEach(function (content) { + content.css(name, _this2._overrides[name]); + }); + } + }, { + key: "overrides", + value: function overrides(contents) { + var overrides = this._overrides; + + for (var rule in overrides) { + if (overrides.hasOwnProperty(rule)) { + contents.css(rule, overrides[rule]); + } + } + } + + /** + * Adjust the font size of a rendition + * @param {number} size + */ + + }, { + key: "fontSize", + value: function fontSize(size) { + this.override("font-size", size); + } + + /** + * Adjust the font-family of a rendition + * @param {string} f + */ + + }, { + key: "font", + value: function font(f) { + this.override("font-family", f); + } + }, { + key: "destroy", + value: function destroy() { + this.rendition = undefined; + this._themes = undefined; + this._overrides = undefined; + this._current = undefined; + this._injected = undefined; + } + }]); + + return Themes; +}(); + +exports.default = Themes; +module.exports = exports["default"]; + +/***/ }), +/* 52 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _eventEmitter = __webpack_require__(2); + +var _eventEmitter2 = _interopRequireDefault(_eventEmitter); + +var _epubcfi = __webpack_require__(1); + +var _epubcfi2 = _interopRequireDefault(_epubcfi); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles managing adding & removing Annotations + * @param {Rendition} rendition + * @class + */ +var Annotations = function () { + function Annotations(rendition) { + _classCallCheck(this, Annotations); + + this.rendition = rendition; + this.highlights = []; + this.underlines = []; + this.marks = []; + this._annotations = {}; + this._annotationsBySectionIndex = {}; + + this.rendition.hooks.render.register(this.inject.bind(this)); + this.rendition.hooks.unloaded.register(this.clear.bind(this)); + } + + /** + * Add an annotation to store + * @param {string} type Type of annotation to add: "highlight", "underline", "mark" + * @param {EpubCFI} cfiRange EpubCFI range to attach annotation to + * @param {object} data Data to assign to annotation + * @param {function} [cb] Callback after annotation is added + * @returns {Annotation} annotation + */ + + + _createClass(Annotations, [{ + key: "add", + value: function add(type, cfiRange, data, cb) { + var hash = encodeURI(cfiRange); + var cfi = new _epubcfi2.default(cfiRange); + var sectionIndex = cfi.spinePos; + var annotation = new Annotation({ + type: type, + cfiRange: cfiRange, + data: data, + sectionIndex: sectionIndex, + cb: cb + }); + + this._annotations[hash] = annotation; + + if (sectionIndex in this._annotationsBySectionIndex) { + this._annotationsBySectionIndex[sectionIndex].push(hash); + } else { + this._annotationsBySectionIndex[sectionIndex] = [hash]; + } + + var views = this.rendition.views(); + + views.forEach(function (view) { + if (annotation.sectionIndex === view.index) { + annotation.attach(view); + } + }); + + return annotation; + } + + /** + * Remove an annotation from store + * @param {EpubCFI} cfiRange EpubCFI range the annotation is attached to + * @param {string} type Type of annotation to add: "highlight", "underline", "mark" + */ + + }, { + key: "remove", + value: function remove(cfiRange, type) { + var _this = this; + + var hash = encodeURI(cfiRange); + + if (hash in this._annotations) { + var annotation = this._annotations[hash]; + + if (type && annotation.type !== type) { + return; + } + + var views = this.rendition.views(); + views.forEach(function (view) { + _this._removeFromAnnotationBySectionIndex(annotation.sectionIndex, hash); + if (annotation.sectionIndex === view.index) { + annotation.detach(view); + } + }); + + delete this._annotations[hash]; + } + } + + /** + * Remove an annotations by Section Index + * @private + */ + + }, { + key: "_removeFromAnnotationBySectionIndex", + value: function _removeFromAnnotationBySectionIndex(sectionIndex, hash) { + this._annotationsBySectionIndex[sectionIndex] = this._annotationsAt(sectionIndex).filter(function (h) { + return h !== hash; + }); + } + + /** + * Get annotations by Section Index + * @private + */ + + }, { + key: "_annotationsAt", + value: function _annotationsAt(index) { + return this._annotationsBySectionIndex[index]; + } + + /** + * Add a highlight to the store + * @param {EpubCFI} cfiRange EpubCFI range to attach annotation to + * @param {object} data Data to assign to annotation + * @param {function} cb Callback after annotation is added + */ + + }, { + key: "highlight", + value: function highlight(cfiRange, data, cb) { + this.add("highlight", cfiRange, data, cb); + } + + /** + * Add a underline to the store + * @param {EpubCFI} cfiRange EpubCFI range to attach annotation to + * @param {object} data Data to assign to annotation + * @param {function} cb Callback after annotation is added + */ + + }, { + key: "underline", + value: function underline(cfiRange, data, cb) { + this.add("underline", cfiRange, data, cb); + } + + /** + * Add a mark to the store + * @param {EpubCFI} cfiRange EpubCFI range to attach annotation to + * @param {object} data Data to assign to annotation + * @param {function} cb Callback after annotation is added + */ + + }, { + key: "mark", + value: function mark(cfiRange, data, cb) { + this.add("mark", cfiRange, data, cb); + } + + /** + * iterate over annotations in the store + */ + + }, { + key: "each", + value: function each() { + return this._annotations.forEach.apply(this._annotations, arguments); + } + + /** + * Hook for injecting annotation into a view + * @param {View} view + * @private + */ + + }, { + key: "inject", + value: function inject(view) { + var _this2 = this; + + var sectionIndex = view.index; + if (sectionIndex in this._annotationsBySectionIndex) { + var annotations = this._annotationsBySectionIndex[sectionIndex]; + annotations.forEach(function (hash) { + var annotation = _this2._annotations[hash]; + annotation.attach(view); + }); + } + } + + /** + * Hook for removing annotation from a view + * @param {View} view + * @private + */ + + }, { + key: "clear", + value: function clear(view) { + var _this3 = this; + + var sectionIndex = view.index; + if (sectionIndex in this._annotationsBySectionIndex) { + var annotations = this._annotationsBySectionIndex[sectionIndex]; + annotations.forEach(function (hash) { + var annotation = _this3._annotations[hash]; + annotation.detach(view); + }); + } + } + + /** + * [Not Implemented] Show annotations + * @TODO: needs implementation in View + */ + + }, { + key: "show", + value: function show() {} + + /** + * [Not Implemented] Hide annotations + * @TODO: needs implementation in View + */ + + }, { + key: "hide", + value: function hide() {} + }]); + + return Annotations; +}(); + +/** + * Annotation object + * @class + * @param {object} options + * @param {string} options.type Type of annotation to add: "highlight", "underline", "mark" + * @param {EpubCFI} options.cfiRange EpubCFI range to attach annotation to + * @param {object} options.data Data to assign to annotation + * @param {int} options.sectionIndex Index in the Spine of the Section annotation belongs to + * @param {function} [options.cb] Callback after annotation is added + * @returns {Annotation} annotation + */ + + +var Annotation = function () { + function Annotation(_ref) { + var type = _ref.type, + cfiRange = _ref.cfiRange, + data = _ref.data, + sectionIndex = _ref.sectionIndex, + cb = _ref.cb; + + _classCallCheck(this, Annotation); + + this.type = type; + this.cfiRange = cfiRange; + this.data = data; + this.sectionIndex = sectionIndex; + this.mark = undefined; + this.cb = cb; + } + + /** + * Update stored data + * @param {object} data + */ + + + _createClass(Annotation, [{ + key: "update", + value: function update(data) { + this.data = data; + } + + /** + * Add to a view + * @param {View} view + */ + + }, { + key: "attach", + value: function attach(view) { + var cfiRange = this.cfiRange, + data = this.data, + type = this.type, + mark = this.mark, + cb = this.cb; + + var result = void 0; + + if (type === "highlight") { + result = view.highlight(cfiRange, data, cb); + } else if (type === "underline") { + result = view.underline(cfiRange, data, cb); + } else if (type === "mark") { + result = view.mark(cfiRange, data, cb); + } + + this.mark = result; + + return result; + } + + /** + * Remove from a view + * @param {View} view + */ + + }, { + key: "detach", + value: function detach(view) { + var cfiRange = this.cfiRange, + type = this.type; + + var result = void 0; + + if (view) { + if (type === "highlight") { + result = view.unhighlight(cfiRange); + } else if (type === "underline") { + result = view.ununderline(cfiRange); + } else if (type === "mark") { + result = view.unmark(cfiRange); + } + } + + this.mark = undefined; + + return result; + } + + /** + * [Not Implemented] Get text of an annotation + * @TODO: needs implementation in contents + */ + + }, { + key: "text", + value: function text() {} + }]); + + return Annotation; +}(); + +(0, _eventEmitter2.default)(Annotation.prototype); + +exports.default = Annotations; +module.exports = exports["default"]; + +/***/ }), +/* 53 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Underline = exports.Highlight = exports.Mark = exports.Pane = undefined; + +var _get = function get(object, property, receiver) { + if (object === null) object = Function.prototype;var desc = Object.getOwnPropertyDescriptor(object, property);if (desc === undefined) { + var parent = Object.getPrototypeOf(object);if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get;if (getter === undefined) { + return undefined; + }return getter.call(receiver); + } +}; + +var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor); + } + }return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor; + }; +}(); + +var _svg = __webpack_require__(54); + +var _svg2 = _interopRequireDefault(_svg); + +var _events = __webpack_require__(55); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + }return call && ((typeof call === "undefined" ? "undefined" : _typeof(call)) === "object" || typeof call === "function") ? call : self; +} + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : _typeof(superClass))); + }subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; +} + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +var Pane = exports.Pane = function () { + function Pane(target) { + var container = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body; + + _classCallCheck(this, Pane); + + this.target = target; + this.element = _svg2.default.createElement('svg'); + this.marks = []; + + // Match the coordinates of the target element + this.element.style.position = 'absolute'; + // Disable pointer events + this.element.setAttribute('pointer-events', 'none'); + + // Set up mouse event proxying between the target element and the marks + _events2.default.proxyMouse(this.target, this.marks); + + this.container = container; + this.container.appendChild(this.element); + + this.render(); + } + + _createClass(Pane, [{ + key: 'addMark', + value: function addMark(mark) { + var g = _svg2.default.createElement('g'); + this.element.appendChild(g); + mark.bind(g, this.container); + + this.marks.push(mark); + + mark.render(); + return mark; + } + }, { + key: 'removeMark', + value: function removeMark(mark) { + var idx = this.marks.indexOf(mark); + if (idx === -1) { + return; + } + var el = mark.unbind(); + this.element.removeChild(el); + this.marks.splice(idx, 1); + } + }, { + key: 'render', + value: function render() { + setCoords(this.element, coords(this.target, this.container)); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.marks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var m = _step.value; + + m.render(); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } + }]); + + return Pane; +}(); + +var Mark = exports.Mark = function () { + function Mark() { + _classCallCheck(this, Mark); + + this.element = null; + } + + _createClass(Mark, [{ + key: 'bind', + value: function bind(element, container) { + this.element = element; + this.container = container; + } + }, { + key: 'unbind', + value: function unbind() { + var el = this.element; + this.element = null; + return el; + } + }, { + key: 'render', + value: function render() {} + }, { + key: 'dispatchEvent', + value: function dispatchEvent(e) { + if (!this.element) return; + this.element.dispatchEvent(e); + } + }, { + key: 'getBoundingClientRect', + value: function getBoundingClientRect() { + return this.element.getBoundingClientRect(); + } + }, { + key: 'getClientRects', + value: function getClientRects() { + var rects = []; + var el = this.element.firstChild; + while (el) { + rects.push(el.getBoundingClientRect()); + el = el.nextSibling; + } + return rects; + } + }, { + key: 'filteredRanges', + value: function filteredRanges() { + var rects = Array.from(this.range.getClientRects()); + + // De-duplicate the boxes + return rects.filter(function (box) { + for (var i = 0; i < rects.length; i++) { + if (rects[i] === box) { + return true; + } + var contained = contains(rects[i], box); + if (contained) { + return false; + } + } + return true; + }); + } + }]); + + return Mark; +}(); + +var Highlight = exports.Highlight = function (_Mark) { + _inherits(Highlight, _Mark); + + function Highlight(range, className, data, attributes) { + _classCallCheck(this, Highlight); + + var _this = _possibleConstructorReturn(this, (Highlight.__proto__ || Object.getPrototypeOf(Highlight)).call(this)); + + _this.range = range; + _this.className = className; + _this.data = data || {}; + _this.attributes = attributes || {}; + return _this; + } + + _createClass(Highlight, [{ + key: 'bind', + value: function bind(element, container) { + _get(Highlight.prototype.__proto__ || Object.getPrototypeOf(Highlight.prototype), 'bind', this).call(this, element, container); + + for (var attr in this.data) { + if (this.data.hasOwnProperty(attr)) { + this.element.dataset[attr] = this.data[attr]; + } + } + + for (var attr in this.attributes) { + if (this.attributes.hasOwnProperty(attr)) { + this.element.setAttribute(attr, this.attributes[attr]); + } + } + + if (this.className) { + this.element.classList.add(this.className); + } + } + }, { + key: 'render', + value: function render() { + // Empty element + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + + var docFrag = this.element.ownerDocument.createDocumentFragment(); + var filtered = this.filteredRanges(); + var offset = this.element.getBoundingClientRect(); + var container = this.container.getBoundingClientRect(); + + for (var i = 0, len = filtered.length; i < len; i++) { + var r = filtered[i]; + var el = _svg2.default.createElement('rect'); + el.setAttribute('x', r.left - offset.left + container.left); + el.setAttribute('y', r.top - offset.top + container.top); + el.setAttribute('height', r.height); + el.setAttribute('width', r.width); + docFrag.appendChild(el); + } + + this.element.appendChild(docFrag); + } + }]); + + return Highlight; +}(Mark); + +var Underline = exports.Underline = function (_Highlight) { + _inherits(Underline, _Highlight); + + function Underline(range, className, data, attributes) { + _classCallCheck(this, Underline); + + return _possibleConstructorReturn(this, (Underline.__proto__ || Object.getPrototypeOf(Underline)).call(this, range, className, data, attributes)); + } + + _createClass(Underline, [{ + key: 'render', + value: function render() { + // Empty element + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + + var docFrag = this.element.ownerDocument.createDocumentFragment(); + var filtered = this.filteredRanges(); + var offset = this.element.getBoundingClientRect(); + var container = this.container.getBoundingClientRect(); + + for (var i = 0, len = filtered.length; i < len; i++) { + var r = filtered[i]; + + var rect = _svg2.default.createElement('rect'); + rect.setAttribute('x', r.left - offset.left + container.left); + rect.setAttribute('y', r.top - offset.top + container.top); + rect.setAttribute('height', r.height); + rect.setAttribute('width', r.width); + rect.setAttribute('fill', 'none'); + + var line = _svg2.default.createElement('line'); + line.setAttribute('x1', r.left - offset.left + container.left); + line.setAttribute('x2', r.left - offset.left + container.left + r.width); + line.setAttribute('y1', r.top - offset.top + container.top + r.height - 1); + line.setAttribute('y2', r.top - offset.top + container.top + r.height - 1); + + line.setAttribute('stroke-width', 1); + line.setAttribute('stroke', 'black'); //TODO: match text color? + line.setAttribute('stroke-linecap', 'square'); + + docFrag.appendChild(rect); + + docFrag.appendChild(line); + } + + this.element.appendChild(docFrag); + } + }]); + + return Underline; +}(Highlight); + +function coords(el, container) { + var offset = container.getBoundingClientRect(); + var rect = el.getBoundingClientRect(); + + return { + top: rect.top - offset.top, + left: rect.left - offset.left, + height: el.scrollHeight, + width: el.scrollWidth + }; +} + +function setCoords(el, coords) { + el.style.top = coords.top + 'px'; + el.style.left = coords.left + 'px'; + el.style.height = coords.height + 'px'; + el.style.width = coords.width + 'px'; +} + +function contains(rect1, rect2) { + return rect2.right <= rect1.right && rect2.left >= rect1.left && rect2.top >= rect1.top && rect2.bottom <= rect1.bottom; +} + +/***/ }), +/* 54 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createElement = createElement; +function createElement(name) { + return document.createElementNS('http://www.w3.org/2000/svg', name); +} + +exports.default = { + createElement: createElement +}; + +/***/ }), +/* 55 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.proxyMouse = proxyMouse; +exports.clone = clone; +// import 'babelify/polyfill'; // needed for Object.assign + +exports.default = { + proxyMouse: proxyMouse +}; + +/** + * Start proxying all mouse events that occur on the target node to each node in + * a set of tracked nodes. + * + * The items in tracked do not strictly have to be DOM Nodes, but they do have + * to have dispatchEvent, getBoundingClientRect, and getClientRects methods. + * + * @param target {Node} The node on which to listen for mouse events. + * @param tracked {Node[]} A (possibly mutable) array of nodes to which to proxy + * events. + */ + +function proxyMouse(target, tracked) { + function dispatch(e) { + // We walk through the set of tracked elements in reverse order so that + // events are sent to those most recently added first. + // + // This is the least surprising behaviour as it simulates the way the + // browser would work if items added later were drawn "on top of" + // earlier ones. + for (var i = tracked.length - 1; i >= 0; i--) { + var t = tracked[i]; + var x = e.clientX; + var y = e.clientY; + + if (e.touches && e.touches.length) { + x = e.touches[0].clientX; + y = e.touches[0].clientY; + } + + if (!contains(t, target, x, y)) { + continue; + } + + // The event targets this mark, so dispatch a cloned event: + t.dispatchEvent(clone(e)); + // We only dispatch the cloned event to the first matching mark. + break; + } + } + + if (target.nodeName === "iframe" || target.nodeName === "IFRAME") { + + try { + // Try to get the contents if same domain + this.target = target.contentDocument; + } catch (err) { + this.target = target; + } + } else { + this.target = target; + } + + var _arr = ['mouseup', 'mousedown', 'click', 'touchstart']; + for (var _i = 0; _i < _arr.length; _i++) { + var ev = _arr[_i]; + this.target.addEventListener(ev, function (e) { + return dispatch(e); + }, false); + } +} + +/** + * Clone a mouse event object. + * + * @param e {MouseEvent} A mouse event object to clone. + * @returns {MouseEvent} + */ +function clone(e) { + var opts = Object.assign({}, e, { bubbles: false }); + try { + return new MouseEvent(e.type, opts); + } catch (err) { + // compat: webkit + var copy = document.createEvent('MouseEvents'); + copy.initMouseEvent(e.type, false, opts.cancelable, opts.view, opts.detail, opts.screenX, opts.screenY, opts.clientX, opts.clientY, opts.ctrlKey, opts.altKey, opts.shiftKey, opts.metaKey, opts.button, opts.relatedTarget); + return copy; + } +} + +/** + * Check if the item contains the point denoted by the passed coordinates + * @param item {Object} An object with getBoundingClientRect and getClientRects + * methods. + * @param x {Number} + * @param y {Number} + * @returns {Boolean} + */ +function contains(item, target, x, y) { + // offset + var offset = target.getBoundingClientRect(); + + function rectContains(r, x, y) { + var top = r.top - offset.top; + var left = r.left - offset.left; + var bottom = top + r.height; + var right = left + r.width; + return top <= y && left <= x && bottom > y && right > x; + } + + // Check overall bounding box first + var rect = item.getBoundingClientRect(); + if (!rectContains(rect, x, y)) { + return false; + } + + // Then continue to check each child rect + var rects = item.getClientRects(); + for (var i = 0, len = rects.length; i < len; i++) { + if (rectContains(rects[i], x, y)) { + return true; + } + } + return false; +} + +/***/ }), +/* 56 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _throttle = __webpack_require__(57); + +var _throttle2 = _interopRequireDefault(_throttle); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Stage = function () { + function Stage(_options) { + _classCallCheck(this, Stage); + + this.settings = _options || {}; + this.id = "epubjs-container-" + (0, _core.uuid)(); + + 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 + */ + + + _createClass(Stage, [{ + key: "create", + value: function 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"; + var direction = options.direction; + + if (options.height && (0, _core.isNumber)(options.height)) { + height = options.height + "px"; + } + + if (options.width && (0, _core.isNumber)(options.width)) { + width = options.width + "px"; + } + + // Create new container element + var 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"; + container.style.position = "relative"; + + if (axis === "horizontal") { + // container.style.whiteSpace = "nowrap"; + container.style.display = "flex"; + container.style.flexDirection = "row"; + container.style.flexWrap = "nowrap"; + } + + if (width) { + container.style.width = width; + } + + if (height) { + container.style.height = height; + } + + if (overflow) { + container.style.overflow = overflow; + } + + if (direction) { + container.dir = direction; + container.style["direction"] = direction; + } + + if (direction && this.settings.fullsize) { + document.body.style["direction"] = direction; + } + + return container; + } + }, { + key: "wrap", + value: function 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; + } + }, { + key: "getElement", + value: function getElement(_element) { + var element; + + if ((0, _core.isElement)(_element)) { + element = _element; + } else if (typeof _element === "string") { + element = document.getElementById(_element); + } + + if (!element) { + throw new Error("Not an Element"); + } + + return element; + } + }, { + key: "attachTo", + value: function attachTo(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; + } + }, { + key: "getContainer", + value: function getContainer() { + return this.container; + } + }, { + key: "onResize", + value: function 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 (!(0, _core.isNumber)(this.settings.width) || !(0, _core.isNumber)(this.settings.height)) { + this.resizeFunc = (0, _throttle2.default)(func, 50); + window.addEventListener("resize", this.resizeFunc, false); + } + } + }, { + key: "onOrientationChange", + value: function onOrientationChange(func) { + this.orientationChangeFunc = func; + window.addEventListener("orientationchange", this.orientationChangeFunc, false); + } + }, { + key: "size", + value: function 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"; + } + } + + if (height === null) { + bounds = bounds || this.element.getBoundingClientRect(); + + if (bounds.height) { + height = bounds.height; + this.container.style.height = bounds.height + "px"; + } + } + + if (!(0, _core.isNumber)(width)) { + bounds = this.container.getBoundingClientRect(); + width = bounds.width; + //height = bounds.height; + } + + if (!(0, _core.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 + }; + + // Bounds not set, get them from window + var _windowBounds = (0, _core.windowBounds)(); + if (!width) { + width = _windowBounds.width; + } + if (this.settings.fullsize || !height) { + height = _windowBounds.height; + } + + return { + width: width - this.containerPadding.left - this.containerPadding.right, + height: height - this.containerPadding.top - this.containerPadding.bottom + }; + } + }, { + key: "bounds", + value: function bounds() { + var box = void 0; + if (this.container.style.overflow !== "visible") { + box = this.container && this.container.getBoundingClientRect(); + } + + if (!box || !box.width || !box.height) { + return (0, _core.windowBounds)(); + } else { + return box; + } + } + }, { + key: "getSheet", + value: function 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; + } + }, { + key: "addStyleRules", + value: function 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); + } + }, { + key: "axis", + value: function axis(_axis) { + if (_axis === "horizontal") { + this.container.style.display = "flex"; + this.container.style.flexDirection = "row"; + this.container.style.flexWrap = "nowrap"; + } else { + this.container.style.display = "block"; + } + } + + // orientation(orientation) { + // if (orientation === "landscape") { + // + // } else { + // + // } + // + // this.orientation = orientation; + // } + + }, { + key: "direction", + value: function direction(dir) { + if (this.container) { + this.container.dir = dir; + this.container.style["direction"] = dir; + } + + if (this.settings.fullsize) { + document.body.style["direction"] = dir; + } + } + }, { + key: "destroy", + value: function destroy() { + var base; + + if (this.element) { + + if (this.settings.hidden) { + base = this.wrapper; + } else { + base = this.container; + } + + if (this.element.contains(this.container)) { + this.element.removeChild(this.container); + } + + window.removeEventListener("resize", this.resizeFunc); + window.removeEventListener("orientationChange", this.orientationChangeFunc); + } + } + }]); + + return Stage; +}(); + +exports.default = Stage; +module.exports = exports["default"]; + +/***/ }), +/* 57 */ +/***/ (function(module, exports, __webpack_require__) { + +var debounce = __webpack_require__(21), + isObject = __webpack_require__(15); + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ +function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); +} + +module.exports = throttle; + + +/***/ }), +/* 58 */ +/***/ (function(module, exports, __webpack_require__) { + +var root = __webpack_require__(22); + +/** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ +var now = function() { + return root.Date.now(); +}; + +module.exports = now; + + +/***/ }), +/* 59 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +module.exports = freeGlobal; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(8))) + +/***/ }), +/* 60 */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(15), + isSymbol = __webpack_require__(61); + +/** Used as references for various `Number` constants. */ +var NAN = 0 / 0; + +/** Used to match leading and trailing whitespace. */ +var reTrim = /^\s+|\s+$/g; + +/** Used to detect bad signed hexadecimal string values. */ +var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + +/** Used to detect binary string values. */ +var reIsBinary = /^0b[01]+$/i; + +/** Used to detect octal string values. */ +var reIsOctal = /^0o[0-7]+$/i; + +/** Built-in method references without a dependency on `root`. */ +var freeParseInt = parseInt; + +/** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ +function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); +} + +module.exports = toNumber; + + +/***/ }), +/* 61 */ +/***/ (function(module, exports, __webpack_require__) { + +var baseGetTag = __webpack_require__(62), + isObjectLike = __webpack_require__(65); + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); +} + +module.exports = isSymbol; + + +/***/ }), +/* 62 */ +/***/ (function(module, exports, __webpack_require__) { + +var Symbol = __webpack_require__(23), + getRawTag = __webpack_require__(63), + objectToString = __webpack_require__(64); + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +module.exports = baseGetTag; + + +/***/ }), +/* 63 */ +/***/ (function(module, exports, __webpack_require__) { + +var Symbol = __webpack_require__(23); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +module.exports = getRawTag; + + +/***/ }), +/* 64 */ +/***/ (function(module, exports) { + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} + +module.exports = objectToString; + + +/***/ }), +/* 65 */ +/***/ (function(module, exports) { + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +module.exports = isObjectLike; + + +/***/ }), +/* 66 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Views = function () { + function Views(container) { + _classCallCheck(this, Views); + + this.container = container; + this._views = []; + this.length = 0; + this.hidden = false; + } + + _createClass(Views, [{ + key: "all", + value: function all() { + return this._views; + } + }, { + key: "first", + value: function first() { + return this._views[0]; + } + }, { + key: "last", + value: function last() { + return this._views[this._views.length - 1]; + } + }, { + key: "indexOf", + value: function indexOf(view) { + return this._views.indexOf(view); + } + }, { + key: "slice", + value: function slice() { + return this._views.slice.apply(this._views, arguments); + } + }, { + key: "get", + value: function get(i) { + return this._views[i]; + } + }, { + key: "append", + value: function append(view) { + this._views.push(view); + if (this.container) { + this.container.appendChild(view.element); + } + this.length++; + return view; + } + }, { + key: "prepend", + value: function prepend(view) { + this._views.unshift(view); + if (this.container) { + this.container.insertBefore(view.element, this.container.firstChild); + } + this.length++; + return view; + } + }, { + key: "insert", + value: function insert(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 { + this.container.appendChild(view.element); + } + } + + this.length++; + return view; + } + }, { + key: "remove", + value: function remove(view) { + var index = this._views.indexOf(view); + + if (index > -1) { + this._views.splice(index, 1); + } + + this.destroy(view); + + this.length--; + } + }, { + key: "destroy", + value: function destroy(view) { + if (view.displayed) { + view.destroy(); + } + + if (this.container) { + this.container.removeChild(view.element); + } + view = null; + } + + // Iterators + + }, { + key: "forEach", + value: function forEach() { + return this._views.forEach.apply(this._views, arguments); + } + }, { + key: "clear", + value: function 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._views = []; + this.length = 0; + } + }, { + key: "find", + value: function 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; + } + } + } + }, { + key: "displayed", + value: function 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; + } + }, { + key: "show", + value: function 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; + } + }, { + key: "hide", + value: function 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; + } + }]); + + return Views; +}(); + +exports.default = Views; +module.exports = exports["default"]; + +/***/ }), +/* 67 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = __webpack_require__(0); + +var _request = __webpack_require__(11); + +var _request2 = _interopRequireDefault(_request); + +var _mime = __webpack_require__(17); + +var _mime2 = _interopRequireDefault(_mime); + +var _path = __webpack_require__(4); + +var _path2 = _interopRequireDefault(_path); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles Unzipping a requesting files from an Epub Archive + * @class + */ +var Archive = function () { + function Archive() { + _classCallCheck(this, Archive); + + this.zip = undefined; + this.urlCache = {}; + + this.checkRequirements(); + } + + /** + * Checks to see if JSZip exists in global namspace, + * Requires JSZip if it isn't there + * @private + */ + + + _createClass(Archive, [{ + key: "checkRequirements", + value: function checkRequirements() { + try { + if (typeof JSZip === "undefined") { + var _JSZip = __webpack_require__(68); + this.zip = new _JSZip(); + } else { + this.zip = new JSZip(); + } + } catch (e) { + throw new Error("JSZip lib not loaded"); + } + } + + /** + * Open an archive + * @param {binary} input + * @param {boolean} isBase64 tells JSZip if the input data is base64 encoded + * @return {Promise} zipfile + */ + + }, { + key: "open", + value: function open(input, isBase64) { + return this.zip.loadAsync(input, { "base64": isBase64 }); + } + + /** + * Load and Open an archive + * @param {string} zipUrl + * @param {boolean} isBase64 tells JSZip if the input data is base64 encoded + * @return {Promise} zipfile + */ + + }, { + key: "openUrl", + value: function openUrl(zipUrl, isBase64) { + return (0, _request2.default)(zipUrl, "binary").then(function (data) { + return this.zip.loadAsync(data, { "base64": isBase64 }); + }.bind(this)); + } + + /** + * Request a url from the archive + * @param {string} url a url to request from the archive + * @param {string} [type] specify the type of the returned result + * @return {Promise} + */ + + }, { + key: "request", + value: function request(url, type) { + var deferred = new _core.defer(); + var response; + var path = new _path2.default(url); + + // If type isn't set, determine it from the file extension + if (!type) { + type = path.extension; + } + + if (type == "blob") { + response = this.getBlob(url); + } else { + response = this.getText(url); + } + + if (response) { + response.then(function (r) { + var result = this.handleResponse(r, type); + deferred.resolve(result); + }.bind(this)); + } else { + deferred.reject({ + message: "File not found in the epub: " + url, + stack: new Error().stack + }); + } + return deferred.promise; + } + + /** + * Handle the response from request + * @private + * @param {any} response + * @param {string} [type] + * @return {any} the parsed result + */ + + }, { + key: "handleResponse", + value: function handleResponse(response, type) { + var r; + + if (type == "json") { + r = JSON.parse(response); + } else if ((0, _core.isXml)(type)) { + r = (0, _core.parse)(response, "text/xml"); + } else if (type == "xhtml") { + r = (0, _core.parse)(response, "application/xhtml+xml"); + } else if (type == "html" || type == "htm") { + r = (0, _core.parse)(response, "text/html"); + } else { + r = response; + } + + return r; + } + + /** + * Get a Blob from Archive by Url + * @param {string} url + * @param {string} [mimeType] + * @return {Blob} + */ + + }, { + key: "getBlob", + value: function getBlob(url, mimeType) { + var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash + var entry = this.zip.file(decodededUrl); + + if (entry) { + mimeType = mimeType || _mime2.default.lookup(entry.name); + return entry.async("uint8array").then(function (uint8array) { + return new Blob([uint8array], { type: mimeType }); + }); + } + } + + /** + * Get Text from Archive by Url + * @param {string} url + * @param {string} [encoding] + * @return {string} + */ + + }, { + key: "getText", + value: function getText(url, encoding) { + var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash + var entry = this.zip.file(decodededUrl); + + if (entry) { + return entry.async("string").then(function (text) { + return text; + }); + } + } + + /** + * Get a base64 encoded result from Archive by Url + * @param {string} url + * @param {string} [mimeType] + * @return {string} base64 encoded + */ + + }, { + key: "getBase64", + value: function getBase64(url, mimeType) { + var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash + var entry = this.zip.file(decodededUrl); + + if (entry) { + mimeType = mimeType || _mime2.default.lookup(entry.name); + return entry.async("base64").then(function (data) { + return "data:" + mimeType + ";base64," + data; + }); + } + } + + /** + * Create a Url from an unarchived item + * @param {string} url + * @param {object} [options.base64] use base64 encoding or blob url + * @return {Promise} url promise with Url string + */ + + }, { + key: "createUrl", + value: function createUrl(url, options) { + var deferred = new _core.defer(); + var _URL = window.URL || window.webkitURL || window.mozURL; + var tempUrl; + var response; + var useBase64 = options && options.base64; + + if (url in this.urlCache) { + deferred.resolve(this.urlCache[url]); + return deferred.promise; + } + + if (useBase64) { + response = this.getBase64(url); + + if (response) { + response.then(function (tempUrl) { + + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); + }.bind(this)); + } + } else { + + response = this.getBlob(url); + + if (response) { + response.then(function (blob) { + + tempUrl = _URL.createObjectURL(blob); + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); + }.bind(this)); + } + } + + if (!response) { + deferred.reject({ + message: "File not found in the epub: " + url, + stack: new Error().stack + }); + } + + return deferred.promise; + } + + /** + * Revoke Temp Url for a achive item + * @param {string} url url of the item in the archive + */ + + }, { + key: "revokeUrl", + value: function revokeUrl(url) { + var _URL = window.URL || window.webkitURL || window.mozURL; + var fromCache = this.urlCache[url]; + if (fromCache) _URL.revokeObjectURL(fromCache); + } + }, { + key: "destroy", + value: function destroy() { + var _URL = window.URL || window.webkitURL || window.mozURL; + for (var fromCache in this.urlCache) { + _URL.revokeObjectURL(fromCache); + } + this.zip = undefined; + this.urlCache = {}; + } + }]); + + return Archive; +}(); + +exports.default = Archive; +module.exports = exports["default"]; + +/***/ }), +/* 68 */ +/***/ (function(module, exports) { + +if(typeof __WEBPACK_EXTERNAL_MODULE_68__ === 'undefined') {var e = new Error("Cannot find module \"jszip\""); e.code = 'MODULE_NOT_FOUND'; throw e;} +module.exports = __WEBPACK_EXTERNAL_MODULE_68__; + +/***/ }), +/* 69 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global, module) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* From https://github.com/webcomponents/URL/blob/master/url.js + * Added UMD, file link handling */ + +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +(function (root, factory) { + // Fix for this being undefined in modules + if (!root) { + root = window || global; + } + if (( false ? 'undefined' : _typeof(module)) === 'object' && module.exports) { + // Node + module.exports = factory(root); + } else if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else { + // Browser globals (root is window) + root.URL = factory(root); + } +})(undefined, function (scope) { + // feature detect for URL constructor + var hasWorkingUrl = false; + if (!scope.forceJURL) { + try { + var u = new URL('b', 'http://a'); + u.pathname = 'c%20d'; + hasWorkingUrl = u.href === 'http://a/c%20d'; + } catch (e) {} + } + + if (hasWorkingUrl) return scope.URL; + + var relative = Object.create(null); + relative['ftp'] = 21; + relative['file'] = 0; + relative['gopher'] = 70; + relative['http'] = 80; + relative['https'] = 443; + relative['ws'] = 80; + relative['wss'] = 443; + + var relativePathDotMapping = Object.create(null); + relativePathDotMapping['%2e'] = '.'; + relativePathDotMapping['.%2e'] = '..'; + relativePathDotMapping['%2e.'] = '..'; + relativePathDotMapping['%2e%2e'] = '..'; + + function isRelativeScheme(scheme) { + return relative[scheme] !== undefined; + } + + function invalid() { + clear.call(this); + this._isInvalid = true; + } + + function IDNAToASCII(h) { + if ('' == h) { + invalid.call(this); + } + // XXX + return h.toLowerCase(); + } + + function percentEscape(c) { + var unicode = c.charCodeAt(0); + if (unicode > 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 toString() { + 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 'file': + return 'file://'; // EPUBJS Added + case 'data': + 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; +}); +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(8), __webpack_require__(70)(module))) + +/***/ }), +/* 70 */ +/***/ (function(module, exports) { + +module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + if(!module.children) module.children = []; + Object.defineProperty(module, "loaded", { + enumerable: true, + get: function() { + return module.l; + } + }); + Object.defineProperty(module, "id", { + enumerable: true, + get: function() { + return module.i; + } + }); + module.webpackPolyfill = 1; + } + return module; +}; + + +/***/ }) +/******/ ]); +}); +//# sourceMappingURL=epub.js.map \ No newline at end of file