UNPKG

epubjs

Version:
297 lines (249 loc) 7.15 kB
"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 = require("./utils/core"); var _queue = require("./utils/queue"); var _queue2 = _interopRequireDefault(_queue); var _epubcfi = require("./epubcfi"); var _epubcfi2 = _interopRequireDefault(_epubcfi); var _eventEmitter = require("event-emitter"); 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) { _classCallCheck(this, Locations); this.spine = spine; this.request = request; this.q = new _queue2.default(this); this.epubcfi = new _epubcfi2.default(); this._locations = []; this.total = 0; this.break = 150; this._current = 0; } /** * Load all of sections in the book to generate locations * @param {int} chars how many chars to split on * @return {object} locations */ _createClass(Locations, [{ key: "generate", value: function generate(chars) { if (chars) { this.break = chars; } this.q.pause(); this.spine.each(function (section) { this.q.enqueue(this.process.bind(this), section); }.bind(this)); return this.q.run().then(function () { this.total = this._locations.length - 1; if (this._currentCfi) { this.currentLocation = this._currentCfi; } return this._locations; // console.log(this.percentage(this.book.rendition.location.start), this.percentage(this.book.rendition.location.end)); }.bind(this)); } }, { 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 locations = this.parse(contents, section.cfiBase); this._locations = this._locations.concat(locations); }.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) { // counter = this.break; pos += dist; // Gone over if (pos >= len) { // Continue counter for next node counter = len - (pos - _break); // At End } else { // End the previous range range.endContainer = node; range.endOffset = pos; // cfi = section.cfiFromRange(range); var cfi = new _epubcfi2.default(range, cfiBase).toString(); locations.push(cfi); counter = 0; // Start new range pos += 1; range = this.createRange(); range.startContainer = node; range.startOffset = pos; dist = _break; } } prev = node; }; (0, _core.sprint)(body, parser.bind(this)); // Close remaining if (range && range.startContainer && prev) { range.endContainer = prev; range.endOffset = prev.length; // cfi = section.cfiFromRange(range); var cfi = new _epubcfi2.default(range, cfiBase).toString(); locations.push(cfi); counter = 0; } return locations; } }, { key: "locationFromCfi", value: function locationFromCfi(cfi) { // Check if the location has not been set yet if (this._locations.length === 0) { return -1; } return (0, _core.locationOf)(cfi.start, this._locations, this.epubcfi.compare); } }, { 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); } }, { key: "percentageFromLocation", value: function percentageFromLocation(loc) { if (!loc || !this.total) { return 0; } return loc / this.total; } }, { 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; } }, { key: "cfiFromPercentage", value: function cfiFromPercentage(value) { var percentage = value > 1 ? value / 100 : value; // Normalize value to 0-1 var loc = Math.ceil(this.total * percentage); return this.cfiFromLocation(loc); } }, { key: "load", value: function load(locations) { this._locations = JSON.parse(locations); this.total = this._locations.length - 1; return this._locations; } }, { key: "save", value: function save(json) { return JSON.stringify(this._locations); } }, { key: "getCurrent", value: function getCurrent(json) { 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("changed", { percentage: this.percentageFromLocation(loc) }); } }, { key: "length", value: function length() { return this._locations.length; } }, { key: "currentLocation", get: function get() { return this._current; }, set: function set(curr) { this.setCurrent(curr); } }]); return Locations; }(); (0, _eventEmitter2.default)(Locations.prototype); exports.default = Locations; module.exports = exports["default"];