[GV] Add a viewer for GeckoView

This commit is contained in:
Calixte Denizet 2022-12-14 16:40:25 +01:00
parent 8587ce6afd
commit f19572c4cc
6 changed files with 763 additions and 134 deletions

View File

@ -103,6 +103,7 @@ const DEFINES = Object.freeze({
// The main build targets:
GENERIC: false,
MOZCENTRAL: false,
GECKOVIEW: false,
CHROME: false,
MINIFIED: false,
COMPONENTS: false,
@ -477,6 +478,25 @@ function createWebBundle(defines, options) {
.pipe(replaceNonWebpackImport());
}
function createGVWebBundle(defines, options) {
const viewerOutputName = "viewer-geckoview.js";
defines = builder.merge(defines, { GECKOVIEW: true });
const viewerFileConfig = createWebpackConfig(
defines,
{
filename: viewerOutputName,
},
{
defaultPreferencesDir: options.defaultPreferencesDir,
}
);
return gulp
.src("./web/viewer-geckoview.js")
.pipe(webpack2Stream(viewerFileConfig))
.pipe(replaceNonWebpackImport());
}
function createComponentsBundle(defines) {
const componentsAMDName = "pdfjs-dist/web/pdf_viewer";
const componentsOutputName = "pdf_viewer.js";
@ -1291,6 +1311,9 @@ gulp.task(
createWebBundle(defines, { defaultPreferencesDir: "mozcentral/" }).pipe(
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")
),
createGVWebBundle(defines, {
defaultPreferencesDir: "mozcentral/",
}).pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),
gulp
.src(MOZCENTRAL_WEB_FILES, { base: "web/" })
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),
@ -1304,6 +1327,10 @@ gulp.task(
preprocessHTML("web/viewer.html", defines).pipe(
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")
),
preprocessHTML("web/viewer-geckoview.html", defines).pipe(
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")
),
preprocessCSS("web/viewer.css", defines)
.pipe(
postcss([
@ -1314,6 +1341,16 @@ gulp.task(
)
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),
preprocessCSS("web/viewer-geckoview.css", defines)
.pipe(
postcss([
autoprefixer({
overrideBrowserslist: ["last 1 firefox versions"],
}),
])
)
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),
gulp
.src("l10n/en-US/*.properties")
.pipe(gulp.dest(MOZCENTRAL_L10N_DIR)),

View File

@ -510,15 +510,17 @@ const PDFViewerApplication = {
pdfLinkService.setViewer(this.pdfViewer);
pdfScriptingManager.setViewer(this.pdfViewer);
this.pdfThumbnailViewer = new PDFThumbnailViewer({
container: appConfig.sidebar.thumbnailView,
eventBus,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService,
l10n: this.l10n,
pageColors,
});
pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
if (appConfig.sidebar?.thumbnailView) {
this.pdfThumbnailViewer = new PDFThumbnailViewer({
container: appConfig.sidebar.thumbnailView,
eventBus,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService,
l10n: this.l10n,
pageColors,
});
pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
}
// The browsing history is only enabled when the viewer is standalone,
// i.e. not when it is embedded in a web page.
@ -530,33 +532,37 @@ const PDFViewerApplication = {
pdfLinkService.setHistory(this.pdfHistory);
}
if (!this.supportsIntegratedFind) {
if (appConfig.findBar && !this.supportsIntegratedFind) {
this.findBar = new PDFFindBar(appConfig.findBar, eventBus, this.l10n);
}
if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
this.annotationEditorParams = new AnnotationEditorParams(
appConfig.annotationEditorParams,
eventBus
);
} else {
for (const element of [
document.getElementById("editorModeButtons"),
document.getElementById("editorModeSeparator"),
]) {
element.hidden = true;
if (appConfig.annotationEditorParams) {
if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
this.annotationEditorParams = new AnnotationEditorParams(
appConfig.annotationEditorParams,
eventBus
);
} else {
for (const element of [
document.getElementById("editorModeButtons"),
document.getElementById("editorModeSeparator"),
]) {
element.hidden = true;
}
}
}
this.pdfDocumentProperties = new PDFDocumentProperties(
appConfig.documentProperties,
this.overlayManager,
eventBus,
this.l10n,
/* fileNameLookup = */ () => {
return this._docFilename;
}
);
if (appConfig.documentProperties) {
this.pdfDocumentProperties = new PDFDocumentProperties(
appConfig.documentProperties,
this.overlayManager,
eventBus,
this.l10n,
/* fileNameLookup = */ () => {
return this._docFilename;
}
);
}
this.pdfCursorTools = new PDFCursorTools({
container,
@ -564,13 +570,17 @@ const PDFViewerApplication = {
cursorToolOnLoad: AppOptions.get("cursorToolOnLoad"),
});
this.toolbar = new Toolbar(appConfig.toolbar, eventBus, this.l10n);
if (appConfig.toolbar) {
this.toolbar = new Toolbar(appConfig.toolbar, eventBus, this.l10n);
}
this.secondaryToolbar = new SecondaryToolbar(
appConfig.secondaryToolbar,
eventBus,
this.externalServices
);
if (appConfig.secondaryToolbar) {
this.secondaryToolbar = new SecondaryToolbar(
appConfig.secondaryToolbar,
eventBus,
this.externalServices
);
}
if (this.supportsFullscreen) {
this.pdfPresentationMode = new PDFPresentationMode({
@ -580,46 +590,56 @@ const PDFViewerApplication = {
});
}
this.passwordPrompt = new PasswordPrompt(
appConfig.passwordOverlay,
this.overlayManager,
this.l10n,
this.isViewerEmbedded
);
if (appConfig.passwordOverlay) {
this.passwordPrompt = new PasswordPrompt(
appConfig.passwordOverlay,
this.overlayManager,
this.l10n,
this.isViewerEmbedded
);
}
this.pdfOutlineViewer = new PDFOutlineViewer({
container: appConfig.sidebar.outlineView,
eventBus,
linkService: pdfLinkService,
downloadManager,
});
if (appConfig.sidebar?.outlineView) {
this.pdfOutlineViewer = new PDFOutlineViewer({
container: appConfig.sidebar.outlineView,
eventBus,
linkService: pdfLinkService,
downloadManager,
});
}
this.pdfAttachmentViewer = new PDFAttachmentViewer({
container: appConfig.sidebar.attachmentsView,
eventBus,
downloadManager,
});
if (appConfig.sidebar?.attachmentsView) {
this.pdfAttachmentViewer = new PDFAttachmentViewer({
container: appConfig.sidebar.attachmentsView,
eventBus,
downloadManager,
});
}
this.pdfLayerViewer = new PDFLayerViewer({
container: appConfig.sidebar.layersView,
eventBus,
l10n: this.l10n,
});
if (appConfig.sidebar?.layersView) {
this.pdfLayerViewer = new PDFLayerViewer({
container: appConfig.sidebar.layersView,
eventBus,
l10n: this.l10n,
});
}
this.pdfSidebar = new PDFSidebar({
elements: appConfig.sidebar,
pdfViewer: this.pdfViewer,
pdfThumbnailViewer: this.pdfThumbnailViewer,
eventBus,
l10n: this.l10n,
});
this.pdfSidebar.onToggled = this.forceRendering.bind(this);
if (appConfig.sidebar) {
this.pdfSidebar = new PDFSidebar({
elements: appConfig.sidebar,
pdfViewer: this.pdfViewer,
pdfThumbnailViewer: this.pdfThumbnailViewer,
eventBus,
l10n: this.l10n,
});
this.pdfSidebar.onToggled = this.forceRendering.bind(this);
this.pdfSidebarResizer = new PDFSidebarResizer(
appConfig.sidebarResizer,
eventBus,
this.l10n
);
this.pdfSidebarResizer = new PDFSidebarResizer(
appConfig.sidebarResizer,
eventBus,
this.l10n
);
}
},
run(config) {
@ -684,7 +704,8 @@ const PDFViewerApplication = {
},
get loadingBar() {
const bar = new ProgressBar("loadingBar");
const barElement = document.getElementById("loadingBar");
const bar = barElement ? new ProgressBar(barElement) : null;
return shadow(this, "loadingBar", bar);
},
@ -816,10 +837,10 @@ const PDFViewerApplication = {
if (this.pdfDocument) {
this.pdfDocument = null;
this.pdfThumbnailViewer.setDocument(null);
this.pdfThumbnailViewer?.setDocument(null);
this.pdfViewer.setDocument(null);
this.pdfLinkService.setDocument(null);
this.pdfDocumentProperties.setDocument(null);
this.pdfDocumentProperties?.setDocument(null);
}
this.pdfLinkService.externalLinkEnabled = true;
this.store = null;
@ -838,15 +859,15 @@ const PDFViewerApplication = {
promises.push(this.pdfScriptingManager.destroyPromise);
this.setTitle();
this.pdfSidebar.reset();
this.pdfOutlineViewer.reset();
this.pdfAttachmentViewer.reset();
this.pdfLayerViewer.reset();
this.pdfSidebar?.reset();
this.pdfOutlineViewer?.reset();
this.pdfAttachmentViewer?.reset();
this.pdfLayerViewer?.reset();
this.pdfHistory?.reset();
this.findBar?.reset();
this.toolbar.reset();
this.secondaryToolbar.reset();
this.toolbar?.reset();
this.secondaryToolbar?.reset();
this._PDFBug?.cleanup();
await Promise.all(promises);
@ -1063,7 +1084,7 @@ const PDFViewerApplication = {
},
progress(level) {
if (this.downloadComplete) {
if (!this.loadingBar || this.downloadComplete) {
// Don't accidentally show the loading bar again when the entire file has
// already been fetched (only an issue when disableAutoFetch is enabled).
return;
@ -1108,7 +1129,7 @@ const PDFViewerApplication = {
pdfDocument.getDownloadInfo().then(({ length }) => {
this._contentLength = length; // Ensure that the correct length is used.
this.downloadComplete = true;
this.loadingBar.hide();
this.loadingBar?.hide();
firstPagePromise.then(() => {
this.eventBus.dispatch("documentloaded", { source: this });
@ -1127,8 +1148,8 @@ const PDFViewerApplication = {
/* Avoid breaking initial rendering; ignoring errors. */
});
this.toolbar.setPagesCount(pdfDocument.numPages, false);
this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
this.toolbar?.setPagesCount(pdfDocument.numPages, false);
this.secondaryToolbar?.setPagesCount(pdfDocument.numPages);
let baseDocumentUrl;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
@ -1144,14 +1165,13 @@ const PDFViewerApplication = {
baseDocumentUrl = null;
}
this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);
this.pdfDocumentProperties.setDocument(pdfDocument);
this.pdfDocumentProperties?.setDocument(pdfDocument);
const pdfViewer = this.pdfViewer;
pdfViewer.setDocument(pdfDocument);
const { firstPagePromise, onePageRendered, pagesPromise } = pdfViewer;
const pdfThumbnailViewer = this.pdfThumbnailViewer;
pdfThumbnailViewer.setDocument(pdfDocument);
this.pdfThumbnailViewer?.setDocument(pdfDocument);
const storedPromise = (this.store = new ViewHistory(
pdfDocument.fingerprints[0]
@ -1172,7 +1192,7 @@ const PDFViewerApplication = {
});
firstPagePromise.then(pdfPage => {
this.loadingBar.setWidth(this.appConfig.viewerContainer);
this.loadingBar?.setWidth(this.appConfig.viewerContainer);
this._initializeAnnotationStorageCallbacks(pdfDocument);
Promise.all([
@ -1308,13 +1328,13 @@ const PDFViewerApplication = {
if (pdfDocument !== this.pdfDocument) {
return; // The document was closed while the outline resolved.
}
this.pdfOutlineViewer.render({ outline, pdfDocument });
this.pdfOutlineViewer?.render({ outline, pdfDocument });
});
pdfDocument.getAttachments().then(attachments => {
if (pdfDocument !== this.pdfDocument) {
return; // The document was closed while the attachments resolved.
}
this.pdfAttachmentViewer.render({ attachments });
this.pdfAttachmentViewer?.render({ attachments });
});
// Ensure that the layers accurately reflects the current state in the
// viewer itself, rather than the default state provided by the API.
@ -1322,7 +1342,7 @@ const PDFViewerApplication = {
if (pdfDocument !== this.pdfDocument) {
return; // The document was closed while the layers resolved.
}
this.pdfLayerViewer.render({ optionalContentConfig, pdfDocument });
this.pdfLayerViewer?.render({ optionalContentConfig, pdfDocument });
});
});
@ -1515,12 +1535,12 @@ const PDFViewerApplication = {
const { pdfViewer, pdfThumbnailViewer, toolbar } = this;
pdfViewer.setPageLabels(labels);
pdfThumbnailViewer.setPageLabels(labels);
pdfThumbnailViewer?.setPageLabels(labels);
// Changing toolbar page display to use labels and we need to set
// the label of the current page.
toolbar.setPagesCount(numLabels, true);
toolbar.setPageNumber(
toolbar?.setPagesCount(numLabels, true);
toolbar?.setPageNumber(
pdfViewer.currentPageNumber,
pdfViewer.currentPageLabel
);
@ -1612,7 +1632,7 @@ const PDFViewerApplication = {
}
};
this.isInitialViewSet = true;
this.pdfSidebar.setInitialView(sidebarView);
this.pdfSidebar?.setInitialView(sidebarView);
setViewerModes(scrollMode, spreadMode);
@ -1630,11 +1650,11 @@ const PDFViewerApplication = {
// Ensure that the correct page number is displayed in the UI,
// even if the active page didn't change during document load.
this.toolbar.setPageNumber(
this.toolbar?.setPageNumber(
this.pdfViewer.currentPageNumber,
this.pdfViewer.currentPageLabel
);
this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber);
this.secondaryToolbar?.setPageNumber(this.pdfViewer.currentPageNumber);
if (!this.pdfViewer.currentScaleValue) {
// Scale was not initialized: invalid bookmark or scale was not specified.
@ -1651,7 +1671,7 @@ const PDFViewerApplication = {
return; // run cleanup when document is loaded
}
this.pdfViewer.cleanup();
this.pdfThumbnailViewer.cleanup();
this.pdfThumbnailViewer?.cleanup();
if (
typeof PDFJSDev === "undefined" ||
@ -1669,7 +1689,7 @@ const PDFViewerApplication = {
forceRendering() {
this.pdfRenderingQueue.printing = !!this.printService;
this.pdfRenderingQueue.isThumbnailViewEnabled =
this.pdfSidebar.visibleView === SidebarView.THUMBS;
this.pdfSidebar?.visibleView === SidebarView.THUMBS;
this.pdfRenderingQueue.renderHighestPriority();
},
@ -2151,16 +2171,16 @@ function webViewerInitialized() {
}
if (!PDFViewerApplication.supportsPrinting) {
appConfig.toolbar.print.classList.add("hidden");
appConfig.secondaryToolbar.printButton.classList.add("hidden");
appConfig.toolbar?.print.classList.add("hidden");
appConfig.secondaryToolbar?.printButton.classList.add("hidden");
}
if (!PDFViewerApplication.supportsFullscreen) {
if (appConfig.secondaryToolbar && !PDFViewerApplication.supportsFullscreen) {
appConfig.secondaryToolbar.presentationModeButton.hidden = true;
}
if (PDFViewerApplication.supportsIntegratedFind) {
appConfig.toolbar.viewFind.classList.add("hidden");
appConfig.toolbar?.viewFind.classList.add("hidden");
}
appConfig.mainContainer.addEventListener(
@ -2197,15 +2217,15 @@ function webViewerPageRendered({ pageNumber, error }) {
// If the page is still visible when it has finished rendering,
// ensure that the page number input loading indicator is hidden.
if (pageNumber === PDFViewerApplication.page) {
PDFViewerApplication.toolbar.updateLoadingIndicatorState(false);
PDFViewerApplication.toolbar?.updateLoadingIndicatorState(false);
}
// Use the rendered page to set the corresponding thumbnail image.
if (PDFViewerApplication.pdfSidebar.visibleView === SidebarView.THUMBS) {
if (PDFViewerApplication.pdfSidebar?.visibleView === SidebarView.THUMBS) {
const pageView = PDFViewerApplication.pdfViewer.getPageView(
/* index = */ pageNumber - 1
);
const thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(
const thumbnailView = PDFViewerApplication.pdfThumbnailViewer?.getThumbnail(
/* index = */ pageNumber - 1
);
if (pageView && thumbnailView) {
@ -2244,7 +2264,7 @@ function webViewerPageMode({ mode }) {
console.error('Invalid "pagemode" hash parameter: ' + mode);
return;
}
PDFViewerApplication.pdfSidebar.switchView(view, /* forceOpen = */ true);
PDFViewerApplication.pdfSidebar?.switchView(view, /* forceOpen = */ true);
}
function webViewerNamedAction(evt) {
@ -2252,12 +2272,12 @@ function webViewerNamedAction(evt) {
// `PDFLinkService.executeNamedAction`.
switch (evt.action) {
case "GoToPage":
PDFViewerApplication.appConfig.toolbar.pageNumber.select();
PDFViewerApplication.appConfig.toolbar?.pageNumber.select();
break;
case "Find":
if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.toggle();
PDFViewerApplication?.findBar.toggle();
}
break;
@ -2305,15 +2325,17 @@ function webViewerUpdateViewarea({ location }) {
const href = PDFViewerApplication.pdfLinkService.getAnchorUrl(
location.pdfOpenParams
);
PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href =
href;
if (PDFViewerApplication.appConfig.secondaryToolbar) {
PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href =
href;
}
// Show/hide the loading indicator in the page number input element.
const currentPage = PDFViewerApplication.pdfViewer.getPageView(
/* index = */ PDFViewerApplication.page - 1
);
const loading = currentPage?.renderingState !== RenderingStates.FINISHED;
PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading);
PDFViewerApplication.toolbar?.updateLoadingIndicatorState(loading);
}
function webViewerScrollModeChanged(evt) {
@ -2452,7 +2474,7 @@ function webViewerPageNumberChanged(evt) {
evt.value !== pdfViewer.currentPageNumber.toString() &&
evt.value !== pdfViewer.currentPageLabel
) {
PDFViewerApplication.toolbar.setPageNumber(
PDFViewerApplication.toolbar?.setPageNumber(
pdfViewer.currentPageNumber,
pdfViewer.currentPageLabel
);
@ -2477,7 +2499,7 @@ function webViewerSwitchSpreadMode(evt) {
PDFViewerApplication.pdfViewer.spreadMode = evt.mode;
}
function webViewerDocumentProperties() {
PDFViewerApplication.pdfDocumentProperties.open();
PDFViewerApplication.pdfDocumentProperties?.open();
}
function webViewerFindFromUrlHash(evt) {
@ -2516,18 +2538,20 @@ function webViewerUpdateFindControlState({
rawQuery,
});
} else {
PDFViewerApplication.findBar.updateUIState(state, previous, matchesCount);
PDFViewerApplication.findBar?.updateUIState(state, previous, matchesCount);
}
}
function webViewerScaleChanging(evt) {
PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale);
PDFViewerApplication.toolbar?.setPageScale(evt.presetValue, evt.scale);
PDFViewerApplication.pdfViewer.update();
}
function webViewerRotationChanging(evt) {
PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation;
if (PDFViewerApplication.pdfThumbnailViewer) {
PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation;
}
PDFViewerApplication.forceRendering();
// Ensure that the active page doesn't change during rotation.
@ -2535,11 +2559,13 @@ function webViewerRotationChanging(evt) {
}
function webViewerPageChanging({ pageNumber, pageLabel }) {
PDFViewerApplication.toolbar.setPageNumber(pageNumber, pageLabel);
PDFViewerApplication.secondaryToolbar.setPageNumber(pageNumber);
PDFViewerApplication.toolbar?.setPageNumber(pageNumber, pageLabel);
PDFViewerApplication.secondaryToolbar?.setPageNumber(pageNumber);
if (PDFViewerApplication.pdfSidebar.visibleView === SidebarView.THUMBS) {
PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(pageNumber);
if (PDFViewerApplication.pdfSidebar?.visibleView === SidebarView.THUMBS) {
PDFViewerApplication.pdfThumbnailViewer?.scrollThumbnailIntoView(
pageNumber
);
}
}
@ -2652,14 +2678,14 @@ function webViewerTouchStart(evt) {
}
function webViewerClick(evt) {
if (!PDFViewerApplication.secondaryToolbar.isOpen) {
if (!PDFViewerApplication.secondaryToolbar?.isOpen) {
return;
}
const appConfig = PDFViewerApplication.appConfig;
if (
PDFViewerApplication.pdfViewer.containsElement(evt.target) ||
(appConfig.toolbar.container.contains(evt.target) &&
evt.target !== appConfig.secondaryToolbar.toggleButton)
(appConfig.toolbar?.container.contains(evt.target) &&
evt.target !== appConfig.secondaryToolbar?.toggleButton)
) {
PDFViewerApplication.secondaryToolbar.close();
}
@ -2687,7 +2713,7 @@ function webViewerKeyDown(evt) {
switch (evt.keyCode) {
case 70: // f
if (!PDFViewerApplication.supportsIntegratedFind && !evt.shiftKey) {
PDFViewerApplication.findBar.open();
PDFViewerApplication.findBar?.open();
handled = true;
}
break;
@ -2786,8 +2812,10 @@ function webViewerKeyDown(evt) {
break;
case 71: // g
// focuses input#pageNumber field
PDFViewerApplication.appConfig.toolbar.pageNumber.select();
handled = true;
if (PDFViewerApplication.appConfig.toolbar) {
PDFViewerApplication.appConfig.toolbar.pageNumber.select();
handled = true;
}
break;
}
}
@ -2846,13 +2874,13 @@ function webViewerKeyDown(evt) {
turnPage = -1;
break;
case 27: // esc key
if (PDFViewerApplication.secondaryToolbar.isOpen) {
if (PDFViewerApplication.secondaryToolbar?.isOpen) {
PDFViewerApplication.secondaryToolbar.close();
handled = true;
}
if (
!PDFViewerApplication.supportsIntegratedFind &&
PDFViewerApplication.findBar.opened
PDFViewerApplication.findBar?.opened
) {
PDFViewerApplication.findBar.close();
handled = true;
@ -2903,10 +2931,10 @@ function webViewerKeyDown(evt) {
break;
case 83: // 's'
PDFViewerApplication.pdfCursorTools.switchTool(CursorTool.SELECT);
PDFViewerApplication.pdfCursorTools?.switchTool(CursorTool.SELECT);
break;
case 72: // 'h'
PDFViewerApplication.pdfCursorTools.switchTool(CursorTool.HAND);
PDFViewerApplication.pdfCursorTools?.switchTool(CursorTool.HAND);
break;
case 82: // 'r'
@ -2914,7 +2942,7 @@ function webViewerKeyDown(evt) {
break;
case 115: // F4
PDFViewerApplication.pdfSidebar.toggle();
PDFViewerApplication.pdfSidebar?.toggle();
break;
}

View File

@ -697,8 +697,7 @@ class ProgressBar {
#visible = true;
constructor(id) {
const bar = document.getElementById(id);
constructor(bar) {
this.#classList = bar.classList;
}

367
web/viewer-geckoview.css Normal file
View File

@ -0,0 +1,367 @@
/* Copyright 2014 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.
*/
@import url(pdf_viewer.css);
:root {
--dir-factor: 1;
--scale-select-width: 140px;
--toolbar-icon-opacity: 0.7;
--doorhanger-icon-opacity: 0.9;
--main-color: rgba(12, 12, 13, 1);
--body-bg-color: rgba(237, 237, 240, 1);
--scrollbar-color: auto;
--scrollbar-bg-color: auto;
--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);
}
:root:dir(rtl) {
--dir-factor: -1;
}
@media (prefers-color-scheme: dark) {
:root {
--main-color: rgba(249, 249, 250, 1);
--body-bg-color: rgba(42, 42, 46, 1);
--progressBar-color: rgba(0, 96, 223, 1);
--progressBar-indeterminate-bg-color: rgba(40, 40, 43, 1);
--progressBar-indeterminate-blend-color: rgba(20, 68, 133, 1);
--scrollbar-color: rgba(121, 121, 123, 1);
--scrollbar-bg-color: rgba(35, 35, 39, 1);
--dialog-button-bg-color: rgba(92, 92, 97, 1);
--dialog-button-hover-bg-color: rgba(115, 115, 115, 1);
}
}
@media screen and (forced-colors: active) {
:root {
--dialog-button-border: 1px solid Highlight;
--dialog-button-hover-bg-color: Highlight;
--dialog-button-hover-color: ButtonFace;
--main-color: CanvasText;
}
}
* {
padding: 0;
margin: 0;
}
html,
body {
height: 100%;
width: 100%;
}
body {
background-color: var(--body-bg-color);
scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color);
}
.hidden,
[hidden] {
display: none !important;
}
#outerContainer {
width: 100%;
height: 100%;
position: relative;
}
#mainContainer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
min-width: 350px;
}
#viewerContainer {
overflow: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
outline: none;
}
#viewerContainer {
transition-duration: var(--sidebar-transition-duration);
transition-timing-function: var(--sidebar-transition-timing-function);
}
.dialogButton {
border: none;
background: none;
width: 28px;
height: 28px;
outline: none;
}
.dialogButton:hover,
.dialogButton:focus-visible {
background-color: var(--dialog-button-hover-bg-color);
}
.dialogButton:hover > span,
.dialogButton:focus-visible > span {
color: var(--dialog-button-hover-color);
}
.dialogButton[disabled] {
opacity: 0.5;
}
.dialogButton {
min-width: 16px;
margin: 2px 1px;
padding: 2px 6px 0;
border: none;
border-radius: 2px;
color: var(--main-color);
font-size: 12px;
line-height: 14px;
user-select: none;
cursor: default;
box-sizing: border-box;
}
.toolbarField {
padding: 4px 7px;
margin: 3px 0;
border-radius: 2px;
background-color: var(--field-bg-color);
background-clip: padding-box;
border: 1px solid var(--field-border-color);
box-shadow: none;
color: var(--field-color);
font-size: 12px;
line-height: 16px;
outline: none;
}
.toolbarField:focus {
border-color: #0a84ff;
}
.dialogButton {
width: auto;
margin: 3px 4px 2px !important;
padding: 2px 11px;
color: var(--main-color);
background-color: var(--dialog-button-bg-color);
border: var(--dialog-button-border) !important;
}
dialog {
margin: auto;
padding: 15px;
border-spacing: 4px;
color: var(--main-color);
font: message-box;
font-size: 12px;
line-height: 14px;
background-color: var(--doorhanger-bg-color);
border: 1px solid rgba(0, 0, 0, 0.5);
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.2);
}
dialog > .row {
display: table-row;
}
dialog > .row > * {
display: table-cell;
}
dialog .toolbarField {
margin: 5px 0;
}
dialog .separator {
display: block;
margin: 4px 0;
height: 1px;
width: 100%;
background-color: var(--separator-color);
}
dialog .buttonRow {
text-align: center;
vertical-align: middle;
}
dialog :link {
color: rgba(255, 255, 255, 1);
}
#passwordDialog {
text-align: center;
}
#passwordDialog .toolbarField {
width: 200px;
}
.grab-to-pan-grab {
cursor: grab !important;
}
.grab-to-pan-grab
*:not(input):not(textarea):not(button):not(select):not(:link) {
cursor: inherit !important;
}
.grab-to-pan-grab:active,
.grab-to-pan-grabbing {
cursor: grabbing !important;
position: fixed;
background: rgba(0, 0, 0, 0);
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 50000; /* should be higher than anything else in PDF.js! */
}
@page {
margin: 0;
}
#printContainer {
display: none;
}
@media print {
body {
background: rgba(0, 0, 0, 0) none;
}
body[data-pdfjsprinting] #outerContainer {
display: none;
}
body[data-pdfjsprinting] #printContainer {
display: block;
}
#printContainer {
height: 100%;
}
/* wrapper around (scaled) print canvas elements */
#printContainer > .printedPage {
page-break-after: always;
page-break-inside: avoid;
/* The wrapper always cover the whole page. */
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#printContainer > .xfaPrintedPage .xfaPage {
position: absolute;
}
#printContainer > .xfaPrintedPage {
page-break-after: always;
page-break-inside: avoid;
width: 100%;
height: 100%;
position: relative;
}
#printContainer > .printedPage canvas,
#printContainer > .printedPage img {
/* The intrinsic canvas / image size will make sure that we fit the page. */
max-width: 100%;
max-height: 100%;
direction: ltr;
display: block;
}
}
.visibleLargeView,
.visibleMediumView {
display: none;
}
@media all and (max-width: 900px) {
#toolbarViewerMiddle {
display: table;
margin: auto;
left: auto;
position: inherit;
transform: none;
}
}
@media all and (max-width: 840px) {
#sidebarContainer {
background-color: var(--sidebar-narrow-bg-color);
}
#outerContainer.sidebarOpen #viewerContainer {
inset-inline-start: 0 !important;
}
}
@media all and (max-width: 820px) {
#outerContainer .hiddenLargeView {
display: none;
}
#outerContainer .visibleLargeView {
display: inherit;
}
}
@media all and (max-width: 750px) {
#outerContainer .hiddenMediumView {
display: none;
}
#outerContainer .visibleMediumView {
display: inherit;
}
}
@media all and (max-width: 690px) {
.hiddenSmallView,
.hiddenSmallView * {
display: none;
}
.toolbarButtonSpacer {
width: 0;
}
.findbar {
inset-inline-start: 34px;
}
}
@media all and (max-width: 560px) {
#scaleSelectContainer {
display: none;
}
}

96
web/viewer-geckoview.html Normal file
View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<!--
Copyright 2012 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.
Adobe CMap resources are covered by their own copyright but the same license:
Copyright 1990-2015 Adobe Systems Incorporated.
See https://github.com/adobe-type-tools/cmap-resources
-->
<html dir="ltr" mozdisallowselectionprint>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>PDF.js viewer</title>
<!--#if MOZCENTRAL-->
<!--#include viewer-snippet-firefox-extension.html-->
<!--#endif-->
<!--#if MOZCENTRAL-->
<!--<link rel="stylesheet" href="viewer.css">-->
<!--#else-->
<link rel="stylesheet" href="viewer-geckoview.css">
<!--#endif-->
<!--#if !MOZCENTRAL-->
<link rel="resource" type="application/l10n" href="locale/locale.properties">
<!--#endif-->
<!--#if !MOZCENTRAL-->
<script defer src="../node_modules/es-module-shims/dist/es-module-shims.js"></script>
<script type="importmap-shim">
{
"imports": {
"pdfjs/": "../src/",
"pdfjs-lib": "../src/pdf.js",
"pdfjs-web/": "./",
"pdfjs-fitCurve": "../build/dev-fitCurve/fit_curve.js"
}
}
</script>
<script src="viewer-geckoview.js" type="module-shim"></script>
<!--#else-->
<!--<script src="viewer.js"></script>-->
<!--#endif-->
</head>
<body tabindex="1">
<div id="outerContainer">
<div id="mainContainer">
<div id="viewerContainer" tabindex="0">
<div id="viewer" class="pdfViewer"></div>
</div>
</div> <!-- mainContainer -->
<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 class="row">
<input type="password" id="password" class="toolbarField">
</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>
</div> <!-- dialogContainer -->
</div> <!-- outerContainer -->
<div id="printContainer"></div>
<!--#if !MOZCENTRAL-->
<input type="file" id="fileInput" class="hidden">
<!--#endif-->
</body>
</html>

102
web/viewer-geckoview.js Normal file
View File

@ -0,0 +1,102 @@
/* Copyright 2016 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.
*/
import { RenderingStates, ScrollMode, SpreadMode } from "./ui_utils.js";
import { AppOptions } from "./app_options.js";
import { LinkTarget } from "./pdf_link_service.js";
import { PDFViewerApplication } from "./app.js";
/* eslint-disable-next-line no-unused-vars */
const pdfjsVersion =
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_VERSION") : void 0;
/* eslint-disable-next-line no-unused-vars */
const pdfjsBuild =
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;
const AppConstants =
typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")
? { LinkTarget, RenderingStates, ScrollMode, SpreadMode }
: null;
window.PDFViewerApplication = PDFViewerApplication;
window.PDFViewerApplicationConstants = AppConstants;
window.PDFViewerApplicationOptions = AppOptions;
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
require("./firefoxcom.js");
require("./firefox_print_service.js");
}
function getViewerConfiguration() {
return {
appContainer: document.body,
mainContainer: document.getElementById("viewerContainer"),
viewerContainer: document.getElementById("viewer"),
passwordOverlay: {
dialog: document.getElementById("passwordDialog"),
label: document.getElementById("passwordText"),
input: document.getElementById("password"),
submitButton: document.getElementById("passwordSubmit"),
cancelButton: document.getElementById("passwordCancel"),
},
printContainer: document.getElementById("printContainer"),
openFileInput:
typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")
? document.getElementById("fileInput")
: null,
};
}
function webViewerLoad() {
const config = getViewerConfiguration();
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
if (window.chrome) {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "../build/dev-css/viewer.css";
document.head.append(link);
}
Promise.all([
import("pdfjs-web/genericcom.js"),
import("pdfjs-web/pdf_print_service.js"),
]).then(function ([genericCom, pdfPrintService]) {
PDFViewerApplication.run(config);
});
} else {
PDFViewerApplication.run(config);
}
}
// Block the "load" event until all pages are loaded, to ensure that printing
// works in Firefox; see https://bugzilla.mozilla.org/show_bug.cgi?id=1618553
document.blockUnblockOnload?.(true);
if (
document.readyState === "interactive" ||
document.readyState === "complete"
) {
webViewerLoad();
} else {
document.addEventListener("DOMContentLoaded", webViewerLoad, true);
}
export {
PDFViewerApplication,
AppConstants as PDFViewerApplicationConstants,
AppOptions as PDFViewerApplicationOptions,
};