diff --git a/extensions/chromium/preferences_schema.json b/extensions/chromium/preferences_schema.json index 019577cfd..eb264dee2 100644 --- a/extensions/chromium/preferences_schema.json +++ b/extensions/chromium/preferences_schema.json @@ -147,6 +147,10 @@ "type": "boolean", "default": false }, + "historyUpdateUrl": { + "type": "boolean", + "default": false + }, "enablePrintAutoRotate": { "title": "Automatically rotate printed pages", "description": "When enabled, pages whose orientation differ from the first page are rotated when printed.", diff --git a/web/app.js b/web/app.js index 420125a87..cdff6173a 100644 --- a/web/app.js +++ b/web/app.js @@ -903,8 +903,11 @@ let PDFViewerApplication = { if (!AppOptions.get('disableHistory') && !this.isViewerEmbedded) { // The browsing history is only enabled when the viewer is standalone, // i.e. not when it is embedded in a web page. - let resetHistory = !AppOptions.get('showPreviousViewOnLoad'); - this.pdfHistory.initialize(pdfDocument.fingerprint, resetHistory); + this.pdfHistory.initialize({ + fingerprint: pdfDocument.fingerprint, + resetHistory: !AppOptions.get('showPreviousViewOnLoad'), + updateUrl: AppOptions.get('historyUpdateUrl'), + }); if (this.pdfHistory.initialBookmark) { this.initialBookmark = this.pdfHistory.initialBookmark; diff --git a/web/app_options.js b/web/app_options.js index bbd8e6c82..7e9864623 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -91,6 +91,11 @@ const defaultOptions = { value: 0, kind: OptionKind.VIEWER, }, + historyUpdateUrl: { + /** @type {boolean} */ + value: false, + kind: OptionKind.VIEWER, + }, imageResourcesPath: { /** @type {string} */ value: './images/', diff --git a/web/default_preferences.json b/web/default_preferences.json index f41aa1487..702b5d5a9 100644 --- a/web/default_preferences.json +++ b/web/default_preferences.json @@ -19,6 +19,7 @@ "disableOpenActionDestination": true, "disablePageMode": false, "disablePageLabels": false, + "historyUpdateUrl": false, "scrollModeOnLoad": 0, "spreadModeOnLoad": 0 } diff --git a/web/interfaces.js b/web/interfaces.js index a7f58a2c8..f644f113e 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -86,10 +86,9 @@ class IPDFLinkService { */ class IPDFHistory { /** - * @param {string} fingerprint - The PDF document's unique fingerprint. - * @param {boolean} resetHistory - (optional) Reset the browsing history. + * @param {Object} params */ - initialize(fingerprint, resetHistory = false) {} + initialize({ fingerprint, resetHistory = false, updateUrl = false, }) {} /** * @param {Object} params diff --git a/web/pdf_history.js b/web/pdf_history.js index f33a9f2f2..a336ff07a 100644 --- a/web/pdf_history.js +++ b/web/pdf_history.js @@ -30,6 +30,14 @@ const UPDATE_VIEWAREA_TIMEOUT = 1000; // milliseconds * @property {EventBus} eventBus - The application event bus. */ +/** + * @typedef {Object} InitializeParameters + * @property {string} fingerprint - The PDF document's unique fingerprint. + * @property {boolean} resetHistory - (optional) Reset the browsing history. + * @property {boolean} updateUrl - (optional) Attempt to update the document + * URL, with the current hash, when pushing/replacing browser history entries. + */ + /** * @typedef {Object} PushParameters * @property {string} namedDest - (optional) The named destination. If absent, @@ -82,10 +90,9 @@ class PDFHistory { /** * Initialize the history for the PDF document, using either the current * browser history entry or the document hash, whichever is present. - * @param {string} fingerprint - The PDF document's unique fingerprint. - * @param {boolean} resetHistory - (optional) Reset the browsing history. + * @param {InitializeParameters} params */ - initialize(fingerprint, resetHistory = false) { + initialize({ fingerprint, resetHistory = false, updateUrl = false, }) { if (!fingerprint || typeof fingerprint !== 'string') { console.error( 'PDFHistory.initialize: The "fingerprint" must be a non-empty string.'); @@ -93,6 +100,7 @@ class PDFHistory { } let reInitialized = this.initialized && this.fingerprint !== fingerprint; this.fingerprint = fingerprint; + this._updateUrl = (updateUrl === true); if (!this.initialized) { this._bindEvents(); @@ -290,11 +298,18 @@ class PDFHistory { } this._updateInternalState(destination, newState.uid); + let newUrl; + if (this._updateUrl && destination && destination.hash) { + const baseUrl = document.location.href.split('#')[0]; + if (!baseUrl.startsWith('file://')) { // Prevent errors in Firefox. + newUrl = `${baseUrl}#${destination.hash}`; + } + } if (shouldReplace) { - window.history.replaceState(newState, ''); + window.history.replaceState(newState, '', newUrl); } else { this._maxUid = this._uid; - window.history.pushState(newState, ''); + window.history.pushState(newState, '', newUrl); } if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME') &&