UNPKG

epubjs

Version:
1,977 lines (1,677 loc) 283 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory((function webpackLoadOptionalExternalModule() { try { return require("JSZip"); } catch(e) {} }()), require("xmldom")); else if(typeof define === 'function' && define.amd) define(["JSZip", "xmldom"], factory); else if(typeof exports === 'object') exports["ePub"] = factory((function webpackLoadOptionalExternalModule() { try { return require("JSZip"); } catch(e) {} }()), require("xmldom")); else root["ePub"] = factory(root["JSZip"], root["xmldom"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_48__, __WEBPACK_EXTERNAL_MODULE_14__) { 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; /******/ /******/ // identity function for calling harmory imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmory exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ 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 = 49); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { "use strict"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isElement = isElement; exports.uuid = uuid; exports.documentHeight = documentHeight; 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.cleanStringForXpath = cleanStringForXpath; exports.indexOfTextNode = indexOfTextNode; exports.isXml = isXml; exports.createBlob = createBlob; exports.createBlobUrl = createBlobUrl; 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; var requestAnimationFrame = exports.requestAnimationFrame = typeof window != "undefined" ? window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame : false; function isElement(obj) { return !!(obj && obj.nodeType == 1); } // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript 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; } function documentHeight() { return Math.max(document.documentElement.clientHeight, document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight); } function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function isFloat(n) { return isNumber(n) && Math.floor(n) !== n; } function prefixed(unprefixed) { var vendors = ["Webkit", "Moz", "O", "ms"]; // var prefixes = ["-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 vendors[i] + upper; } } return unprefixed; } 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; } 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 function insert(item, array, compareFunction) { var location = locationOf(item, array, compareFunction); array.splice(location, 0, item); return location; } // Returns where something would fit in function locationOf(item, array, compareFunction, _start, _end) { 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); } } // Returns -1 of mpt found 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); } } 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 }; } 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 }; } function windowBounds() { var width = window.innerWidth; var height = window.innerHeight; return { top: 0, left: 0, right: width, bottom: height, width: width, height: height }; } //-- https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496 function cleanStringForXpath(str) { var parts = str.match(/[^'"]+|['"]/g); parts = parts.map(function (part) { if (part === "'") { return "\"\'\""; // output "'" } if (part === "\"") { return "\'\"\'"; // output '"' } return "'" + part + "'"; }); return "concat(''," + parts.join(",") + ")"; } function indexOfTextNode(textNode) { var parent = textNode.parentNode; var children = parent.childNodes; var sib; var index = -1; for (var i = 0; i < children.length; i++) { sib = children[i]; if (sib.nodeType === Node.TEXT_NODE) { index++; } if (sib == textNode) break; } return index; } function isXml(ext) { return ["xml", "opf", "ncx"].indexOf(ext) > -1; } function createBlob(content, mime) { return new Blob([content], { type: mime }); } function createBlobUrl(content, mime) { var _URL = window.URL || window.webkitURL || window.mozURL; var tempUrl; var blob = this.createBlob(content, mime); tempUrl = _URL.createObjectURL(blob); return tempUrl; } function createBase64Url(content, mime) { var data; var datauri; if (typeof content !== "string") { // Only handles strings return; } data = btoa(content); datauri = "data:" + mime + ";base64," + data; return datauri; } function type(obj) { return Object.prototype.toString.call(obj).slice(8, -1); } function parse(markup, mime, forceXMLDom) { var doc; var Parser; if (typeof DOMParser === "undefined" || forceXMLDom) { Parser = __webpack_require__(14).DOMParser; } else { Parser = DOMParser; } doc = new Parser().parseFromString(markup, mime); return doc; } 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]; } } } function qsa(el, sel) { if (typeof el.querySelector != "undefined") { return el.querySelectorAll(sel); } else { return el.getElementsByTagName(sel); } } 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 * @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); } } // export function walk(root, func, onlyText) { // var node = root; // // if (node && !onlyText || node.nodeType === 3) { // Node.TEXT_NODE // func(node); // } // console.log(root); // // node = node.firstChild; // while(node) { // walk(node, func, onlyText); // node = node.nextSibling; // } // } /** * @param callback return false for continue,true for break * @return boolean true: break visit; */ 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); } } function blob2base64(blob, cb) { var reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = function () { cb(reader.result); }; } // From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible 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); } 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) { return query[i]; } } } else { return query; } } function findChildren(el) { var result = []; var childNodes = el.parentNode.childNodes; for (var i = 0; i < childNodes.length; i++) { var node = childNodes[i]; if (node.nodeType === 1) { result.push(node); } } return result; } /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { "use strict"; "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"); } } /** EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html Implements: - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) Does Not Implement: - Temporal Offset (~) - Spatial Offset (@) - Temporal-Spatial Offset (~ + @) - Text Location Assertion ([) */ var ELEMENT_NODE = 1; var TEXT_NODE = 3; // const COMMENT_NODE = 8; var DOCUMENT_NODE = 9; 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"); } } _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; } } }, { 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]) || null; textLocationAssertion = assertion[1]; } else { characterOffset = parseInt(termialStr) || 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; } }, { 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.start) { cfiString += ","; cfiString += this.segmentString(this.start); } if (this.end) { cfiString += ","; cfiString += this.segmentString(this.end); } cfiString += ")"; return cfiString; } }, { key: "compare", value: function compare(cfiOne, cfiTwo) { var stepsA, stepsB; var terminalA, terminalB; if (typeof cfiOne === "string") { cfiOne = new EpubCFI(cfiOne); } if (typeof cfiTwo === "string") { cfiTwo = new EpubCFI(cfiTwo); } // Compare Spine Positions if (cfiOne.spinePos > cfiTwo.spinePos) { return 1; } if (cfiOne.spinePos < cfiTwo.spinePos) { return -1; } if (cfiOne.range) { stepsA = cfiOne.path.steps.concat(cfiOne.start.steps); terminalA = cfiOne.start.terminal; } else { stepsA = cfiOne.path.steps; terminalA = cfiOne.path.terminal; } if (cfiTwo.range) { stepsB = cfiTwo.path.steps.concat(cfiTwo.start.steps); terminalB = cfiTwo.start.terminal; } else { stepsB = cfiTwo.path.steps; terminalB = cfiTwo.path.terminal; } // Compare Each Step in the First item for (var i = 0; i < stepsA.length; i++) { if (!stepsA[i]) { return -1; } if (!stepsB[i]) { return 1; } if (stepsA[i].index > stepsB[i].index) { return 1; } if (stepsA[i].index < stepsB[i].index) { return -1; } // Otherwise continue checking } // All steps in First equal to Second and First is Less Specific if (stepsA.length < stepsB.length) { return 1; } // Compare the charecter offset of the text node if (terminalA.offset > terminalB.offset) { return 1; } if (terminalA.offset < terminalB.offset) { return -1; } // CFI's are equal return 0; } }, { 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; } }, { 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; } }, { 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 step; var len = steps.length; var i; for (i = 0; i < len; i++) { step = steps[i]; if (step.type === "element") { container = container.children[step.index]; } else if (step.type === "text") { container = this.textNodes(container, ignoreClass)[step.index]; } } return container; } }, { 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 }; } }, { key: "toRange", value: function toRange(_doc, ignoreClass) { var doc = _doc || document; var range = doc.createRange(); var start, end, startContainer, endContainer; var cfi = this; var startSteps, endSteps; var needsIgnoring = ignoreClass ? doc.querySelector("." + ignoreClass) != null : false; var missed; if (cfi.range) { start = cfi.start; startSteps = cfi.path.steps.concat(start.steps); startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); end = cfi.end; endSteps = cfi.path.steps.concat(end.steps); endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); } else { start = cfi.path; startSteps = cfi.path.steps; startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); } if (startContainer) { try { if (start.terminal.offset != null) { range.setStart(startContainer, start.terminal.offset); } else { range.setStart(startContainer, 0); } } catch (e) { missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); range.setStart(missed.container, missed.offset); } } else { // No start found return null; } if (endContainer) { try { if (end.terminal.offset != null) { range.setEnd(endContainer, end.terminal.offset); } else { range.setEnd(endContainer, 0); } } catch (e) { missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); range.setEnd(missed.container, missed.offset); } } // doc.defaultView.getSelection().addRange(range); return range; } // is a cfi string, should be wrapped with "epubcfi()" }, { 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, cfi = "/" + spineNodeIndex + "/"; cfi += (pos + 1) * 2; if (id) { cfi += "[" + id + "]"; } return cfi; } }]); return EpubCFI; }(); exports.default = EpubCFI; module.exports = exports["default"]; /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { "use strict"; 'use strict'; var d = __webpack_require__(33) , callable = __webpack_require__(42) , 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"; "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__(5); 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"); } } 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); } _createClass(Path, [{ key: "parse", value: function parse(what) { return _pathWebpack2.default.parse(what); } }, { key: "isAbsolute", value: function isAbsolute(what) { return _pathWebpack2.default.isAbsolute(what || this.path); } }, { key: "isDirectory", value: function isDirectory(what) { return what.charAt(what.length - 1) === "/"; } }, { key: "resolve", value: function resolve(what) { return _pathWebpack2.default.resolve(this.directory, what); } }, { 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); } }, { key: "toString", value: function toString() { return this.path; } }]); return Path; }(); exports.default = Path; module.exports = exports["default"]; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { "use strict"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.replaceBase = replaceBase; exports.replaceCanonical = replaceCanonical; exports.replaceLinks = replaceLinks; exports.substitute = substitute; var _core = __webpack_require__(0); var _url = __webpack_require__(11); var _url2 = _interopRequireDefault(_url); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function replaceBase(doc, section) { var base; var head; if (!doc) { return; } // head = doc.querySelector("head"); // base = head.querySelector("base"); head = (0, _core.qs)(doc, "head"); base = (0, _core.qs)(head, "base"); if (!base) { base = doc.createElement("base"); head.insertBefore(base, head.firstChild); } base.setAttribute("href", section.url); } function replaceCanonical(doc, section) { var head; var link; var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url); 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); } } // TODO: move me to Contents function replaceLinks(contents, fn) { var links = contents.querySelectorAll("a[href]"); var base = (0, _core.qs)(contents.ownerDocument, "base"); var location = base ? base.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; } /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { "use strict"; /* WEBPACK VAR INJECTION */(function(process) {'use strict'; 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 += '