UNPKG

epubjs

Version:
988 lines (794 loc) 24.3 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 _eventEmitter = require("event-emitter"); var _eventEmitter2 = _interopRequireDefault(_eventEmitter); var _core = require("../../utils/core"); var _mapping = require("../../mapping"); var _mapping2 = _interopRequireDefault(_mapping); var _queue = require("../../utils/queue"); var _queue2 = _interopRequireDefault(_queue); var _stage = require("../helpers/stage"); var _stage2 = _interopRequireDefault(_stage); var _views = require("../helpers/views"); var _views2 = _interopRequireDefault(_views); var _constants = require("../../utils/constants"); 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"];