/** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2019 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * Javascript code in this page */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isDestHashesEqual = isDestHashesEqual; exports.isDestArraysEqual = isDestArraysEqual; exports.PDFHistory = void 0; var _ui_utils = require("./ui_utils"); function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var HASH_CHANGE_TIMEOUT = 1000; var POSITION_UPDATED_THRESHOLD = 50; var UPDATE_VIEWAREA_TIMEOUT = 1000; function getCurrentHash() { return document.location.hash; } function parseCurrentHash(linkService) { var hash = unescape(getCurrentHash()).substring(1); var params = (0, _ui_utils.parseQueryString)(hash); var page = params.page | 0; if (!(Number.isInteger(page) && page > 0 && page <= linkService.pagesCount)) { page = null; } return { hash: hash, page: page, rotation: linkService.rotation }; } var PDFHistory = /*#__PURE__*/ function () { function PDFHistory(_ref) { var _this = this; var linkService = _ref.linkService, eventBus = _ref.eventBus; _classCallCheck(this, PDFHistory); this.linkService = linkService; this.eventBus = eventBus || (0, _ui_utils.getGlobalEventBus)(); this.initialized = false; this.initialBookmark = null; this.initialRotation = null; this._boundEvents = Object.create(null); this._isViewerInPresentationMode = false; this._isPagesLoaded = false; this.eventBus.on('presentationmodechanged', function (evt) { _this._isViewerInPresentationMode = evt.active || evt.switchInProgress; }); this.eventBus.on('pagesloaded', function (evt) { _this._isPagesLoaded = !!evt.pagesCount; }); } _createClass(PDFHistory, [{ key: "initialize", value: function initialize(_ref2) { var fingerprint = _ref2.fingerprint, _ref2$resetHistory = _ref2.resetHistory, resetHistory = _ref2$resetHistory === void 0 ? false : _ref2$resetHistory, _ref2$updateUrl = _ref2.updateUrl, updateUrl = _ref2$updateUrl === void 0 ? false : _ref2$updateUrl; if (!fingerprint || typeof fingerprint !== 'string') { console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.'); return; } var reInitialized = this.initialized && this.fingerprint !== fingerprint; this.fingerprint = fingerprint; this._updateUrl = updateUrl === true; if (!this.initialized) { this._bindEvents(); } var state = window.history.state; this.initialized = true; this.initialBookmark = null; this.initialRotation = null; this._popStateInProgress = false; this._blockHashChange = 0; this._currentHash = getCurrentHash(); this._numPositionUpdates = 0; this._uid = this._maxUid = 0; this._destination = null; this._position = null; if (!this._isValidState(state, true) || resetHistory) { var _parseCurrentHash = parseCurrentHash(this.linkService), hash = _parseCurrentHash.hash, page = _parseCurrentHash.page, rotation = _parseCurrentHash.rotation; if (!hash || reInitialized || resetHistory) { this._pushOrReplaceState(null, true); return; } this._pushOrReplaceState({ hash: hash, page: page, rotation: rotation }, true); return; } var destination = state.destination; this._updateInternalState(destination, state.uid, true); if (this._uid > this._maxUid) { this._maxUid = this._uid; } if (destination.rotation !== undefined) { this.initialRotation = destination.rotation; } if (destination.dest) { this.initialBookmark = JSON.stringify(destination.dest); this._destination.page = null; } else if (destination.hash) { this.initialBookmark = destination.hash; } else if (destination.page) { this.initialBookmark = "page=".concat(destination.page); } } }, { key: "push", value: function push(_ref3) { var _this2 = this; var _ref3$namedDest = _ref3.namedDest, namedDest = _ref3$namedDest === void 0 ? null : _ref3$namedDest, explicitDest = _ref3.explicitDest, pageNumber = _ref3.pageNumber; if (!this.initialized) { return; } if (namedDest && typeof namedDest !== 'string') { console.error('PDFHistory.push: ' + "\"".concat(namedDest, "\" is not a valid namedDest parameter.")); return; } else if (!Array.isArray(explicitDest)) { console.error('PDFHistory.push: ' + "\"".concat(explicitDest, "\" is not a valid explicitDest parameter.")); return; } else if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.linkService.pagesCount)) { if (pageNumber !== null || this._destination) { console.error('PDFHistory.push: ' + "\"".concat(pageNumber, "\" is not a valid pageNumber parameter.")); return; } } var hash = namedDest || JSON.stringify(explicitDest); if (!hash) { return; } var forceReplace = false; if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) { if (this._destination.page) { return; } forceReplace = true; } if (this._popStateInProgress && !forceReplace) { return; } this._pushOrReplaceState({ dest: explicitDest, hash: hash, page: pageNumber, rotation: this.linkService.rotation }, forceReplace); if (!this._popStateInProgress) { this._popStateInProgress = true; Promise.resolve().then(function () { _this2._popStateInProgress = false; }); } } }, { key: "pushCurrentPosition", value: function pushCurrentPosition() { if (!this.initialized || this._popStateInProgress) { return; } this._tryPushCurrentPosition(); } }, { key: "back", value: function back() { if (!this.initialized || this._popStateInProgress) { return; } var state = window.history.state; if (this._isValidState(state) && state.uid > 0) { window.history.back(); } } }, { key: "forward", value: function forward() { if (!this.initialized || this._popStateInProgress) { return; } var state = window.history.state; if (this._isValidState(state) && state.uid < this._maxUid) { window.history.forward(); } } }, { key: "_pushOrReplaceState", value: function _pushOrReplaceState(destination) { var forceReplace = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var shouldReplace = forceReplace || !this._destination; var newState = { fingerprint: this.fingerprint, uid: shouldReplace ? this._uid : this._uid + 1, destination: destination }; this._updateInternalState(destination, newState.uid); var newUrl; if (this._updateUrl && destination && destination.hash) { var baseUrl = document.location.href.split('#')[0]; if (!baseUrl.startsWith('file://')) { newUrl = "".concat(baseUrl, "#").concat(destination.hash); } } if (shouldReplace) { if (newUrl) { window.history.replaceState(newState, '', newUrl); } else { window.history.replaceState(newState, ''); } } else { this._maxUid = this._uid; if (newUrl) { window.history.pushState(newState, '', newUrl); } else { window.history.pushState(newState, ''); } } } }, { key: "_tryPushCurrentPosition", value: function _tryPushCurrentPosition() { var temporary = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; if (!this._position) { return; } var position = this._position; if (temporary) { position = Object.assign(Object.create(null), this._position); position.temporary = true; } if (!this._destination) { this._pushOrReplaceState(position); return; } if (this._destination.temporary) { this._pushOrReplaceState(position, true); return; } if (this._destination.hash === position.hash) { return; } if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) { return; } var forceReplace = false; if (this._destination.page >= position.first && this._destination.page <= position.page) { if (this._destination.dest || !this._destination.first) { return; } forceReplace = true; } this._pushOrReplaceState(position, forceReplace); } }, { key: "_isValidState", value: function _isValidState(state) { var checkReload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (!state) { return false; } if (state.fingerprint !== this.fingerprint) { if (checkReload) { if (typeof state.fingerprint !== 'string' || state.fingerprint.length !== this.fingerprint.length) { return false; } var _performance$getEntri = performance.getEntriesByType('navigation'), _performance$getEntri2 = _slicedToArray(_performance$getEntri, 1), perfEntry = _performance$getEntri2[0]; if (!perfEntry || perfEntry.type !== 'reload') { return false; } } else { return false; } } if (!Number.isInteger(state.uid) || state.uid < 0) { return false; } if (state.destination === null || _typeof(state.destination) !== 'object') { return false; } return true; } }, { key: "_updateInternalState", value: function _updateInternalState(destination, uid) { var removeTemporary = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (this._updateViewareaTimeout) { clearTimeout(this._updateViewareaTimeout); this._updateViewareaTimeout = null; } if (removeTemporary && destination && destination.temporary) { delete destination.temporary; } this._destination = destination; this._uid = uid; this._numPositionUpdates = 0; } }, { key: "_updateViewarea", value: function _updateViewarea(_ref4) { var _this3 = this; var location = _ref4.location; if (this._updateViewareaTimeout) { clearTimeout(this._updateViewareaTimeout); this._updateViewareaTimeout = null; } this._position = { hash: this._isViewerInPresentationMode ? "page=".concat(location.pageNumber) : location.pdfOpenParams.substring(1), page: this.linkService.page, first: location.pageNumber, rotation: location.rotation }; if (this._popStateInProgress) { return; } if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) { this._numPositionUpdates++; } if (UPDATE_VIEWAREA_TIMEOUT > 0) { this._updateViewareaTimeout = setTimeout(function () { if (!_this3._popStateInProgress) { _this3._tryPushCurrentPosition(true); } _this3._updateViewareaTimeout = null; }, UPDATE_VIEWAREA_TIMEOUT); } } }, { key: "_popState", value: function _popState(_ref5) { var _this4 = this; var state = _ref5.state; var newHash = getCurrentHash(), hashChanged = this._currentHash !== newHash; this._currentHash = newHash; if (!state || false) { this._uid++; var _parseCurrentHash2 = parseCurrentHash(this.linkService), hash = _parseCurrentHash2.hash, page = _parseCurrentHash2.page, rotation = _parseCurrentHash2.rotation; this._pushOrReplaceState({ hash: hash, page: page, rotation: rotation }, true); return; } if (!this._isValidState(state)) { return; } this._popStateInProgress = true; if (hashChanged) { this._blockHashChange++; (0, _ui_utils.waitOnEventOrTimeout)({ target: window, name: 'hashchange', delay: HASH_CHANGE_TIMEOUT }).then(function () { _this4._blockHashChange--; }); } var destination = state.destination; this._updateInternalState(destination, state.uid, true); if (this._uid > this._maxUid) { this._maxUid = this._uid; } if ((0, _ui_utils.isValidRotation)(destination.rotation)) { this.linkService.rotation = destination.rotation; } if (destination.dest) { this.linkService.navigateTo(destination.dest); } else if (destination.hash) { this.linkService.setHash(destination.hash); } else if (destination.page) { this.linkService.page = destination.page; } Promise.resolve().then(function () { _this4._popStateInProgress = false; }); } }, { key: "_bindEvents", value: function _bindEvents() { var _this5 = this; var _boundEvents = this._boundEvents, eventBus = this.eventBus; _boundEvents.updateViewarea = this._updateViewarea.bind(this); _boundEvents.popState = this._popState.bind(this); _boundEvents.pageHide = function (evt) { if (!_this5._destination || _this5._destination.temporary) { _this5._tryPushCurrentPosition(); } }; eventBus.on('updateviewarea', _boundEvents.updateViewarea); window.addEventListener('popstate', _boundEvents.popState); window.addEventListener('pagehide', _boundEvents.pageHide); } }, { key: "popStateInProgress", get: function get() { return this.initialized && (this._popStateInProgress || this._blockHashChange > 0); } }]); return PDFHistory; }(); exports.PDFHistory = PDFHistory; function isDestHashesEqual(destHash, pushHash) { if (typeof destHash !== 'string' || typeof pushHash !== 'string') { return false; } if (destHash === pushHash) { return true; } var _parseQueryString = (0, _ui_utils.parseQueryString)(destHash), nameddest = _parseQueryString.nameddest; if (nameddest === pushHash) { return true; } return false; } function isDestArraysEqual(firstDest, secondDest) { function isEntryEqual(first, second) { if (_typeof(first) !== _typeof(second)) { return false; } if (Array.isArray(first) || Array.isArray(second)) { return false; } if (first !== null && _typeof(first) === 'object' && second !== null) { if (Object.keys(first).length !== Object.keys(second).length) { return false; } for (var key in first) { if (!isEntryEqual(first[key], second[key])) { return false; } } return true; } return first === second || Number.isNaN(first) && Number.isNaN(second); } if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) { return false; } if (firstDest.length !== secondDest.length) { return false; } for (var i = 0, ii = firstDest.length; i < ii; i++) { if (!isEntryEqual(firstDest[i], secondDest[i])) { return false; } } return true; }