diff --git a/web/genericcom.js b/web/genericcom.js index df616133a..7ba212447 100644 --- a/web/genericcom.js +++ b/web/genericcom.js @@ -21,8 +21,7 @@ import { GenericScripting } from "./generic_scripting.js"; if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("GENERIC")) { throw new Error( - 'Module "pdfjs-web/genericcom" shall not be used outside ' + - "GENERIC build." + 'Module "pdfjs-web/genericcom" shall not be used outside GENERIC build.' ); } diff --git a/web/preferences.js b/web/preferences.js index ea1ffd483..d47362bd8 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -21,29 +21,36 @@ import { AppOptions, OptionKind } from "./app_options.js"; * or every time the viewer is loaded. */ class BasePreferences { + #defaults = Object.freeze( + typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") + ? AppOptions.getAll(OptionKind.PREFERENCE) + : PDFJSDev.eval("DEFAULT_PREFERENCES") + ); + + #prefs = Object.create(null); + + #initializedPromise = null; + constructor() { if (this.constructor === BasePreferences) { throw new Error("Cannot initialize BasePreferences."); } - Object.defineProperty(this, "defaults", { - value: Object.freeze( - typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") - ? AppOptions.getAll(OptionKind.PREFERENCE) - : PDFJSDev.eval("DEFAULT_PREFERENCES") - ), - writable: false, - enumerable: true, - configurable: false, - }); - this.prefs = Object.create(null); - this._initializedPromise = this._readFromStorage(this.defaults).then( + if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("CHROME")) { + Object.defineProperty(this, "defaults", { + get() { + return this.#defaults; + }, + }); + } + + this.#initializedPromise = this._readFromStorage(this.#defaults).then( prefs => { - for (const name in this.defaults) { + for (const name in this.#defaults) { const prefValue = prefs?.[name]; // Ignore preferences whose types don't match the default values. - if (typeof prefValue === typeof this.defaults[name]) { - this.prefs[name] = prefValue; + if (typeof prefValue === typeof this.#defaults[name]) { + this.#prefs[name] = prefValue; } } } @@ -76,9 +83,15 @@ class BasePreferences { * have been reset. */ async reset() { - await this._initializedPromise; - this.prefs = Object.create(null); - return this._writeToStorage(this.defaults); + await this.#initializedPromise; + const prefs = this.#prefs; + + this.#prefs = Object.create(null); + return this._writeToStorage(this.#defaults).catch(reason => { + // Revert all preference values, since writing to storage failed. + this.#prefs = prefs; + throw reason; + }); } /** @@ -89,16 +102,17 @@ class BasePreferences { * provided that the preference exists and the types match. */ async set(name, value) { - await this._initializedPromise; - const defaultValue = this.defaults[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name], + prefs = this.#prefs; if (defaultValue === undefined) { throw new Error(`Set preference: "${name}" is undefined.`); } else if (value === undefined) { throw new Error("Set preference: no value is specified."); } - const valueType = typeof value; - const defaultType = typeof defaultValue; + const valueType = typeof value, + defaultType = typeof defaultValue; if (valueType !== defaultType) { if (valueType === "number" && defaultType === "string") { @@ -113,8 +127,13 @@ class BasePreferences { throw new Error(`Set preference: "${value}" must be an integer.`); } } - this.prefs[name] = value; - return this._writeToStorage(this.prefs); + + this.#prefs[name] = value; + return this._writeToStorage(this.#prefs).catch(reason => { + // Revert all preference values, since writing to storage failed. + this.#prefs = prefs; + throw reason; + }); } /** @@ -124,14 +143,13 @@ class BasePreferences { * containing the value of the preference. */ async get(name) { - await this._initializedPromise; - const defaultValue = this.defaults[name], - prefValue = this.prefs[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name]; if (defaultValue === undefined) { throw new Error(`Get preference: "${name}" is undefined.`); } - return prefValue !== undefined ? prefValue : defaultValue; + return this.#prefs[name] ?? defaultValue; } /** @@ -140,12 +158,11 @@ class BasePreferences { * the values of all preferences. */ async getAll() { - await this._initializedPromise; + await this.#initializedPromise; const obj = Object.create(null); - for (const name in this.defaults) { - const prefValue = this.prefs[name]; - obj[name] = prefValue !== undefined ? prefValue : this.defaults[name]; + for (const name in this.#defaults) { + obj[name] = this.#prefs[name] ?? this.#defaults[name]; } return obj; }