Re-factor the OverlayManager
class to use a WeakMap
internally
This way we're able to store the `<dialog>` elements directly, which removes the need to use manually specified name-strings thus simplifying both the `OverlayManager` itself and its calling code.
This commit is contained in:
parent
f0aa08b464
commit
923bd52cdb
@ -162,13 +162,11 @@ function requestAccessToLocalFile(fileUrl, overlayManager, callback) {
|
|||||||
reloadIfRuntimeIsUnavailable();
|
reloadIfRuntimeIsUnavailable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!chromeFileAccessOverlayPromise) {
|
chromeFileAccessOverlayPromise ||= overlayManager.register(
|
||||||
chromeFileAccessOverlayPromise = overlayManager.register(
|
dialog,
|
||||||
"chromeFileAccessDialog",
|
/* canForceClose = */ true
|
||||||
dialog,
|
);
|
||||||
/* canForceClose = */ true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
chromeFileAccessOverlayPromise.then(function () {
|
chromeFileAccessOverlayPromise.then(function () {
|
||||||
const iconPath = chrome.runtime.getManifest().icons[48];
|
const iconPath = chrome.runtime.getManifest().icons[48];
|
||||||
document.getElementById("chrome-pdfjs-logo-bg").style.backgroundImage =
|
document.getElementById("chrome-pdfjs-logo-bg").style.backgroundImage =
|
||||||
@ -227,11 +225,11 @@ function requestAccessToLocalFile(fileUrl, overlayManager, callback) {
|
|||||||
originalUrl = "file:///fakepath/to/" + encodeURIComponent(file.name);
|
originalUrl = "file:///fakepath/to/" + encodeURIComponent(file.name);
|
||||||
}
|
}
|
||||||
callback(URL.createObjectURL(file), file.size, originalUrl);
|
callback(URL.createObjectURL(file), file.size, originalUrl);
|
||||||
overlayManager.close("chromeFileAccessOverlay");
|
overlayManager.close(dialog);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
overlayManager.open("chromeFileAccessDialog");
|
overlayManager.open(dialog);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class OverlayManager {
|
class OverlayManager {
|
||||||
#overlays = Object.create(null);
|
#overlays = new WeakMap();
|
||||||
|
|
||||||
#active = null;
|
#active = null;
|
||||||
|
|
||||||
@ -23,20 +23,19 @@ class OverlayManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - The name of the overlay that is registered.
|
|
||||||
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @param {boolean} [canForceClose] - Indicates if opening the overlay closes
|
* @param {boolean} [canForceClose] - Indicates if opening the overlay closes
|
||||||
* an active overlay. The default is `false`.
|
* an active overlay. The default is `false`.
|
||||||
* @returns {Promise} A promise that is resolved when the overlay has been
|
* @returns {Promise} A promise that is resolved when the overlay has been
|
||||||
* registered.
|
* registered.
|
||||||
*/
|
*/
|
||||||
async register(name, dialog, canForceClose = false) {
|
async register(dialog, canForceClose = false) {
|
||||||
if (!name || !dialog) {
|
if (typeof dialog !== "object") {
|
||||||
throw new Error("Not enough parameters.");
|
throw new Error("Not enough parameters.");
|
||||||
} else if (this.#overlays[name]) {
|
} else if (this.#overlays.has(dialog)) {
|
||||||
throw new Error("The overlay is already registered.");
|
throw new Error("The overlay is already registered.");
|
||||||
}
|
}
|
||||||
this.#overlays[name] = { dialog, canForceClose };
|
this.#overlays.set(dialog, { canForceClose });
|
||||||
|
|
||||||
dialog.addEventListener("cancel", evt => {
|
dialog.addEventListener("cancel", evt => {
|
||||||
this.#active = null;
|
this.#active = null;
|
||||||
@ -44,54 +43,54 @@ class OverlayManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - The name of the overlay that is unregistered.
|
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @returns {Promise} A promise that is resolved when the overlay has been
|
* @returns {Promise} A promise that is resolved when the overlay has been
|
||||||
* unregistered.
|
* unregistered.
|
||||||
*/
|
*/
|
||||||
async unregister(name) {
|
async unregister(dialog) {
|
||||||
if (!this.#overlays[name]) {
|
if (!this.#overlays.has(dialog)) {
|
||||||
throw new Error("The overlay does not exist.");
|
throw new Error("The overlay does not exist.");
|
||||||
} else if (this.#active === name) {
|
} else if (this.#active === dialog) {
|
||||||
throw new Error("The overlay cannot be removed while it is active.");
|
throw new Error("The overlay cannot be removed while it is active.");
|
||||||
}
|
}
|
||||||
delete this.#overlays[name];
|
this.#overlays.delete(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - The name of the overlay that should be opened.
|
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @returns {Promise} A promise that is resolved when the overlay has been
|
* @returns {Promise} A promise that is resolved when the overlay has been
|
||||||
* opened.
|
* opened.
|
||||||
*/
|
*/
|
||||||
async open(name) {
|
async open(dialog) {
|
||||||
if (!this.#overlays[name]) {
|
if (!this.#overlays.has(dialog)) {
|
||||||
throw new Error("The overlay does not exist.");
|
throw new Error("The overlay does not exist.");
|
||||||
} else if (this.#active) {
|
} else if (this.#active) {
|
||||||
if (this.#active === name) {
|
if (this.#active === dialog) {
|
||||||
throw new Error("The overlay is already active.");
|
throw new Error("The overlay is already active.");
|
||||||
} else if (this.#overlays[name].canForceClose) {
|
} else if (this.#overlays.get(dialog).canForceClose) {
|
||||||
await this.close();
|
await this.close();
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Another overlay is currently active.");
|
throw new Error("Another overlay is currently active.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#active = name;
|
this.#active = dialog;
|
||||||
this.#overlays[this.#active].dialog.showModal();
|
dialog.showModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - The name of the overlay that should be closed.
|
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @returns {Promise} A promise that is resolved when the overlay has been
|
* @returns {Promise} A promise that is resolved when the overlay has been
|
||||||
* closed.
|
* closed.
|
||||||
*/
|
*/
|
||||||
async close(name = this.#active) {
|
async close(dialog = this.#active) {
|
||||||
if (!this.#overlays[name]) {
|
if (!this.#overlays.has(dialog)) {
|
||||||
throw new Error("The overlay does not exist.");
|
throw new Error("The overlay does not exist.");
|
||||||
} else if (!this.#active) {
|
} else if (!this.#active) {
|
||||||
throw new Error("The overlay is currently not active.");
|
throw new Error("The overlay is currently not active.");
|
||||||
} else if (this.#active !== name) {
|
} else if (this.#active !== dialog) {
|
||||||
throw new Error("Another overlay is currently active.");
|
throw new Error("Another overlay is currently active.");
|
||||||
}
|
}
|
||||||
this.#overlays[this.#active].dialog.close();
|
dialog.close();
|
||||||
this.#active = null;
|
this.#active = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import { PasswordResponses } from "pdfjs-lib";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} PasswordPromptOptions
|
* @typedef {Object} PasswordPromptOptions
|
||||||
* @property {string} dialogName - Name/identifier for the dialog.
|
|
||||||
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @property {HTMLParagraphElement} label - Label containing instructions for
|
* @property {HTMLParagraphElement} label - Label containing instructions for
|
||||||
* entering the password.
|
* entering the password.
|
||||||
@ -41,7 +40,6 @@ class PasswordPrompt {
|
|||||||
* an <iframe> or an <object>. The default value is `false`.
|
* an <iframe> or an <object>. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
constructor(options, overlayManager, l10n, isViewerEmbedded = false) {
|
constructor(options, overlayManager, l10n, isViewerEmbedded = false) {
|
||||||
this.dialogName = options.dialogName;
|
|
||||||
this.dialog = options.dialog;
|
this.dialog = options.dialog;
|
||||||
this.label = options.label;
|
this.label = options.label;
|
||||||
this.input = options.input;
|
this.input = options.input;
|
||||||
@ -60,17 +58,13 @@ class PasswordPrompt {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.overlayManager.register(
|
this.overlayManager.register(this.dialog, /* canForceClose = */ true);
|
||||||
this.dialogName,
|
|
||||||
this.dialog,
|
|
||||||
/* canForceClose = */ true
|
|
||||||
);
|
|
||||||
|
|
||||||
this.dialog.addEventListener("close", this.#cancel.bind(this));
|
this.dialog.addEventListener("close", this.#cancel.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
async open() {
|
async open() {
|
||||||
await this.overlayManager.open(this.dialogName);
|
await this.overlayManager.open(this.dialog);
|
||||||
|
|
||||||
const passwordIncorrect =
|
const passwordIncorrect =
|
||||||
this.#reason === PasswordResponses.INCORRECT_PASSWORD;
|
this.#reason === PasswordResponses.INCORRECT_PASSWORD;
|
||||||
@ -84,8 +78,8 @@ class PasswordPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async close() {
|
async close() {
|
||||||
if (this.overlayManager.active === this.dialogName) {
|
if (this.overlayManager.active === this.dialog) {
|
||||||
this.overlayManager.close(this.dialogName);
|
this.overlayManager.close(this.dialog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ function getPageName(size, isPortrait, pageNames) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} PDFDocumentPropertiesOptions
|
* @typedef {Object} PDFDocumentPropertiesOptions
|
||||||
* @property {string} dialogName - Name/identifier for the dialog.
|
|
||||||
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||||
* @property {Object} fields - Names and elements of the overlay's fields.
|
* @property {Object} fields - Names and elements of the overlay's fields.
|
||||||
* @property {HTMLButtonElement} closeButton - Button for closing the overlay.
|
* @property {HTMLButtonElement} closeButton - Button for closing the overlay.
|
||||||
@ -60,13 +59,7 @@ class PDFDocumentProperties {
|
|||||||
* @param {EventBus} eventBus - The application event bus.
|
* @param {EventBus} eventBus - The application event bus.
|
||||||
* @param {IL10n} l10n - Localization service.
|
* @param {IL10n} l10n - Localization service.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor({ dialog, fields, closeButton }, overlayManager, eventBus, l10n) {
|
||||||
{ dialogName, dialog, fields, closeButton },
|
|
||||||
overlayManager,
|
|
||||||
eventBus,
|
|
||||||
l10n
|
|
||||||
) {
|
|
||||||
this.dialogName = dialogName;
|
|
||||||
this.dialog = dialog;
|
this.dialog = dialog;
|
||||||
this.fields = fields;
|
this.fields = fields;
|
||||||
this.overlayManager = overlayManager;
|
this.overlayManager = overlayManager;
|
||||||
@ -76,7 +69,7 @@ class PDFDocumentProperties {
|
|||||||
// Bind the event listener for the Close button.
|
// Bind the event listener for the Close button.
|
||||||
closeButton.addEventListener("click", this.close.bind(this));
|
closeButton.addEventListener("click", this.close.bind(this));
|
||||||
|
|
||||||
this.overlayManager.register(this.dialogName, this.dialog);
|
this.overlayManager.register(this.dialog);
|
||||||
|
|
||||||
eventBus._on("pagechanging", evt => {
|
eventBus._on("pagechanging", evt => {
|
||||||
this._currentPageNumber = evt.pageNumber;
|
this._currentPageNumber = evt.pageNumber;
|
||||||
@ -96,7 +89,7 @@ class PDFDocumentProperties {
|
|||||||
*/
|
*/
|
||||||
async open() {
|
async open() {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.overlayManager.open(this.dialogName),
|
this.overlayManager.open(this.dialog),
|
||||||
this._dataAvailableCapability.promise,
|
this._dataAvailableCapability.promise,
|
||||||
]);
|
]);
|
||||||
const currentPageNumber = this._currentPageNumber;
|
const currentPageNumber = this._currentPageNumber;
|
||||||
@ -176,7 +169,7 @@ class PDFDocumentProperties {
|
|||||||
* Close the document properties overlay.
|
* Close the document properties overlay.
|
||||||
*/
|
*/
|
||||||
async close() {
|
async close() {
|
||||||
this.overlayManager.close(this.dialogName);
|
this.overlayManager.close(this.dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +217,7 @@ class PDFDocumentProperties {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.overlayManager.active !== this.dialogName) {
|
if (this.overlayManager.active !== this.dialog) {
|
||||||
// Don't bother updating the dialog if has already been closed,
|
// Don't bother updating the dialog if has already been closed,
|
||||||
// since it will be updated the next time `this.open` is called.
|
// since it will be updated the next time `this.open` is called.
|
||||||
return;
|
return;
|
||||||
|
@ -18,6 +18,7 @@ import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js";
|
|||||||
import { getXfaHtmlForPrinting } from "./print_utils.js";
|
import { getXfaHtmlForPrinting } from "./print_utils.js";
|
||||||
|
|
||||||
let activeService = null;
|
let activeService = null;
|
||||||
|
let dialog = null;
|
||||||
let overlayManager = null;
|
let overlayManager = null;
|
||||||
|
|
||||||
// Renders the page to the canvas of the given print service, and returns
|
// Renders the page to the canvas of the given print service, and returns
|
||||||
@ -131,8 +132,8 @@ PDFPrintService.prototype = {
|
|||||||
this.scratchCanvas = null;
|
this.scratchCanvas = null;
|
||||||
activeService = null;
|
activeService = null;
|
||||||
ensureOverlay().then(function () {
|
ensureOverlay().then(function () {
|
||||||
if (overlayManager.active === "printServiceDialog") {
|
if (overlayManager.active === dialog) {
|
||||||
overlayManager.close("printServiceDialog");
|
overlayManager.close(dialog);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -229,7 +230,7 @@ window.print = function () {
|
|||||||
}
|
}
|
||||||
ensureOverlay().then(function () {
|
ensureOverlay().then(function () {
|
||||||
if (activeService) {
|
if (activeService) {
|
||||||
overlayManager.open("printServiceDialog");
|
overlayManager.open(dialog);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -239,8 +240,8 @@ window.print = function () {
|
|||||||
if (!activeService) {
|
if (!activeService) {
|
||||||
console.error("Expected print service to be initialized.");
|
console.error("Expected print service to be initialized.");
|
||||||
ensureOverlay().then(function () {
|
ensureOverlay().then(function () {
|
||||||
if (overlayManager.active === "printServiceDialog") {
|
if (overlayManager.active === dialog) {
|
||||||
overlayManager.close("printServiceDialog");
|
overlayManager.close(dialog);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return; // eslint-disable-line no-unsafe-finally
|
return; // eslint-disable-line no-unsafe-finally
|
||||||
@ -281,10 +282,10 @@ function abort() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderProgress(index, total, l10n) {
|
function renderProgress(index, total, l10n) {
|
||||||
const progressDialog = document.getElementById("printServiceDialog");
|
dialog ||= document.getElementById("printServiceDialog");
|
||||||
const progress = Math.round((100 * index) / total);
|
const progress = Math.round((100 * index) / total);
|
||||||
const progressBar = progressDialog.querySelector("progress");
|
const progressBar = dialog.querySelector("progress");
|
||||||
const progressPerc = progressDialog.querySelector(".relative-progress");
|
const progressPerc = dialog.querySelector(".relative-progress");
|
||||||
progressBar.value = progress;
|
progressBar.value = progress;
|
||||||
l10n.get("print_progress_percent", { progress }).then(msg => {
|
l10n.get("print_progress_percent", { progress }).then(msg => {
|
||||||
progressPerc.textContent = msg;
|
progressPerc.textContent = msg;
|
||||||
@ -336,10 +337,9 @@ function ensureOverlay() {
|
|||||||
if (!overlayManager) {
|
if (!overlayManager) {
|
||||||
throw new Error("The overlay manager has not yet been initialized.");
|
throw new Error("The overlay manager has not yet been initialized.");
|
||||||
}
|
}
|
||||||
const dialog = document.getElementById("printServiceDialog");
|
dialog ||= document.getElementById("printServiceDialog");
|
||||||
|
|
||||||
overlayPromise = overlayManager.register(
|
overlayPromise = overlayManager.register(
|
||||||
"printServiceDialog",
|
|
||||||
dialog,
|
dialog,
|
||||||
/* canForceClose = */ true
|
/* canForceClose = */ true
|
||||||
);
|
);
|
||||||
|
@ -161,7 +161,6 @@ function getViewerConfiguration() {
|
|||||||
findNextButton: document.getElementById("findNext"),
|
findNextButton: document.getElementById("findNext"),
|
||||||
},
|
},
|
||||||
passwordOverlay: {
|
passwordOverlay: {
|
||||||
dialogName: "passwordDialog",
|
|
||||||
dialog: document.getElementById("passwordDialog"),
|
dialog: document.getElementById("passwordDialog"),
|
||||||
label: document.getElementById("passwordText"),
|
label: document.getElementById("passwordText"),
|
||||||
input: document.getElementById("password"),
|
input: document.getElementById("password"),
|
||||||
@ -169,7 +168,6 @@ function getViewerConfiguration() {
|
|||||||
cancelButton: document.getElementById("passwordCancel"),
|
cancelButton: document.getElementById("passwordCancel"),
|
||||||
},
|
},
|
||||||
documentProperties: {
|
documentProperties: {
|
||||||
dialogName: "documentPropertiesDialog",
|
|
||||||
dialog: document.getElementById("documentPropertiesDialog"),
|
dialog: document.getElementById("documentPropertiesDialog"),
|
||||||
closeButton: document.getElementById("documentPropertiesClose"),
|
closeButton: document.getElementById("documentPropertiesClose"),
|
||||||
fields: {
|
fields: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user