From f195bec9b22f8509ca49d49d6982003100c119a2 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Fri, 24 Jul 2026 21:54:17 +0200 Subject: [PATCH] Add the Firefox features notification bar to the viewer (bug 2057608) The bar itself (``) ships from mozilla-central, so the viewer only hosts it. Finally the maximum number of preferences is raised to 60, to match the change made in mozilla-central in bug 2056102, since this adds a 51st one. --- test/unit/app_options_spec.js | 2 +- web/app.js | 60 +++++++++++++++++++++++++++++++++++ web/app_options.js | 13 ++++++++ web/firefoxcom.js | 7 ++++ web/viewer.css | 16 ++++++++++ web/viewer.html | 6 ++++ web/viewer.js | 8 +++++ 7 files changed, 111 insertions(+), 1 deletion(-) diff --git a/test/unit/app_options_spec.js b/test/unit/app_options_spec.js index 72e778f8e9a48..786817666a901 100644 --- a/test/unit/app_options_spec.js +++ b/test/unit/app_options_spec.js @@ -39,7 +39,7 @@ describe("AppOptions", function () { // If the following constant is updated then you *MUST* make the same change // in mozilla-central as well to ensure that preference-fetching works; see // https://searchfox.org/mozilla-central/source/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs - const MAX_NUMBER_OF_PREFS = 50; + const MAX_NUMBER_OF_PREFS = 60; const options = AppOptions.getAll(OptionKind.PREFERENCE); expect(Object.keys(options).length).toBeLessThanOrEqual( diff --git a/web/app.js b/web/app.js index 1042ea5e09581..cd3e6b6170078 100644 --- a/web/app.js +++ b/web/app.js @@ -504,6 +504,66 @@ const PDFViewerApplication = { this.editorUndoBar = new EditorUndoBar(appConfig.editorUndoBar, eventBus); } + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("MOZCENTRAL && !GECKOVIEW")) && + !this.isViewerEmbedded && + appConfig.featuresNotification && + !AppOptions.get("featuresNotificationDismissed") + ) { + const { featuresNotification } = appConfig; + customElements.whenDefined("pdf-features-notification").then(() => { + if (AppOptions.get("featuresNotificationDismissed")) { + return; + } + + featuresNotification.addEventListener( + "click", + event => { + if (!event.target.closest(".cta")) { + return; + } + event.preventDefault(); + externalServices.openAboutPdfFeatures(); + }, + { signal: abortSignal } + ); + + const barResizeObserver = new ResizeObserver(entries => { + const box = entries[0]?.borderBoxSize?.[0]; + const height = box + ? box.blockSize + : (entries[0]?.contentRect.height ?? 0); + docStyle.setProperty("--pfn-bar-height", `${Math.ceil(height)}px`); + }); + barResizeObserver.observe(featuresNotification); + + const hideBar = () => { + barResizeObserver.disconnect(); + docStyle.setProperty("--pfn-bar-height", "0px"); + featuresNotification.hidden = true; + }; + featuresNotification.addEventListener( + "pdf-features-notification:dismissed", + () => { + hideBar(); + this.preferences.set("featuresNotificationDismissed", true); + }, + { once: true } + ); + eventBus.on( + "featuresnotificationdismissed", + ({ value }) => { + if (value) { + hideBar(); + } + }, + { signal: abortSignal, ...internalOpt } + ); + featuresNotification.show(); + }); + } + const signatureManager = AppOptions.get("enableSignatureEditor") && appConfig.addSignatureDialog ? new SignatureManager( diff --git a/web/app_options.js b/web/app_options.js index cb20c0f45e405..c173028124037 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -309,6 +309,19 @@ const defaultOptions = { value: 0, kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, + ...(typeof PDFJSDev === "undefined" || + PDFJSDev.test("MOZCENTRAL && !GECKOVIEW") + ? { + featuresNotificationDismissed: { + /** @type {boolean} */ + value: false, + kind: + OptionKind.VIEWER + + OptionKind.PREFERENCE + + OptionKind.EVENT_DISPATCH, + }, + } + : {}), highlightEditorColors: { /** @type {string} */ value: diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 7da64a4efc265..94117c28a6ad1 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -769,6 +769,13 @@ class ExternalServices extends BaseExternalServices { dispatchGlobalEvent(event) { FirefoxCom.request("dispatchGlobalEvent", event); } + + openAboutPdfFeatures() { + if (PDFJSDev.test("GECKOVIEW")) { + throw new Error("Not implemented: openAboutPdfFeatures"); + } + FirefoxCom.request("openAboutPdfFeatures", null); + } } export { DownloadManager, ExternalServices, initCom, MLManager, Preferences }; diff --git a/web/viewer.css b/web/viewer.css index d607e356afef8..c10a9f260ea04 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -292,6 +292,22 @@ body { transition-timing-function: var(--sidebar-transition-timing-function); } +/*#if MOZCENTRAL*/ +#viewerContainer:not(.pdfPresentationMode) { + inset-block-start: calc(var(--toolbar-height) + var(--pfn-bar-height, 0px)); +} + +#outerContainer #toolbarContainer #loadingBar { + top: calc(var(--toolbar-height) + var(--pfn-bar-height, 0px)); +} + +#viewsManager { + inset-block-start: calc( + 100% + var(--pfn-bar-height, 0px) + var(--sidebar-block-padding) + ); +} +/*#endif*/ + #sidebarContainer :is(input, button, select) { font: message-box; } diff --git a/web/viewer.html b/web/viewer.html index d02f476986819..9e69f62b2bfa8 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -69,6 +69,8 @@ + + @@ -880,6 +882,10 @@ + + + +
diff --git a/web/viewer.js b/web/viewer.js index 6e21e1f52c2aa..5534294bb691c 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -352,6 +352,14 @@ function getViewerConfiguration() { undoButton: document.getElementById("editorUndoBarUndoButton"), closeButton: document.getElementById("editorUndoBarCloseButton"), }, + ...(typeof PDFJSDev === "undefined" || + PDFJSDev.test("MOZCENTRAL && !GECKOVIEW") + ? { + featuresNotification: document.getElementById( + "pdfFeaturesNotification" + ), + } + : {}), editCommentDialog: { dialog: document.getElementById("commentManagerDialog"), toolbar: document.getElementById("commentManagerToolbar"),