Merge pull request #14710 from Snuffleupagus/overlays-dialog
Convert the existing overlays to use `<dialog>` elements (issue 14698)
This commit is contained in:
commit
d6592b5e37
13
package-lock.json
generated
13
package-lock.json
generated
@ -21,6 +21,7 @@
|
||||
"canvas": "^2.9.1",
|
||||
"core-js": "^3.21.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dialog-polyfill": "^0.5.6",
|
||||
"dommatrix": "^0.0.24",
|
||||
"es-module-shims": "1.4.7",
|
||||
"eslint": "^8.11.0",
|
||||
@ -4350,6 +4351,12 @@
|
||||
"kuler": "1.0.x"
|
||||
}
|
||||
},
|
||||
"node_modules/dialog-polyfill": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz",
|
||||
"integrity": "sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@ -21951,6 +21958,12 @@
|
||||
"kuler": "1.0.x"
|
||||
}
|
||||
},
|
||||
"dialog-polyfill": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz",
|
||||
"integrity": "sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w==",
|
||||
"dev": true
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
|
@ -14,6 +14,7 @@
|
||||
"canvas": "^2.9.1",
|
||||
"core-js": "^3.21.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dialog-polyfill": "^0.5.6",
|
||||
"dommatrix": "^0.0.24",
|
||||
"es-module-shims": "1.4.7",
|
||||
"eslint": "^8.11.0",
|
||||
|
@ -147,7 +147,7 @@ function reloadIfRuntimeIsUnavailable() {
|
||||
|
||||
let chromeFileAccessOverlayPromise;
|
||||
function requestAccessToLocalFile(fileUrl, overlayManager, callback) {
|
||||
let onCloseOverlay = null;
|
||||
const dialog = document.getElementById("chromeFileAccessDialog");
|
||||
if (top !== window) {
|
||||
// When the extension reloads after receiving new permissions, the pages
|
||||
// have to be reloaded to restore the extension runtime. Auto-reload
|
||||
@ -157,20 +157,16 @@ function requestAccessToLocalFile(fileUrl, overlayManager, callback) {
|
||||
// for detecting unload of the top-level frame. Should this ever change
|
||||
// (crbug.com/511670), then the user can just reload the tab.
|
||||
window.addEventListener("focus", reloadIfRuntimeIsUnavailable);
|
||||
onCloseOverlay = function () {
|
||||
dialog.addEventListener("close", function () {
|
||||
window.removeEventListener("focus", reloadIfRuntimeIsUnavailable);
|
||||
reloadIfRuntimeIsUnavailable();
|
||||
overlayManager.close("chromeFileAccessOverlay");
|
||||
};
|
||||
}
|
||||
if (!chromeFileAccessOverlayPromise) {
|
||||
chromeFileAccessOverlayPromise = overlayManager.register(
|
||||
"chromeFileAccessOverlay",
|
||||
document.getElementById("chromeFileAccessOverlay"),
|
||||
onCloseOverlay,
|
||||
true
|
||||
);
|
||||
});
|
||||
}
|
||||
chromeFileAccessOverlayPromise ||= overlayManager.register(
|
||||
dialog,
|
||||
/* canForceClose = */ true
|
||||
);
|
||||
|
||||
chromeFileAccessOverlayPromise.then(function () {
|
||||
const iconPath = chrome.runtime.getManifest().icons[48];
|
||||
document.getElementById("chrome-pdfjs-logo-bg").style.backgroundImage =
|
||||
@ -229,11 +225,11 @@ function requestAccessToLocalFile(fileUrl, overlayManager, callback) {
|
||||
originalUrl = "file:///fakepath/to/" + encodeURIComponent(file.name);
|
||||
}
|
||||
callback(URL.createObjectURL(file), file.size, originalUrl);
|
||||
overlayManager.close("chromeFileAccessOverlay");
|
||||
overlayManager.close(dialog);
|
||||
}
|
||||
};
|
||||
|
||||
overlayManager.open("chromeFileAccessOverlay");
|
||||
overlayManager.open(dialog);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -14,123 +14,93 @@
|
||||
*/
|
||||
|
||||
class OverlayManager {
|
||||
#overlays = Object.create(null);
|
||||
#overlays = new WeakMap();
|
||||
|
||||
#active = null;
|
||||
|
||||
#keyDownBound = null;
|
||||
|
||||
get active() {
|
||||
return this.#active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - The name of the overlay that is registered.
|
||||
* @param {HTMLDivElement} element - The overlay's DOM element.
|
||||
* @param {function} [callerCloseMethod] - The method that, if present, calls
|
||||
* `OverlayManager.close` from the object registering the
|
||||
* overlay. Access to this method is necessary in order to
|
||||
* run cleanup code when e.g. the overlay is force closed.
|
||||
* The default is `null`.
|
||||
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||
* @param {boolean} [canForceClose] - Indicates if opening the overlay closes
|
||||
* an active overlay. The default is `false`.
|
||||
* @returns {Promise} A promise that is resolved when the overlay has been
|
||||
* registered.
|
||||
*/
|
||||
async register(
|
||||
name,
|
||||
element,
|
||||
callerCloseMethod = null,
|
||||
canForceClose = false
|
||||
) {
|
||||
let container;
|
||||
if (!name || !element || !(container = element.parentNode)) {
|
||||
async register(dialog, canForceClose = false) {
|
||||
if (typeof dialog !== "object") {
|
||||
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.");
|
||||
}
|
||||
this.#overlays[name] = {
|
||||
element,
|
||||
container,
|
||||
callerCloseMethod,
|
||||
canForceClose,
|
||||
};
|
||||
this.#overlays.set(dialog, { canForceClose });
|
||||
|
||||
if (
|
||||
typeof PDFJSDev !== "undefined" &&
|
||||
PDFJSDev.test("GENERIC && !SKIP_BABEL") &&
|
||||
!dialog.showModal
|
||||
) {
|
||||
const dialogPolyfill = require("dialog-polyfill/dist/dialog-polyfill.js");
|
||||
dialogPolyfill.registerDialog(dialog);
|
||||
}
|
||||
|
||||
dialog.addEventListener("cancel", evt => {
|
||||
this.#active = null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* unregistered.
|
||||
*/
|
||||
async unregister(name) {
|
||||
if (!this.#overlays[name]) {
|
||||
async unregister(dialog) {
|
||||
if (!this.#overlays.has(dialog)) {
|
||||
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.");
|
||||
}
|
||||
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
|
||||
* opened.
|
||||
*/
|
||||
async open(name) {
|
||||
if (!this.#overlays[name]) {
|
||||
async open(dialog) {
|
||||
if (!this.#overlays.has(dialog)) {
|
||||
throw new Error("The overlay does not exist.");
|
||||
} else if (this.#active) {
|
||||
if (this.#active === name) {
|
||||
if (this.#active === dialog) {
|
||||
throw new Error("The overlay is already active.");
|
||||
} else if (this.#overlays[name].canForceClose) {
|
||||
this.#closeThroughCaller();
|
||||
} else if (this.#overlays.get(dialog).canForceClose) {
|
||||
await this.close();
|
||||
} else {
|
||||
throw new Error("Another overlay is currently active.");
|
||||
}
|
||||
}
|
||||
this.#active = name;
|
||||
this.#overlays[this.#active].element.classList.remove("hidden");
|
||||
this.#overlays[this.#active].container.classList.remove("hidden");
|
||||
|
||||
this.#keyDownBound = this.#keyDown.bind(this);
|
||||
window.addEventListener("keydown", this.#keyDownBound);
|
||||
this.#active = dialog;
|
||||
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
|
||||
* closed.
|
||||
*/
|
||||
async close(name) {
|
||||
if (!this.#overlays[name]) {
|
||||
async close(dialog = this.#active) {
|
||||
if (!this.#overlays.has(dialog)) {
|
||||
throw new Error("The overlay does not exist.");
|
||||
} else if (!this.#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.");
|
||||
}
|
||||
this.#overlays[this.#active].container.classList.add("hidden");
|
||||
this.#overlays[this.#active].element.classList.add("hidden");
|
||||
dialog.close();
|
||||
this.#active = null;
|
||||
|
||||
window.removeEventListener("keydown", this.#keyDownBound);
|
||||
this.#keyDownBound = null;
|
||||
}
|
||||
|
||||
#keyDown(evt) {
|
||||
if (this.#active && evt.keyCode === /* Esc = */ 27) {
|
||||
this.#closeThroughCaller();
|
||||
evt.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
#closeThroughCaller() {
|
||||
if (this.#overlays[this.#active].callerCloseMethod) {
|
||||
this.#overlays[this.#active].callerCloseMethod();
|
||||
}
|
||||
if (this.#active) {
|
||||
this.close(this.#active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,7 @@ import { PasswordResponses } from "pdfjs-lib";
|
||||
|
||||
/**
|
||||
* @typedef {Object} PasswordPromptOptions
|
||||
* @property {string} overlayName - Name of the overlay for the overlay manager.
|
||||
* @property {HTMLDivElement} container - Div container for the overlay.
|
||||
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||
* @property {HTMLParagraphElement} label - Label containing instructions for
|
||||
* entering the password.
|
||||
* @property {HTMLInputElement} input - Input field for entering the password.
|
||||
@ -29,6 +28,10 @@ import { PasswordResponses } from "pdfjs-lib";
|
||||
*/
|
||||
|
||||
class PasswordPrompt {
|
||||
#updateCallback = null;
|
||||
|
||||
#reason = null;
|
||||
|
||||
/**
|
||||
* @param {PasswordPromptOptions} options
|
||||
* @param {OverlayManager} overlayManager - Manager for the viewer overlays.
|
||||
@ -37,8 +40,7 @@ class PasswordPrompt {
|
||||
* an <iframe> or an <object>. The default value is `false`.
|
||||
*/
|
||||
constructor(options, overlayManager, l10n, isViewerEmbedded = false) {
|
||||
this.overlayName = options.overlayName;
|
||||
this.container = options.container;
|
||||
this.dialog = options.dialog;
|
||||
this.label = options.label;
|
||||
this.input = options.input;
|
||||
this.submitButton = options.submitButton;
|
||||
@ -47,9 +49,6 @@ class PasswordPrompt {
|
||||
this.l10n = l10n;
|
||||
this._isViewerEmbedded = isViewerEmbedded;
|
||||
|
||||
this.updateCallback = null;
|
||||
this.reason = null;
|
||||
|
||||
// Attach the event listeners.
|
||||
this.submitButton.addEventListener("click", this.#verify.bind(this));
|
||||
this.cancelButton.addEventListener("click", this.#cancel.bind(this));
|
||||
@ -59,19 +58,16 @@ class PasswordPrompt {
|
||||
}
|
||||
});
|
||||
|
||||
this.overlayManager.register(
|
||||
this.overlayName,
|
||||
this.container,
|
||||
this.#cancel.bind(this),
|
||||
true
|
||||
);
|
||||
this.overlayManager.register(this.dialog, /* canForceClose = */ true);
|
||||
|
||||
this.dialog.addEventListener("close", this.#cancel.bind(this));
|
||||
}
|
||||
|
||||
async open() {
|
||||
await this.overlayManager.open(this.overlayName);
|
||||
await this.overlayManager.open(this.dialog);
|
||||
|
||||
const passwordIncorrect =
|
||||
this.reason === PasswordResponses.INCORRECT_PASSWORD;
|
||||
this.#reason === PasswordResponses.INCORRECT_PASSWORD;
|
||||
|
||||
if (!this._isViewerEmbedded || passwordIncorrect) {
|
||||
this.input.focus();
|
||||
@ -82,26 +78,36 @@ class PasswordPrompt {
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.overlayManager.close(this.overlayName);
|
||||
this.input.value = "";
|
||||
if (this.overlayManager.active === this.dialog) {
|
||||
this.overlayManager.close(this.dialog);
|
||||
}
|
||||
}
|
||||
|
||||
#verify() {
|
||||
const password = this.input.value;
|
||||
if (password?.length > 0) {
|
||||
this.close();
|
||||
this.updateCallback(password);
|
||||
this.#invokeCallback(password);
|
||||
}
|
||||
}
|
||||
|
||||
#cancel() {
|
||||
this.#invokeCallback(new Error("PasswordPrompt cancelled."));
|
||||
}
|
||||
|
||||
#invokeCallback(password) {
|
||||
if (!this.#updateCallback) {
|
||||
return; // Ensure that the callback is only invoked once.
|
||||
}
|
||||
this.close();
|
||||
this.updateCallback(new Error("PasswordPrompt cancelled."));
|
||||
this.input.value = "";
|
||||
|
||||
this.#updateCallback(password);
|
||||
this.#updateCallback = null;
|
||||
}
|
||||
|
||||
setUpdateCallback(updateCallback, reason) {
|
||||
this.updateCallback = updateCallback;
|
||||
this.reason = reason;
|
||||
this.#updateCallback = updateCallback;
|
||||
this.#reason = reason;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,9 +45,8 @@ function getPageName(size, isPortrait, pageNames) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} PDFDocumentPropertiesOptions
|
||||
* @property {string} overlayName - Name/identifier for the overlay.
|
||||
* @property {HTMLDialogElement} dialog - The overlay's DOM element.
|
||||
* @property {Object} fields - Names and elements of the overlay's fields.
|
||||
* @property {HTMLDivElement} container - Div container for the overlay.
|
||||
* @property {HTMLButtonElement} closeButton - Button for closing the overlay.
|
||||
*/
|
||||
|
||||
@ -60,15 +59,9 @@ class PDFDocumentProperties {
|
||||
* @param {EventBus} eventBus - The application event bus.
|
||||
* @param {IL10n} l10n - Localization service.
|
||||
*/
|
||||
constructor(
|
||||
{ overlayName, fields, container, closeButton },
|
||||
overlayManager,
|
||||
eventBus,
|
||||
l10n
|
||||
) {
|
||||
this.overlayName = overlayName;
|
||||
constructor({ dialog, fields, closeButton }, overlayManager, eventBus, l10n) {
|
||||
this.dialog = dialog;
|
||||
this.fields = fields;
|
||||
this.container = container;
|
||||
this.overlayManager = overlayManager;
|
||||
this.l10n = l10n;
|
||||
|
||||
@ -76,11 +69,7 @@ class PDFDocumentProperties {
|
||||
// Bind the event listener for the Close button.
|
||||
closeButton.addEventListener("click", this.close.bind(this));
|
||||
|
||||
this.overlayManager.register(
|
||||
this.overlayName,
|
||||
this.container,
|
||||
this.close.bind(this)
|
||||
);
|
||||
this.overlayManager.register(this.dialog);
|
||||
|
||||
eventBus._on("pagechanging", evt => {
|
||||
this._currentPageNumber = evt.pageNumber;
|
||||
@ -100,7 +89,7 @@ class PDFDocumentProperties {
|
||||
*/
|
||||
async open() {
|
||||
await Promise.all([
|
||||
this.overlayManager.open(this.overlayName),
|
||||
this.overlayManager.open(this.dialog),
|
||||
this._dataAvailableCapability.promise,
|
||||
]);
|
||||
const currentPageNumber = this._currentPageNumber;
|
||||
@ -179,8 +168,8 @@ class PDFDocumentProperties {
|
||||
/**
|
||||
* Close the document properties overlay.
|
||||
*/
|
||||
close() {
|
||||
this.overlayManager.close(this.overlayName);
|
||||
async close() {
|
||||
this.overlayManager.close(this.dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,7 +217,7 @@ class PDFDocumentProperties {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.overlayManager.active !== this.overlayName) {
|
||||
if (this.overlayManager.active !== this.dialog) {
|
||||
// Don't bother updating the dialog if has already been closed,
|
||||
// since it will be updated the next time `this.open` is called.
|
||||
return;
|
||||
|
@ -18,6 +18,7 @@ import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js";
|
||||
import { getXfaHtmlForPrinting } from "./print_utils.js";
|
||||
|
||||
let activeService = null;
|
||||
let dialog = null;
|
||||
let overlayManager = null;
|
||||
|
||||
// Renders the page to the canvas of the given print service, and returns
|
||||
@ -115,8 +116,7 @@ PDFPrintService.prototype = {
|
||||
destroy() {
|
||||
if (activeService !== this) {
|
||||
// |activeService| cannot be replaced without calling destroy() first,
|
||||
// so if it differs then an external consumer has a stale reference to
|
||||
// us.
|
||||
// so if it differs then an external consumer has a stale reference to us.
|
||||
return;
|
||||
}
|
||||
this.printContainer.textContent = "";
|
||||
@ -132,10 +132,9 @@ PDFPrintService.prototype = {
|
||||
this.scratchCanvas = null;
|
||||
activeService = null;
|
||||
ensureOverlay().then(function () {
|
||||
if (overlayManager.active !== "printServiceOverlay") {
|
||||
return; // overlay was already closed
|
||||
if (overlayManager.active === dialog) {
|
||||
overlayManager.close(dialog);
|
||||
}
|
||||
overlayManager.close("printServiceOverlay");
|
||||
});
|
||||
},
|
||||
|
||||
@ -231,7 +230,7 @@ window.print = function () {
|
||||
}
|
||||
ensureOverlay().then(function () {
|
||||
if (activeService) {
|
||||
overlayManager.open("printServiceOverlay");
|
||||
overlayManager.open(dialog);
|
||||
}
|
||||
});
|
||||
|
||||
@ -241,8 +240,8 @@ window.print = function () {
|
||||
if (!activeService) {
|
||||
console.error("Expected print service to be initialized.");
|
||||
ensureOverlay().then(function () {
|
||||
if (overlayManager.active === "printServiceOverlay") {
|
||||
overlayManager.close("printServiceOverlay");
|
||||
if (overlayManager.active === dialog) {
|
||||
overlayManager.close(dialog);
|
||||
}
|
||||
});
|
||||
return; // eslint-disable-line no-unsafe-finally
|
||||
@ -283,10 +282,10 @@ function abort() {
|
||||
}
|
||||
|
||||
function renderProgress(index, total, l10n) {
|
||||
const progressContainer = document.getElementById("printServiceOverlay");
|
||||
dialog ||= document.getElementById("printServiceDialog");
|
||||
const progress = Math.round((100 * index) / total);
|
||||
const progressBar = progressContainer.querySelector("progress");
|
||||
const progressPerc = progressContainer.querySelector(".relative-progress");
|
||||
const progressBar = dialog.querySelector("progress");
|
||||
const progressPerc = dialog.querySelector(".relative-progress");
|
||||
progressBar.value = progress;
|
||||
l10n.get("print_progress_percent", { progress }).then(msg => {
|
||||
progressPerc.textContent = msg;
|
||||
@ -338,14 +337,15 @@ function ensureOverlay() {
|
||||
if (!overlayManager) {
|
||||
throw new Error("The overlay manager has not yet been initialized.");
|
||||
}
|
||||
dialog ||= document.getElementById("printServiceDialog");
|
||||
|
||||
overlayPromise = overlayManager.register(
|
||||
"printServiceOverlay",
|
||||
document.getElementById("printServiceOverlay"),
|
||||
abort,
|
||||
true
|
||||
dialog,
|
||||
/* canForceClose = */ true
|
||||
);
|
||||
|
||||
document.getElementById("printCancel").onclick = abort;
|
||||
dialog.addEventListener("close", abort);
|
||||
}
|
||||
return overlayPromise;
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
<div id="chromeFileAccessOverlay" class="container hidden">
|
||||
<div class="dialog">
|
||||
<div class="row">
|
||||
<!-- The extension icon (PDF.js logo) will be shown at the left, to help
|
||||
users with recognizing which checkbox they have to click when they
|
||||
visit chrome://extensions.
|
||||
-->
|
||||
<p id="chrome-pdfjs-logo-bg" style="
|
||||
display: block;
|
||||
padding-left: 60px;
|
||||
min-height: 48px;
|
||||
background-size: 48px;
|
||||
background-repeat: no-repeat;
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
word-break: break-all;">
|
||||
Click on
|
||||
"<span id="chrome-file-access-label">Allow access to file URLs</span>"
|
||||
at
|
||||
<a id="chrome-link-to-extensions-page">chrome://extensions</a>
|
||||
<br>
|
||||
to view <span id="chrome-url-of-local-file">this PDF file.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>
|
||||
or select the file again:
|
||||
<input type="file" id="chrome-file-fallback" accept=".pdf">
|
||||
</p>
|
||||
</div>
|
||||
<dialog id="chromeFileAccessDialog">
|
||||
<div class="row">
|
||||
<!-- The extension icon (PDF.js logo) will be shown at the left, to help
|
||||
users with recognizing which checkbox they have to click when they
|
||||
visit chrome://extensions.
|
||||
-->
|
||||
<p id="chrome-pdfjs-logo-bg" style="
|
||||
display: block;
|
||||
padding-left: 60px;
|
||||
min-height: 48px;
|
||||
background-size: 48px;
|
||||
background-repeat: no-repeat;
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
word-break: break-all;">
|
||||
Click on
|
||||
"<span id="chrome-file-access-label">Allow access to file URLs</span>"
|
||||
at
|
||||
<a id="chrome-link-to-extensions-page">chrome://extensions</a>
|
||||
<br>
|
||||
to view <span id="chrome-url-of-local-file">this PDF file.</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>
|
||||
or select the file again:
|
||||
<input type="file" id="chrome-file-fallback" accept=".pdf">
|
||||
</p>
|
||||
</div>
|
||||
</dialog>
|
||||
|
@ -62,9 +62,9 @@
|
||||
--doorhanger-hover-color: rgba(12, 12, 13, 1);
|
||||
--doorhanger-hover-bg-color: rgba(237, 237, 237, 1);
|
||||
--doorhanger-separator-color: rgba(222, 222, 222, 1);
|
||||
--overlay-button-border: 0 none;
|
||||
--overlay-button-bg-color: rgba(12, 12, 13, 0.1);
|
||||
--overlay-button-hover-bg-color: rgba(12, 12, 13, 0.3);
|
||||
--dialog-button-border: 0 none;
|
||||
--dialog-button-bg-color: rgba(12, 12, 13, 0.1);
|
||||
--dialog-button-hover-bg-color: rgba(12, 12, 13, 0.3);
|
||||
|
||||
--loading-icon: url(images/loading.svg);
|
||||
--treeitem-expanded-icon: url(images/treeitem-expanded.svg);
|
||||
@ -146,8 +146,8 @@
|
||||
--doorhanger-hover-color: rgba(249, 249, 250, 1);
|
||||
--doorhanger-hover-bg-color: rgba(93, 94, 98, 1);
|
||||
--doorhanger-separator-color: rgba(92, 92, 97, 1);
|
||||
--overlay-button-bg-color: rgba(92, 92, 97, 1);
|
||||
--overlay-button-hover-bg-color: rgba(115, 115, 115, 1);
|
||||
--dialog-button-bg-color: rgba(92, 92, 97, 1);
|
||||
--dialog-button-hover-bg-color: rgba(115, 115, 115, 1);
|
||||
|
||||
/* This image is used in <input> elements, which unfortunately means that
|
||||
* the `mask-image` approach used with all of the other images doesn't work
|
||||
@ -168,9 +168,9 @@
|
||||
--doorhanger-hover-color: ButtonFace;
|
||||
--doorhanger-border-color-whcm: 1px solid ButtonText;
|
||||
--doorhanger-triangle-opacity-whcm: 0;
|
||||
--overlay-button-border: 1px solid Highlight;
|
||||
--overlay-button-hover-bg-color: Highlight;
|
||||
--overlay-button-hover-color: ButtonFace;
|
||||
--dialog-button-border: 1px solid Highlight;
|
||||
--dialog-button-hover-bg-color: Highlight;
|
||||
--dialog-button-hover-color: ButtonFace;
|
||||
--field-border-color: ButtonText;
|
||||
}
|
||||
}
|
||||
@ -628,21 +628,21 @@ select {
|
||||
|
||||
.toolbarButton,
|
||||
.secondaryToolbarButton,
|
||||
.overlayButton {
|
||||
.dialogButton {
|
||||
border: 0 none;
|
||||
background: none;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.overlayButton:hover,
|
||||
.overlayButton:focus-visible {
|
||||
background-color: var(--overlay-button-hover-bg-color);
|
||||
.dialogButton:hover,
|
||||
.dialogButton:focus-visible {
|
||||
background-color: var(--dialog-button-hover-bg-color);
|
||||
}
|
||||
|
||||
.overlayButton:hover > span,
|
||||
.overlayButton:focus-visible > span {
|
||||
color: var(--overlay-button-hover-color);
|
||||
.dialogButton:hover > span,
|
||||
.dialogButton:focus-visible > span {
|
||||
color: var(--dialog-button-hover-color);
|
||||
}
|
||||
|
||||
.toolbarButton > span {
|
||||
@ -654,7 +654,7 @@ select {
|
||||
|
||||
.toolbarButton[disabled],
|
||||
.secondaryToolbarButton[disabled],
|
||||
.overlayButton[disabled] {
|
||||
.dialogButton[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@ -697,7 +697,7 @@ select {
|
||||
.toolbarButton,
|
||||
.dropdownToolbarButton,
|
||||
.secondaryToolbarButton,
|
||||
.overlayButton {
|
||||
.dialogButton {
|
||||
min-width: 16px;
|
||||
margin: 2px 1px;
|
||||
padding: 2px 6px 0;
|
||||
@ -1278,32 +1278,17 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.overlayButton {
|
||||
.dialogButton {
|
||||
width: auto;
|
||||
margin: 3px 4px 2px !important;
|
||||
padding: 2px 11px;
|
||||
color: var(--main-color);
|
||||
background-color: var(--overlay-button-bg-color);
|
||||
border: var(--overlay-button-border) !important;
|
||||
background-color: var(--dialog-button-bg-color);
|
||||
border: var(--dialog-button-border) !important;
|
||||
}
|
||||
|
||||
#overlayContainer {
|
||||
display: table;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
z-index: 40000;
|
||||
}
|
||||
|
||||
#overlayContainer > .container {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#overlayContainer > .container > .dialog {
|
||||
display: inline-block;
|
||||
dialog {
|
||||
margin: auto;
|
||||
padding: 15px;
|
||||
border-spacing: 4px;
|
||||
color: var(--main-color);
|
||||
@ -1314,20 +1299,24 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
dialog::backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.dialog > .row {
|
||||
dialog > .row {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.dialog > .row > * {
|
||||
dialog > .row > * {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.dialog .toolbarField {
|
||||
dialog .toolbarField {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.dialog .separator {
|
||||
dialog .separator {
|
||||
display: block;
|
||||
margin: 4px 0;
|
||||
height: 1px;
|
||||
@ -1335,38 +1324,38 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
||||
background-color: var(--separator-color);
|
||||
}
|
||||
|
||||
.dialog .buttonRow {
|
||||
dialog .buttonRow {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.dialog :link {
|
||||
dialog :link {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
#passwordOverlay > .dialog {
|
||||
#passwordDialog {
|
||||
text-align: center;
|
||||
}
|
||||
#passwordOverlay .toolbarField {
|
||||
#passwordDialog .toolbarField {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#documentPropertiesOverlay > .dialog {
|
||||
#documentPropertiesDialog {
|
||||
text-align: left;
|
||||
}
|
||||
#documentPropertiesOverlay .row > * {
|
||||
#documentPropertiesDialog .row > * {
|
||||
min-width: 100px;
|
||||
text-align: start;
|
||||
}
|
||||
#documentPropertiesOverlay .row > span {
|
||||
#documentPropertiesDialog .row > span {
|
||||
width: 125px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#documentPropertiesOverlay .row > p {
|
||||
#documentPropertiesDialog .row > p {
|
||||
max-width: 225px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#documentPropertiesOverlay .buttonRow {
|
||||
#documentPropertiesDialog .buttonRow {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
168
web/viewer.html
168
web/viewer.html
@ -233,7 +233,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="69" data-l10n-id="document_properties">
|
||||
<button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="69" data-l10n-id="document_properties" aria-controls="documentPropertiesDialog">
|
||||
<span data-l10n-id="document_properties_label">Document Properties…</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -352,93 +352,101 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
<!--#endif-->
|
||||
</div> <!-- mainContainer -->
|
||||
|
||||
<div id="overlayContainer" class="hidden">
|
||||
<div id="passwordOverlay" class="container hidden">
|
||||
<div class="dialog">
|
||||
<div class="row">
|
||||
<p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="password" id="password" class="toolbarField">
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
|
||||
<button id="passwordSubmit" class="overlayButton"><span data-l10n-id="password_ok">OK</span></button>
|
||||
</div>
|
||||
<div id="dialogContainer">
|
||||
<dialog id="passwordDialog">
|
||||
<div class="row">
|
||||
<label for="password" id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="documentPropertiesOverlay" class="container hidden">
|
||||
<div class="dialog">
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_file_name">File name:</span> <p id="fileNameField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_file_size">File size:</span> <p id="fileSizeField">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_title">Title:</span> <p id="titleField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_author">Author:</span> <p id="authorField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_subject">Subject:</span> <p id="subjectField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_keywords">Keywords:</span> <p id="keywordsField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_creation_date">Creation Date:</span> <p id="creationDateField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_modification_date">Modification Date:</span> <p id="modificationDateField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_creator">Creator:</span> <p id="creatorField">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_producer">PDF Producer:</span> <p id="producerField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_version">PDF Version:</span> <p id="versionField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_page_size">Page Size:</span> <p id="pageSizeField">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span data-l10n-id="document_properties_linearized">Fast Web View:</span> <p id="linearizedField">-</p>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="password" id="password" class="toolbarField">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="passwordCancel" class="dialogButton"><span data-l10n-id="password_cancel">Cancel</span></button>
|
||||
<button id="passwordSubmit" class="dialogButton"><span data-l10n-id="password_ok">OK</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog id="documentPropertiesDialog">
|
||||
<div class="row">
|
||||
<span id="fileNameLabel" data-l10n-id="document_properties_file_name">File name:</span>
|
||||
<p id="fileNameField" aria-labelledby="fileNameLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="fileSizeLabel" data-l10n-id="document_properties_file_size">File size:</span>
|
||||
<p id="fileSizeField" aria-labelledby="fileSizeLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="titleLabel" data-l10n-id="document_properties_title">Title:</span>
|
||||
<p id="titleField" aria-labelledby="titleLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="authorLabel" data-l10n-id="document_properties_author">Author:</span>
|
||||
<p id="authorField" aria-labelledby="authorLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="subjectLabel" data-l10n-id="document_properties_subject">Subject:</span>
|
||||
<p id="subjectField" aria-labelledby="subjectLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="keywordsLabel" data-l10n-id="document_properties_keywords">Keywords:</span>
|
||||
<p id="keywordsField" aria-labelledby="keywordsLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="creationDateLabel" data-l10n-id="document_properties_creation_date">Creation Date:</span>
|
||||
<p id="creationDateField" aria-labelledby="creationDateLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="modificationDateLabel" data-l10n-id="document_properties_modification_date">Modification Date:</span>
|
||||
<p id="modificationDateField" aria-labelledby="modificationDateLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="creatorLabel" data-l10n-id="document_properties_creator">Creator:</span>
|
||||
<p id="creatorField" aria-labelledby="creatorLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="producerLabel" data-l10n-id="document_properties_producer">PDF Producer:</span>
|
||||
<p id="producerField" aria-labelledby="producerLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="versionLabel" data-l10n-id="document_properties_version">PDF Version:</span>
|
||||
<p id="versionField" aria-labelledby="versionLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="pageCountLabel" data-l10n-id="document_properties_page_count">Page Count:</span>
|
||||
<p id="pageCountField" aria-labelledby="pageCountLabel">-</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span id="pageSizeLabel" data-l10n-id="document_properties_page_size">Page Size:</span>
|
||||
<p id="pageSizeField" aria-labelledby="pageSizeLabel">-</p>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<span id="linearizedLabel" data-l10n-id="document_properties_linearized">Fast Web View:</span>
|
||||
<p id="linearizedField" aria-labelledby="linearizedLabel">-</p>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="documentPropertiesClose" class="dialogButton"><span data-l10n-id="document_properties_close">Close</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
<!--#if !MOZCENTRAL-->
|
||||
<div id="printServiceOverlay" class="container hidden">
|
||||
<div class="dialog">
|
||||
<div class="row">
|
||||
<span data-l10n-id="print_progress_message">Preparing document for printing…</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<progress value="0" max="100"></progress>
|
||||
<span data-l10n-id="print_progress_percent" data-l10n-args='{ "progress": 0 }' class="relative-progress">0%</span>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="printCancel" class="overlayButton"><span data-l10n-id="print_progress_close">Cancel</span></button>
|
||||
</div>
|
||||
<dialog id="printServiceDialog" style="min-width: 200px;">
|
||||
<div class="row">
|
||||
<span data-l10n-id="print_progress_message">Preparing document for printing…</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<progress value="0" max="100"></progress>
|
||||
<span data-l10n-id="print_progress_percent" data-l10n-args='{ "progress": 0 }' class="relative-progress">0%</span>
|
||||
</div>
|
||||
<div class="buttonRow">
|
||||
<button id="printCancel" class="dialogButton"><span data-l10n-id="print_progress_close">Cancel</span></button>
|
||||
</div>
|
||||
</dialog>
|
||||
<!--#endif-->
|
||||
<!--#if CHROME-->
|
||||
<!--#include viewer-snippet-chrome-overlays.html-->
|
||||
<!--#endif-->
|
||||
</div> <!-- overlayContainer -->
|
||||
</div> <!-- dialogContainer -->
|
||||
|
||||
</div> <!-- outerContainer -->
|
||||
<div id="printContainer"></div>
|
||||
|
@ -161,16 +161,14 @@ function getViewerConfiguration() {
|
||||
findNextButton: document.getElementById("findNext"),
|
||||
},
|
||||
passwordOverlay: {
|
||||
overlayName: "passwordOverlay",
|
||||
container: document.getElementById("passwordOverlay"),
|
||||
dialog: document.getElementById("passwordDialog"),
|
||||
label: document.getElementById("passwordText"),
|
||||
input: document.getElementById("password"),
|
||||
submitButton: document.getElementById("passwordSubmit"),
|
||||
cancelButton: document.getElementById("passwordCancel"),
|
||||
},
|
||||
documentProperties: {
|
||||
overlayName: "documentPropertiesOverlay",
|
||||
container: document.getElementById("documentPropertiesOverlay"),
|
||||
dialog: document.getElementById("documentPropertiesDialog"),
|
||||
closeButton: document.getElementById("documentPropertiesClose"),
|
||||
fields: {
|
||||
fileName: document.getElementById("fileNameField"),
|
||||
|
Loading…
Reference in New Issue
Block a user