[GeckoView] Add a basic toolbar with a download button for GV (bug 1823164)

This commit is contained in:
Calixte Denizet 2023-04-07 10:28:53 +02:00
parent 65c4a4b3fe
commit 3b147205ba
6 changed files with 186 additions and 5 deletions

View File

@ -264,8 +264,11 @@ function createWebpackConfig(
viewerAlias["web-print_service"] = "web/pdf_print_service.js";
} else if (bundleDefines.MOZCENTRAL) {
if (bundleDefines.GECKOVIEW) {
const gvAlias = {
"web-toolbar": "web/toolbar-geckoview.js",
};
for (const key in viewerAlias) {
viewerAlias[key] = "web/stubs-geckoview.js";
viewerAlias[key] = gvAlias[key] || "web/stubs-geckoview.js";
}
} else {
viewerAlias["web-print_service"] = "web/firefox_print_service.js";

View File

@ -2234,7 +2234,7 @@ function webViewerInitialized() {
}
if (!PDFViewerApplication.supportsPrinting) {
appConfig.toolbar?.print.classList.add("hidden");
appConfig.toolbar?.print?.classList.add("hidden");
appConfig.secondaryToolbar?.printButton.classList.add("hidden");
}
@ -2243,7 +2243,7 @@ function webViewerInitialized() {
}
if (PDFViewerApplication.supportsIntegratedFind) {
appConfig.toolbar?.viewFind.classList.add("hidden");
appConfig.toolbar?.viewFind?.classList.add("hidden");
}
appConfig.mainContainer.addEventListener(
@ -2917,6 +2917,17 @@ function webViewerTouchEnd(evt) {
}
function webViewerClick(evt) {
if (
typeof PDFJSDev === "undefined"
? window.isGECKOVIEW
: PDFJSDev.test("GECKOVIEW")
) {
if (
document.activeElement === PDFViewerApplication.appConfig.mainContainer
) {
PDFViewerApplication.toolbar?.toggle();
}
}
if (!PDFViewerApplication.secondaryToolbar?.isOpen) {
return;
}

79
web/toolbar-geckoview.js Normal file
View File

@ -0,0 +1,79 @@
/* Copyright 2023 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @typedef {Object} ToolbarOptions
* @property {HTMLDivElement} mainContainer - Main container.
* @property {HTMLDivElement} container - Container for the toolbar.
* @property {HTMLButtonElement} download - Button to download the document.
*/
class Toolbar {
#buttons;
#eventBus;
#toolbar;
#mainContainer;
#toggleBound = this.toggle.bind(this);
/**
* @param {ToolbarOptions} options
* @param {EventBus} eventBus
* @param {IL10n} _l10n - Localization service.
*/
constructor(options, eventBus, _l10n) {
this.#toolbar = options.container;
this.#mainContainer = options.mainContainer;
this.#eventBus = eventBus;
this.#buttons = [{ element: options.download, eventName: "download" }];
// Bind the event listeners for click and various other actions.
this.#bindListeners(options);
}
setPageNumber(pageNumber, pageLabel) {}
setPagesCount(pagesCount, hasPageLabels) {}
setPageScale(pageScaleValue, pageScale) {}
reset() {}
#bindListeners(options) {
// The buttons within the toolbar.
for (const { element, eventName, eventDetails } of this.#buttons) {
element.addEventListener("click", evt => {
if (eventName !== null) {
this.#eventBus.dispatch(eventName, { source: this, ...eventDetails });
}
});
}
}
updateLoadingIndicatorState(loading = false) {}
toggle() {
if (this.#toolbar.classList.toggle("show")) {
this.#mainContainer.addEventListener("scroll", this.#toggleBound);
} else {
this.#mainContainer.removeEventListener("scroll", this.#toggleBound);
}
}
}
export { Toolbar };

View File

@ -29,6 +29,8 @@
--dialog-button-border: none;
--dialog-button-bg-color: rgba(12, 12, 13, 0.1);
--dialog-button-hover-bg-color: rgba(12, 12, 13, 0.3);
--toolbarButton-download-icon: url(images/toolbarButton-download.svg);
}
:root:dir(rtl) {
@ -149,6 +151,80 @@ body {
border-color: #0a84ff;
}
#floatingToolbar {
position: absolute;
width: 40px;
height: auto;
bottom: 5%;
right: 5%;
background-color: transparent;
z-index: 100000;
}
#floatingToolbar.show {
display: block;
}
#floatingToolbar:not(show) {
display: none;
}
.toolbarButton {
margin: 2px;
padding: 8px;
border-style: solid;
border-width: 1px;
border-color: transparent;
border-radius: 19px;
user-select: none;
box-sizing: border-box;
background-color: transparent;
backdrop-filter: blur(20px) contrast(100%) invert(100%);
width: 38px;
height: 38px;
outline: none;
position: relative;
}
.toolbarButton > span {
display: inline-block;
width: 0;
height: 0;
overflow: hidden;
}
.toolbarButton[disabled],
.dialogButton[disabled] {
opacity: 0.5;
}
.toolbarButton:hover,
.toolbarButton:focus-visible {
backdrop-filter: blur(20px) contrast(200%) invert(100%);
}
.toolbarButton::before {
display: inline-block;
width: 100%;
height: 100%;
content: "";
background-color: transparent;
backdrop-filter: invert(100%);
mask-size: cover;
}
.toolbarButton::before {
opacity: var(--toolbar-icon-opacity);
}
.toolbarButton:hover::before {
backdrop-filter: invert(60%);
}
#download::before {
mask-image: var(--toolbarButton-download-icon);
}
.dialogButton {
width: auto;
margin: 3px 4px 2px !important;

View File

@ -64,7 +64,7 @@ See https://github.com/adobe-type-tools/cmap-resources
"web-pdf_thumbnail_viewer": "./stubs-geckoview.js",
"web-print_service": "./stubs-geckoview.js",
"web-secondary_toolbar": "./stubs-geckoview.js",
"web-toolbar": "./stubs-geckoview.js"
"web-toolbar": "./toolbar-geckoview.js"
}
}
</script>
@ -103,6 +103,12 @@ See https://github.com/adobe-type-tools/cmap-resources
</div> <!-- outerContainer -->
<div id="floatingToolbar">
<button id="download" class="toolbarButton" title="Save" tabindex="31" data-l10n-id="save">
<span data-l10n-id="save_label">Save</span>
</button>
</div>
<!--#if !MOZCENTRAL-->
<input type="file" id="fileInput" class="hidden">
<!--#endif-->

View File

@ -36,10 +36,16 @@ window.PDFViewerApplicationConstants = AppConstants;
window.PDFViewerApplicationOptions = AppOptions;
function getViewerConfiguration() {
const mainContainer = document.getElementById("viewerContainer");
return {
appContainer: document.body,
mainContainer: document.getElementById("viewerContainer"),
mainContainer,
viewerContainer: document.getElementById("viewer"),
toolbar: {
mainContainer,
container: document.getElementById("floatingToolbar"),
download: document.getElementById("download"),
},
passwordOverlay: {
dialog: document.getElementById("passwordDialog"),