1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 14:48:08 +02:00

Merge pull request #17925 from timvandermeij/web-history-private-methods

Convert the history code to use proper private methods
This commit is contained in:
Tim van der Meij 2024-04-12 13:12:30 +02:00 committed by GitHub
commit 355432fc71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -102,7 +102,7 @@ class PDFHistory {
this._updateUrl = updateUrl === true;
this._initialized = true;
this._bindEvents();
this.#bindEvents();
const state = window.history.state;
this._popStateInProgress = false;
@ -114,19 +114,19 @@ class PDFHistory {
this._destination = null;
this._position = null;
if (!this._isValidState(state, /* checkReload = */ true) || resetHistory) {
const { hash, page, rotation } = this._parseCurrentHash(
if (!this.#isValidState(state, /* checkReload = */ true) || resetHistory) {
const { hash, page, rotation } = this.#parseCurrentHash(
/* checkNameddest = */ true
);
if (!hash || reInitialized || resetHistory) {
// Ensure that the browser history is reset on PDF document load.
this._pushOrReplaceState(null, /* forceReplace = */ true);
this.#pushOrReplaceState(null, /* forceReplace = */ true);
return;
}
// Ensure that the browser history is initialized correctly when
// the document hash is present on PDF document load.
this._pushOrReplaceState(
this.#pushOrReplaceState(
{ hash, page, rotation },
/* forceReplace = */ true
);
@ -136,7 +136,7 @@ class PDFHistory {
// The browser history contains a valid entry, ensure that the history is
// initialized correctly on PDF document load.
const destination = state.destination;
this._updateInternalState(
this.#updateInternalState(
destination,
state.uid,
/* removeTemporary = */ true
@ -166,10 +166,10 @@ class PDFHistory {
*/
reset() {
if (this._initialized) {
this._pageHide(); // Simulate a 'pagehide' event when resetting.
this.#pageHide(); // Simulate a 'pagehide' event when resetting.
this._initialized = false;
this._unbindEvents();
this.#unbindEvents();
}
if (this._updateViewareaTimeout) {
clearTimeout(this._updateViewareaTimeout);
@ -199,7 +199,7 @@ class PDFHistory {
`"${explicitDest}" is not a valid explicitDest parameter.`
);
return;
} else if (!this._isValidPage(pageNumber)) {
} else if (!this.#isValidPage(pageNumber)) {
// Allow an unset `pageNumber` if and only if the history is still empty;
// please refer to the `this._destination.page = null;` comment above.
if (pageNumber !== null || this._destination) {
@ -238,7 +238,7 @@ class PDFHistory {
return;
}
this._pushOrReplaceState(
this.#pushOrReplaceState(
{
dest: explicitDest,
hash,
@ -269,7 +269,7 @@ class PDFHistory {
if (!this._initialized) {
return;
}
if (!this._isValidPage(pageNumber)) {
if (!this.#isValidPage(pageNumber)) {
console.error(
`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`
);
@ -285,8 +285,8 @@ class PDFHistory {
return;
}
this._pushOrReplaceState({
// Simulate an internal destination, for `this._tryPushCurrentPosition`:
this.#pushOrReplaceState({
// Simulate an internal destination, for `this.#tryPushCurrentPosition`:
dest: null,
hash: `page=${pageNumber}`,
page: pageNumber,
@ -312,7 +312,7 @@ class PDFHistory {
if (!this._initialized || this._popStateInProgress) {
return;
}
this._tryPushCurrentPosition();
this.#tryPushCurrentPosition();
}
/**
@ -324,7 +324,7 @@ class PDFHistory {
return;
}
const state = window.history.state;
if (this._isValidState(state) && state.uid > 0) {
if (this.#isValidState(state) && state.uid > 0) {
window.history.back();
}
}
@ -338,7 +338,7 @@ class PDFHistory {
return;
}
const state = window.history.state;
if (this._isValidState(state) && state.uid < this._maxUid) {
if (this.#isValidState(state) && state.uid < this._maxUid) {
window.history.forward();
}
}
@ -362,10 +362,7 @@ class PDFHistory {
return this._initialized ? this._initialRotation : null;
}
/**
* @private
*/
_pushOrReplaceState(destination, forceReplace = false) {
#pushOrReplaceState(destination, forceReplace = false) {
const shouldReplace = forceReplace || !this._destination;
const newState = {
fingerprint: this._fingerprint,
@ -381,7 +378,7 @@ class PDFHistory {
// history.state.chromecomState is managed by chromecom.js.
newState.chromecomState = window.history.state.chromecomState;
}
this._updateInternalState(destination, newState.uid);
this.#updateInternalState(destination, newState.uid);
let newUrl;
if (this._updateUrl && destination?.hash) {
@ -407,10 +404,7 @@ class PDFHistory {
}
}
/**
* @private
*/
_tryPushCurrentPosition(temporary = false) {
#tryPushCurrentPosition(temporary = false) {
if (!this._position) {
return;
}
@ -421,12 +415,12 @@ class PDFHistory {
}
if (!this._destination) {
this._pushOrReplaceState(position);
this.#pushOrReplaceState(position);
return;
}
if (this._destination.temporary) {
// Always replace a previous *temporary* position.
this._pushOrReplaceState(position, /* forceReplace = */ true);
this.#pushOrReplaceState(position, /* forceReplace = */ true);
return;
}
if (this._destination.hash === position.hash) {
@ -460,22 +454,16 @@ class PDFHistory {
// To avoid "flooding" the browser history, replace the current entry.
forceReplace = true;
}
this._pushOrReplaceState(position, forceReplace);
this.#pushOrReplaceState(position, forceReplace);
}
/**
* @private
*/
_isValidPage(val) {
#isValidPage(val) {
return (
Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount
);
}
/**
* @private
*/
_isValidState(state, checkReload = false) {
#isValidState(state, checkReload = false) {
if (!state) {
return false;
}
@ -508,10 +496,7 @@ class PDFHistory {
return true;
}
/**
* @private
*/
_updateInternalState(destination, uid, removeTemporary = false) {
#updateInternalState(destination, uid, removeTemporary = false) {
if (this._updateViewareaTimeout) {
// When updating `this._destination`, make sure that we always wait for
// the next 'updateviewarea' event before (potentially) attempting to
@ -531,26 +516,20 @@ class PDFHistory {
this._numPositionUpdates = 0;
}
/**
* @private
*/
_parseCurrentHash(checkNameddest = false) {
#parseCurrentHash(checkNameddest = false) {
const hash = unescape(getCurrentHash()).substring(1);
const params = parseQueryString(hash);
const nameddest = params.get("nameddest") || "";
let page = params.get("page") | 0;
if (!this._isValidPage(page) || (checkNameddest && nameddest.length > 0)) {
if (!this.#isValidPage(page) || (checkNameddest && nameddest.length > 0)) {
page = null;
}
return { hash, page, rotation: this.linkService.rotation };
}
/**
* @private
*/
_updateViewarea({ location }) {
#updateViewarea({ location }) {
if (this._updateViewareaTimeout) {
clearTimeout(this._updateViewareaTimeout);
this._updateViewareaTimeout = null;
@ -575,9 +554,9 @@ class PDFHistory {
) {
// If the current destination was set through the user changing the hash
// of the document, we will usually not try to push the current position
// to the browser history; see `this._tryPushCurrentPosition()`.
// to the browser history; see `this.#tryPushCurrentPosition()`.
//
// To prevent `this._tryPushCurrentPosition()` from effectively being
// To prevent `this.#tryPushCurrentPosition()` from effectively being
// reduced to a no-op in this case, we will assume that the position
// *did* in fact change if the 'updateviewarea' event was dispatched
// more than `POSITION_UPDATED_THRESHOLD` times.
@ -602,17 +581,14 @@ class PDFHistory {
// the viewer has been idle for `UPDATE_VIEWAREA_TIMEOUT` milliseconds.
this._updateViewareaTimeout = setTimeout(() => {
if (!this._popStateInProgress) {
this._tryPushCurrentPosition(/* temporary = */ true);
this.#tryPushCurrentPosition(/* temporary = */ true);
}
this._updateViewareaTimeout = null;
}, UPDATE_VIEWAREA_TIMEOUT);
}
}
/**
* @private
*/
_popState({ state }) {
#popState({ state }) {
const newHash = getCurrentHash(),
hashChanged = this._currentHash !== newHash;
this._currentHash = newHash;
@ -621,20 +597,20 @@ class PDFHistory {
(typeof PDFJSDev !== "undefined" &&
PDFJSDev.test("CHROME") &&
state?.chromecomState &&
!this._isValidState(state)) ||
!this.#isValidState(state)) ||
!state
) {
// This case corresponds to the user changing the hash of the document.
this._uid++;
const { hash, page, rotation } = this._parseCurrentHash();
this._pushOrReplaceState(
const { hash, page, rotation } = this.#parseCurrentHash();
this.#pushOrReplaceState(
{ hash, page, rotation },
/* forceReplace = */ true
);
return;
}
if (!this._isValidState(state)) {
if (!this.#isValidState(state)) {
// This should only occur in viewers with support for opening more than
// one PDF document, e.g. the GENERIC viewer.
return;
@ -666,7 +642,7 @@ class PDFHistory {
// Navigate to the new destination.
const destination = state.destination;
this._updateInternalState(
this.#updateInternalState(
destination,
state.uid,
/* removeTemporary = */ true
@ -691,31 +667,25 @@ class PDFHistory {
});
}
/**
* @private
*/
_pageHide() {
#pageHide() {
// Attempt to push the `this._position` into the browser history when
// navigating away from the document. This is *only* done if the history
// is empty/temporary, since otherwise an existing browser history entry
// will end up being overwritten (given that new entries cannot be pushed
// into the browser history when the 'unload' event has already fired).
if (!this._destination || this._destination.temporary) {
this._tryPushCurrentPosition();
this.#tryPushCurrentPosition();
}
}
/**
* @private
*/
_bindEvents() {
#bindEvents() {
if (this._boundEvents) {
return; // The event listeners were already added.
}
this._boundEvents = {
updateViewarea: this._updateViewarea.bind(this),
popState: this._popState.bind(this),
pageHide: this._pageHide.bind(this),
updateViewarea: this.#updateViewarea.bind(this),
popState: this.#popState.bind(this),
pageHide: this.#pageHide.bind(this),
};
this.eventBus._on("updateviewarea", this._boundEvents.updateViewarea);
@ -723,10 +693,7 @@ class PDFHistory {
window.addEventListener("pagehide", this._boundEvents.pageHide);
}
/**
* @private
*/
_unbindEvents() {
#unbindEvents() {
if (!this._boundEvents) {
return; // The event listeners were already removed.
}