From 6f40ed729bf8b504bb47b1e28c4c26fb4601435f Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Mon, 1 Jul 2024 22:37:48 +0200 Subject: [PATCH] Refactor the toolbar html & css to improve its overall accessibility (bug 1171799, bug 1855695) The first goal of this patch was to remove the tabindex because it helps to improve overall a11y. That led to move some html elements associated with the buttons which helped to position these elements relatively to their buttons. Consequently it was easy to change the toolbar height (configurable in Firefox with the pref browser.uidensity): it's the second goal of this patch. For a11y reasons we want to be able to change the height of the toolbar to make the buttons larger. --- test/integration/find_spec.mjs | 2 +- web/annotation_editor_layer_builder.css | 15 +- web/app.js | 6 +- web/pdf_find_bar.js | 9 +- web/toolbar.js | 10 +- web/viewer-geckoview.html | 4 +- web/viewer.css | 1201 +++++++++++++---------- web/viewer.html | 534 +++++----- web/viewer.js | 1 + 9 files changed, 975 insertions(+), 807 deletions(-) diff --git a/test/integration/find_spec.mjs b/test/integration/find_spec.mjs index 4fca69c5f6412..b73f499aee2cc 100644 --- a/test/integration/find_spec.mjs +++ b/test/integration/find_spec.mjs @@ -43,7 +43,7 @@ describe("find bar", () => { await page.click("#viewFindButton"); await page.waitForSelector("#viewFindButton", { hidden: false }); await page.type("#findInput", "a"); - await page.click("#findHighlightAll"); + await page.click("#findHighlightAll + label"); await page.waitForSelector(".textLayer .highlight"); // The PDF file contains the text 'AB BA' in a monospace font on a diff --git a/web/annotation_editor_layer_builder.css b/web/annotation_editor_layer_builder.css index 3a7be2f8271bf..a5b8d47e18ba0 100644 --- a/web/annotation_editor_layer_builder.css +++ b/web/annotation_editor_layer_builder.css @@ -1227,18 +1227,9 @@ } #highlightParamsToolbarContainer { - height: auto; - padding-inline: 10px; - padding-block: 10px 16px; gap: 16px; - display: flex; - flex-direction: column; - box-sizing: border-box; - - .editorParamsLabel { - width: fit-content; - inset-inline-start: 0; - } + padding-inline: 10px; + padding-block-end: 12px; .colorPicker { display: flex; @@ -1262,6 +1253,7 @@ align-items: center; background: none; flex: 0 0 auto; + padding: 0; .swatch { width: 24px; @@ -1291,7 +1283,6 @@ align-self: stretch; .editorParamsLabel { - width: 100%; height: auto; align-self: stretch; } diff --git a/web/app.js b/web/app.js index 5812e80ced432..2f18b60498cba 100644 --- a/web/app.js +++ b/web/app.js @@ -516,7 +516,11 @@ const PDFViewerApplication = { } if (!this.supportsIntegratedFind && appConfig.findBar) { - this.findBar = new PDFFindBar(appConfig.findBar, eventBus); + this.findBar = new PDFFindBar( + appConfig.findBar, + appConfig.principalContainer, + eventBus + ); } if (appConfig.annotationEditorParams) { diff --git a/web/pdf_find_bar.js b/web/pdf_find_bar.js index 72147799af567..44787f2505a9b 100644 --- a/web/pdf_find_bar.js +++ b/web/pdf_find_bar.js @@ -25,9 +25,11 @@ const MATCHES_COUNT_LIMIT = 1000; * is done by PDFFindController. */ class PDFFindBar { + #mainContainer; + #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this)); - constructor(options, eventBus) { + constructor(options, mainContainer, eventBus) { this.opened = false; this.bar = options.bar; @@ -42,6 +44,7 @@ class PDFFindBar { this.findPreviousButton = options.findPreviousButton; this.findNextButton = options.findNextButton; this.eventBus = eventBus; + this.#mainContainer = mainContainer; // Add event listeners to the DOM elements. this.toggleButton.addEventListener("click", () => { @@ -170,7 +173,7 @@ class PDFFindBar { // - The width of the viewer itself changes. // - The width of the findbar changes, by toggling the visibility // (or localization) of find count/status messages. - this.#resizeObserver.observe(this.bar.parentNode); + this.#resizeObserver.observe(this.#mainContainer); this.#resizeObserver.observe(this.bar); this.opened = true; @@ -200,7 +203,7 @@ class PDFFindBar { } } - #resizeObserverCallback(entries) { + #resizeObserverCallback() { const { bar } = this; // The find bar has an absolute position and thus the browser extends // its width to the maximum possible width once the find bar does not fit diff --git a/web/toolbar.js b/web/toolbar.js index bc4994ee09829..39f6acb6fbaff 100644 --- a/web/toolbar.js +++ b/web/toolbar.js @@ -21,7 +21,7 @@ import { DEFAULT_SCALE_VALUE, MAX_SCALE, MIN_SCALE, - toggleCheckedBtn, + toggleExpandedBtn, } from "./ui_utils.js"; /** @@ -270,22 +270,22 @@ class Toolbar { editorStampParamsToolbar, } = this.#opts; - toggleCheckedBtn( + toggleExpandedBtn( editorFreeTextButton, mode === AnnotationEditorType.FREETEXT, editorFreeTextParamsToolbar ); - toggleCheckedBtn( + toggleExpandedBtn( editorHighlightButton, mode === AnnotationEditorType.HIGHLIGHT, editorHighlightParamsToolbar ); - toggleCheckedBtn( + toggleExpandedBtn( editorInkButton, mode === AnnotationEditorType.INK, editorInkParamsToolbar ); - toggleCheckedBtn( + toggleExpandedBtn( editorStampButton, mode === AnnotationEditorType.STAMP, editorStampParamsToolbar diff --git a/web/viewer-geckoview.html b/web/viewer-geckoview.html index fe3e2583e5651..e80f528fd9016 100644 --- a/web/viewer-geckoview.html +++ b/web/viewer-geckoview.html @@ -93,13 +93,13 @@ - +
-
diff --git a/web/viewer.css b/web/viewer.css index 738eca4c814bb..f01f79d21be86 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -26,9 +26,15 @@ --sidebar-transition-duration: 200ms; --sidebar-transition-timing-function: ease; + --toolbar-height: 32px; + --toolbar-horizontal-padding: 1px; + --toolbar-vertical-padding: 2px; + --icon-size: 16px; + --toolbar-icon-opacity: 0.7; --doorhanger-icon-opacity: 0.9; --editor-toolbar-base-offset: 105px; + --doorhanger-height: 8px; --main-color: rgb(12 12 13); --body-bg-color: rgb(212 212 215); @@ -213,9 +219,14 @@ } } -* { - padding: 0; - margin: 0; +@keyframes progressIndeterminate { + 0% { + transform: translateX(calc(-142px * var(--dir-factor))); + } + + 100% { + transform: translateX(0); + } } html, @@ -225,6 +236,7 @@ body { } body { + margin: 0; background-color: var(--body-bg-color); scrollbar-color: var(--scrollbar-color) var(--scrollbar-bg-color); @@ -270,6 +282,7 @@ body { width: 100%; height: 100%; position: relative; + margin: 0; } #sidebarContainer { @@ -290,6 +303,7 @@ body { #outerContainer:is(.sidebarMoving, .sidebarOpen) #sidebarContainer { visibility: visible; } + #outerContainer.sidebarOpen #sidebarContainer { inset-inline-start: 0; } @@ -298,6 +312,9 @@ body { position: absolute; inset: 0; min-width: 350px; + margin: 0; + display: flex; + flex-direction: column; } #sidebarContent { @@ -315,6 +332,7 @@ body { inset: var(--toolbar-height) 0 0; outline: none; } + #viewerContainer:not(.pdfPresentationMode) { transition-duration: var(--sidebar-transition-duration); transition-timing-function: var(--sidebar-transition-timing-function); @@ -325,18 +343,12 @@ body { transition-property: inset-inline-start; } -.toolbar { - position: relative; - inset-inline: 0; - z-index: 9999; - cursor: default; +#sidebarContainer :is(input, button, select) { font: message-box; } -:is(.toolbar, .editorParamsToolbar, #sidebarContainer) - :is(input, button, select) { - outline: none; - font: message-box; +.toolbar { + z-index: 9999; } #toolbarContainer { @@ -349,6 +361,36 @@ body { background-color: var(--sidebar-toolbar-bg-color); box-shadow: var(--toolbarSidebar-box-shadow); border-bottom: var(--toolbarSidebar-border-bottom); + padding: var(--toolbar-vertical-padding) var(--toolbar-horizontal-padding); + justify-content: space-between; + + #toolbarSidebarLeft { + width: auto; + height: 100%; + + #viewThumbnail::before { + mask-image: var(--toolbarButton-viewThumbnail-icon); + } + + #viewOutline::before { + mask-image: var(--toolbarButton-viewOutline-icon); + transform: scaleX(var(--dir-factor)); + } + + #viewAttachments::before { + mask-image: var(--toolbarButton-viewAttachments-icon); + } + + #viewLayers::before { + mask-image: var(--toolbarButton-viewLayers-icon); + } + } + + #toolbarSidebarRight { + width: auto; + height: 100%; + padding-inline-end: 2px; + } } #sidebarResizer { @@ -360,181 +402,16 @@ body { cursor: ew-resize; } -#toolbarContainer, -.editorParamsToolbar { - position: relative; - height: var(--toolbar-height); - background-color: var(--toolbar-bg-color); - box-shadow: var(--toolbar-box-shadow); - border-bottom: var(--toolbar-border-bottom); -} - -#toolbarViewer { - height: var(--toolbar-height); -} - -#loadingBar { - /* Define these variables here, and not in :root, to avoid reflowing the - entire viewer when updating progress (see issue 15958). */ - --progressBar-percent: 0%; - --progressBar-end-offset: 0; - - position: absolute; - inset-inline: 0 var(--progressBar-end-offset); - height: 4px; - background-color: var(--progressBar-bg-color); - border-bottom: 1px solid var(--toolbar-border-color); - transition-property: inset-inline-start; - transition-duration: var(--sidebar-transition-duration); - transition-timing-function: var(--sidebar-transition-timing-function); -} - #outerContainer.sidebarOpen #loadingBar { inset-inline-start: var(--sidebar-width); } -#loadingBar .progress { - position: absolute; - top: 0; - inset-inline-start: 0; - width: 100%; - transform: scaleX(var(--progressBar-percent)); - transform-origin: calc(50% - 50% * var(--dir-factor)) 0; - height: 100%; - background-color: var(--progressBar-color); - overflow: hidden; - transition: transform 200ms; -} - -@keyframes progressIndeterminate { - 0% { - transform: translateX(calc(-142px * var(--dir-factor))); - } - 100% { - transform: translateX(0); - } -} - -#loadingBar.indeterminate .progress { - transform: none; - background-color: var(--progressBar-bg-color); - transition: none; -} - -#loadingBar.indeterminate .progress .glimmer { - position: absolute; - top: 0; - inset-inline-start: 0; - height: 100%; - width: calc(100% + 150px); - background: repeating-linear-gradient( - 135deg, - var(--progressBar-blend-color) 0, - var(--progressBar-bg-color) 5px, - var(--progressBar-bg-color) 45px, - var(--progressBar-color) 55px, - var(--progressBar-color) 95px, - var(--progressBar-blend-color) 100px - ); - animation: progressIndeterminate 1s linear infinite; -} - #outerContainer.sidebarResizing :is(#sidebarContainer, #viewerContainer, #loadingBar) { /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */ transition-duration: 0s; } -.editorParamsToolbar { - background-color: var(--doorhanger-bg-color); - top: var(--toolbar-height); - position: absolute; - z-index: 30000; - height: auto; - inset-inline-end: 4px; - padding: 6px 0 10px; - margin: 4px 2px; - font: message-box; - font-size: 12px; - line-height: 14px; - text-align: left; - cursor: default; -} - -.editorParamsToolbarContainer { - width: 220px; - margin-bottom: -4px; -} - -.editorParamsToolbarContainer > .editorParamsSetter { - min-height: 26px; - display: flex; - align-items: center; - justify-content: space-between; - padding-inline: 10px; -} - -.editorParamsToolbarContainer .editorParamsLabel { - padding-inline-end: 10px; - flex: none; - font: menu; - font-size: 13px; - font-style: normal; - font-weight: 400; - line-height: 150%; - color: var(--main-color); -} - -.editorParamsToolbarContainer .editorParamsColor { - width: 32px; - height: 32px; - flex: none; -} - -.editorParamsToolbarContainer .editorParamsSlider { - background-color: transparent; - width: 90px; - flex: 0 1 0; -} - -.editorParamsToolbarContainer .editorParamsSlider::-moz-range-progress { - background-color: black; -} - -/*#if !MOZCENTRAL*/ -.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-runnable-track, -/*#endif*/ -.editorParamsToolbarContainer .editorParamsSlider::-moz-range-track { - background-color: black; -} - -/*#if !MOZCENTRAL*/ -.editorParamsToolbarContainer .editorParamsSlider::-webkit-slider-thumb, -/*#endif*/ -.editorParamsToolbarContainer .editorParamsSlider::-moz-range-thumb { - background-color: white; -} - -#editorStampParamsToolbar { - inset-inline-end: calc(var(--editor-toolbar-base-offset) + 0px); -} - -#editorInkParamsToolbar { - inset-inline-end: calc(var(--editor-toolbar-base-offset) + 28px); -} - -#editorFreeTextParamsToolbar { - inset-inline-end: calc(var(--editor-toolbar-base-offset) + 56px); -} - -#editorHighlightParamsToolbar { - inset-inline-end: calc(var(--editor-toolbar-base-offset) + 84px); -} - -#editorStampAddImage::before { - mask-image: var(--editorParams-stampAddImage-icon); -} - .doorHanger, .doorHangerRight { border-radius: 2px; @@ -542,84 +419,63 @@ body { 0 1px 5px var(--doorhanger-border-color), 0 0 0 1px var(--doorhanger-border-color); border: var(--doorhanger-border-color-whcm); -} -:is(.doorHanger, .doorHangerRight)::after, -:is(.doorHanger, .doorHangerRight)::before { - bottom: 100%; - border: 8px solid rgb(0 0 0 / 0); - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - opacity: var(--doorhanger-triangle-opacity-whcm); -} -.doorHanger::after { - inset-inline-start: 10px; - margin-inline-start: -8px; - border-bottom-color: var(--toolbar-bg-color); -} -.doorHangerRight::after { - inset-inline-end: 10px; - margin-inline-end: -8px; - border-bottom-color: var(--doorhanger-bg-color); -} -:is(.doorHanger, .doorHangerRight)::before { - border-bottom-color: var(--doorhanger-border-color); - border-width: 9px; -} -.doorHanger::before { - inset-inline-start: 10px; - margin-inline-start: -9px; -} -.doorHangerRight::before { - inset-inline-end: 10px; - margin-inline-end: -9px; -} + background-color: var(--doorhanger-bg-color); + inset-block-start: calc(100% + var(--doorhanger-height) - 2px); -#toolbarViewerMiddle { - position: absolute; - left: 50%; - transform: translateX(-50%); -} + &::after, + &::before { + bottom: 100%; + border-style: solid; + border-color: transparent; + content: ""; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + opacity: var(--doorhanger-triangle-opacity-whcm); + } -#toolbarViewerLeft, -#toolbarSidebarLeft { - float: var(--inline-start); -} -#toolbarViewerRight, -#toolbarSidebarRight { - float: var(--inline-end); -} + &::before { + border-width: calc(var(--doorhanger-height) + 2px); + border-bottom-color: var(--doorhanger-border-color); + } -#toolbarViewerLeft > *, -#toolbarViewerMiddle > *, -#toolbarViewerRight > *, -#toolbarSidebarLeft *, -#toolbarSidebarRight * { - position: relative; - float: var(--inline-start); + &::after { + border-width: var(--doorhanger-height); + } } -#toolbarViewerLeft { - padding-inline-start: 1px; -} -#toolbarViewerRight { - padding-inline-end: 1px; +.doorHangerRight { + inset-inline-end: calc(50% - var(--doorhanger-height) - 1px); + + &::before { + inset-inline-end: -1px; + } + + &::after { + border-bottom-color: var(--doorhanger-bg-color); + inset-inline-end: 1px; + } } -#toolbarSidebarRight { - padding-inline-end: 2px; + +.doorHanger { + inset-inline-start: calc(50% - var(--doorhanger-height) - 1px); + + &::before { + inset-inline-start: -1px; + } + + &::after { + border-bottom-color: var(--toolbar-bg-color); + inset-inline-start: 1px; + } } .splitToolbarButton { margin: 2px; display: inline-block; } -.splitToolbarButton > .toolbarButton { - float: var(--inline-start); -} -.toolbarButton, .dialogButton { border: none; background: none; @@ -636,40 +492,14 @@ body { color: var(--dialog-button-hover-color); } -.toolbarButton > span { - display: inline-block; - width: 0; - height: 0; - overflow: hidden; -} - -:is(.toolbarButton, .dialogButton)[disabled] { - opacity: 0.5; -} - -.splitToolbarButton > .toolbarButton:is(:hover, :focus-visible), -.dropdownToolbarButton:hover { - background-color: var(--button-hover-color); -} -.splitToolbarButton > .toolbarButton { - position: relative; - margin: 0; -} -#toolbarSidebar .splitToolbarButton > .toolbarButton { - margin-inline-end: 2px; -} - .splitToolbarButtonSeparator { float: var(--inline-start); - margin: 4px 0; width: 0; - height: 20px; + height: 62%; border-left: 1px solid var(--separator-color); border-right: none; } -.toolbarButton, -.dropdownToolbarButton, .dialogButton { min-width: 16px; margin: 2px 1px; @@ -684,75 +514,7 @@ body { box-sizing: border-box; } -.toolbarButton:is(:hover, :focus-visible) { - background-color: var(--button-hover-color); -} - -.toolbarButton.toggled, -.splitToolbarButton.toggled > .toolbarButton.toggled { - background-color: var(--toggled-btn-bg-color); - color: var(--toggled-btn-color); -} - -.toolbarButton.toggled:hover, -.splitToolbarButton.toggled > .toolbarButton.toggled:hover { - outline: var(--toggled-hover-btn-outline) !important; -} - -.toolbarButton.toggled::before { - background-color: var(--toggled-btn-color); -} - -.toolbarButton.toggled:hover:active, -.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active { - background-color: var(--toggled-hover-active-btn-color); -} - -.dropdownToolbarButton { - display: flex; - width: fit-content; - min-width: 140px; - padding: 0; - background-color: var(--dropdown-btn-bg-color); - border: var(--dropdown-btn-border); -} -.dropdownToolbarButton::after { - top: 6px; - inset-inline-end: 6px; - pointer-events: none; - mask-image: var(--toolbarButton-menuArrow-icon); -} - -.dropdownToolbarButton > select { - appearance: none; - width: inherit; - min-width: inherit; - height: 28px; - font-size: 12px; - color: var(--main-color); - margin: 0; - padding-block: 1px 2px; - padding-inline: 6px 38px; - border: none; - background-color: var(--dropdown-btn-bg-color); -} -.dropdownToolbarButton > select:is(:hover, :focus-visible) { - background-color: var(--button-hover-color); - color: var(--toggled-btn-color); -} -.dropdownToolbarButton > select > option { - background: var(--doorhanger-bg-color); - color: var(--main-color); -} - -.toolbarButtonSpacer { - width: 30px; - display: inline-block; - height: 1px; -} - -:is(.toolbarButton, .treeItemToggler)::before, -.dropdownToolbarButton::after { +.treeItemToggler::before { /* All matching images have a size of 16x16 * All relevant containers have a size of 28x28 */ position: absolute; @@ -765,20 +527,6 @@ body { mask-size: cover; } -.dropdownToolbarButton:is(:hover, :focus-visible, :active)::after { - background-color: var(--toolbar-icon-hover-bg-color); -} - -.toolbarButton::before { - opacity: var(--toolbar-icon-opacity); - top: 6px; - left: 6px; -} - -.toolbarButton:is(:hover, :focus-visible)::before { - background-color: var(--toolbar-icon-hover-bg-color); -} - #sidebarToggleButton::before { mask-image: var(--toolbarButton-sidebarToggle-icon); transform: scaleX(var(--dir-factor)); @@ -805,6 +553,10 @@ body { mask-image: var(--toolbarButton-zoomIn-icon); } +#presentationMode::before { + mask-image: var(--toolbarButton-presentationMode-icon); +} + #editorFreeTextButton::before { mask-image: var(--toolbarButton-editorFreeText-icon); } @@ -821,29 +573,22 @@ body { mask-image: var(--toolbarButton-editorStamp-icon); } -#printButton::before { +:is(#printButton, #secondaryPrint)::before { mask-image: var(--toolbarButton-print-icon); } -#downloadButton::before { - mask-image: var(--toolbarButton-download-icon); -} - -#viewThumbnail::before { - mask-image: var(--toolbarButton-viewThumbnail-icon); -} - -#viewOutline::before { - mask-image: var(--toolbarButton-viewOutline-icon); - transform: scaleX(var(--dir-factor)); +/*#if GENERIC*/ +#secondaryOpenFile::before { + mask-image: var(--toolbarButton-openFile-icon); } +/*#endif*/ -#viewAttachments::before { - mask-image: var(--toolbarButton-viewAttachments-icon); +:is(#downloadButton, #secondaryDownload)::before { + mask-image: var(--toolbarButton-download-icon); } -#viewLayers::before { - mask-image: var(--toolbarButton-viewLayers-icon); +#viewBookmark::before { + mask-image: var(--toolbarButton-bookmark-icon); } #currentOutlineItem::before { @@ -870,12 +615,14 @@ body { .verticalToolbarSeparator { display: block; - margin: 5px 2px; + margin-inline: 2px; width: 0; - height: 22px; + height: 80%; border-left: 1px solid var(--separator-color); border-right: none; + box-sizing: border-box; } + .horizontalToolbarSeparator { display: block; margin: 6px 0; @@ -885,26 +632,45 @@ body { width: 100%; } -.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; +.toggleButton { + display: inline; + + &:is(:hover, :has(> input:focus-visible)) { + color: var(--toggled-btn-color); + background-color: var(--button-hover-color); + } + + &:has(> input:checked) { + color: var(--toggled-btn-color); + background-color: var(--toggled-btn-bg-color); + } + + & > input { + position: absolute; + top: 50%; + left: 50%; + opacity: 0; + width: 0; + height: 0; + } } -.toolbarField[type="checkbox"] { - opacity: 0; - position: absolute !important; - left: 0; - margin: 10px 0 3px; - margin-inline-start: 7px; +.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; + + &:focus { + border-color: #0a84ff; + } } #pageNumber { @@ -921,7 +687,7 @@ body { /*#endif*/ .loadingInput:has(> &.loading)::after { - display: block; + display: inline; visibility: visible; transition-property: visibility; @@ -930,13 +696,14 @@ body { } .loadingInput { + position: relative; + &::after { position: absolute; visibility: hidden; display: none; - top: calc(50% - 8px); - width: 16px; - height: 16px; + width: var(--icon-size); + height: var(--icon-size); content: ""; background-color: var(--toolbar-icon-bg-color); @@ -947,32 +714,12 @@ body { &.start::after { inset-inline-start: 4px; } + &.end::after { inset-inline-end: 4px; } } -.toolbarField:focus { - border-color: #0a84ff; -} - -.toolbarLabel { - min-width: 16px; - padding: 7px; - margin: 2px; - border-radius: 2px; - color: var(--main-color); - font-size: 12px; - line-height: 14px; - text-align: left; - user-select: none; - cursor: default; -} - -#numPages.toolbarLabel { - padding-inline-start: 3px; -} - #thumbnailView, #outlineView, #attachmentsView, @@ -984,6 +731,7 @@ body { overflow: auto; user-select: none; } + #thumbnailView { width: calc(100% - 60px); padding: 10px 30px 0; @@ -1016,6 +764,7 @@ a:focus > .thumbnail, .thumbnail:hover { border-color: var(--thumbnail-hover-color); } + .thumbnail.selected { border-color: var(--thumbnail-selected-color) !important; } @@ -1025,10 +774,12 @@ a:focus > .thumbnail, height: var(--thumbnail-height); opacity: 0.9; } + a:focus > .thumbnail > .thumbnailImage, .thumbnail:hover > .thumbnailImage { opacity: 0.95; } + .thumbnail.selected > .thumbnailImage { opacity: 1 !important; } @@ -1065,9 +816,11 @@ a:focus > .thumbnail > .thumbnailImage, #layersView .treeItem > a * { cursor: pointer; } + #layersView .treeItem > a > label { padding-inline-start: 4px; } + #layersView .treeItem > a > label > input { float: var(--inline-start); margin-top: 1px; @@ -1080,14 +833,17 @@ a:focus > .thumbnail > .thumbnailImage, width: 0; color: rgb(255 255 255 / 0.5); } + .treeItemToggler::before { inset-inline-end: 4px; mask-image: var(--treeitem-expanded-icon); } + .treeItemToggler.treeItemsHidden::before { mask-image: var(--treeitem-collapsed-icon); transform: scaleX(var(--dir-factor)); } + .treeItemToggler.treeItemsHidden ~ .treeItems { display: none; } @@ -1111,7 +867,7 @@ a:focus > .thumbnail > .thumbnailImage, display: none; #sidebarContainer:has(#outlineView:not(.hidden)) & { - display: inherit; + display: inline flex; } } @@ -1137,6 +893,7 @@ dialog { border-radius: 4px; box-shadow: 0 1px 4px rgb(0 0 0 / 0.3); } + dialog::backdrop { background-color: rgb(0 0 0 / 0.2); } @@ -1174,6 +931,7 @@ dialog :link { #passwordDialog { text-align: center; } + #passwordDialog .toolbarField { width: 200px; } @@ -1181,18 +939,22 @@ dialog :link { #documentPropertiesDialog { text-align: left; } + #documentPropertiesDialog .row > * { min-width: 100px; text-align: start; } + #documentPropertiesDialog .row > span { width: 125px; word-wrap: break-word; } + #documentPropertiesDialog .row > p { max-width: 225px; word-wrap: break-word; } + #documentPropertiesDialog .buttonRow { margin-top: 10px; } @@ -1200,14 +962,17 @@ dialog :link { .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; } + .grab-to-pan-grabbing { position: fixed; background: rgb(0 0 0 / 0); @@ -1218,22 +983,81 @@ dialog :link { } .toolbarButton { - &.labeled { - border-radius: 0; + height: 100%; + aspect-ratio: 1; + display: flex; + align-items: center; + justify-content: center; + background: none; + border: none; + color: var(--main-color); + outline: none; + border-radius: 2px; + box-sizing: border-box; + font: message-box; + flex: none; + position: relative; + + > span { display: inline-block; - height: auto; - margin: 0; - padding: 0 0 1px; - padding-inline-start: 36px; - position: relative; - min-height: 26px; - min-width: 100%; + width: 0; + height: 0; + overflow: hidden; + } + + &::before { + opacity: var(--toolbar-icon-opacity); + display: inline-block; + width: var(--icon-size); + height: var(--icon-size); + content: ""; + background-color: var(--toolbar-icon-bg-color); + mask-size: cover; + mask-position: center; + } + + &.toggled { + background-color: var(--toggled-btn-bg-color); + color: var(--toggled-btn-color); + + &::before { + background-color: var(--toggled-btn-color); + } + + &:hover { + outline: var(--toggled-hover-btn-outline) !important; + + &:active { + background-color: var(--toggled-hover-active-btn-color); + } + } + } + + &:is(:hover, :focus-visible) { + background-color: var(--button-hover-color); + + &::before { + background-color: var(--toolbar-icon-hover-bg-color); + } + } + + &:is([disabled="disabled"], [disabled]) { + opacity: 0.5; + pointer-events: none; + } + + &.labeled { + width: 100%; + min-height: var(--menuitem-height); + justify-content: flex-start; + gap: 8px; + padding-inline-start: 12px; + aspect-ratio: unset; text-align: start; white-space: normal; - width: auto; + cursor: default; &:is(a) { - padding-top: 5px; text-decoration: none; &[href="#"] { @@ -1243,50 +1067,132 @@ dialog :link { } &::before { - inset-inline-start: 12px; opacity: var(--doorhanger-icon-opacity); - top: 5px; } - &:not(.toggled):is(:hover, :focus-visible) { + &:is(:hover, :focus-visible) { background-color: var(--doorhanger-hover-bg-color); color: var(--doorhanger-hover-color); } > span { - display: unset; - padding-inline-end: 4px; + display: inline-block; + width: max-content; + height: auto; + } + } +} + +.toolbarButtonWithContainer { + height: 100%; + aspect-ratio: 1; + display: inline-block; + position: relative; + flex: none; + + > .toolbarButton { + width: 100%; + height: 100%; + } + + .menuContainer { + width: 100%; + height: auto; + max-height: calc( + var(--viewer-container-height) - var(--toolbar-height) - + var(--doorhanger-height) + ); + display: flex; + flex-direction: column; + box-sizing: border-box; + padding-block: 5px; + overflow-y: auto; + } + + .editorParamsToolbar { + height: auto; + width: 220px; + position: absolute; + z-index: 30000; + cursor: default; + + #editorStampAddImage::before { + mask-image: var(--editorParams-stampAddImage-icon); + } + + .editorParamsLabel { + flex: none; + font: menu; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 150%; + color: var(--main-color); + width: fit-content; + inset-inline-start: 0; + } + + .editorParamsToolbarContainer { + width: 100%; + height: auto; + display: flex; + flex-direction: column; + box-sizing: border-box; + padding-inline: 10px; + padding-block: 10px; + + > .editorParamsSetter { + min-height: 26px; + display: flex; + align-items: center; + justify-content: space-between; + } + + .editorParamsColor { + width: 32px; + height: 32px; + flex: none; + padding: 0; + } + + .editorParamsSlider { + background-color: transparent; + width: 90px; + flex: 0 1 0; + font: message-box; + + &::-moz-range-progress { + background-color: black; + } + + /*#if !MOZCENTRAL*/ + &::-webkit-slider-runnable-track, + /*#endif*/ + &::-moz-range-track { + background-color: black; + } + + /*#if !MOZCENTRAL*/ + &::-webkit-slider-thumb, + /*#endif*/ + &::-moz-range-thumb { + background-color: white; + } + } } } } #secondaryToolbar { - background-color: var(--doorhanger-bg-color); - cursor: default; - font: message-box; - font-size: 12px; height: auto; - inset-inline-end: 4px; - line-height: 14px; - margin: 4px 2px; - padding: 6px 0 10px; + width: 220px; position: absolute; - text-align: left; - top: var(--toolbar-height); z-index: 30000; - - :is(button, a) { - font: message-box; - outline: none; - } + cursor: default; + min-height: 26px; + max-height: calc(var(--viewer-container-height) - 40px); #secondaryToolbarButtonContainer { - margin-bottom: -4px; - max-height: calc(var(--viewer-container-height) - 40px); - max-width: 220px; - min-height: 26px; - overflow-y: auto; - /*#if GENERIC*/ #secondaryOpenFile::before { mask-image: var(--toolbarButton-openFile-icon); @@ -1372,127 +1278,115 @@ dialog :link { } #findbar { - background-color: var(--toolbar-bg-color); - cursor: default; - font: message-box; - font-size: 12px; + --input-horizontal-padding: 4px; + --findbar-padding: 2px; + + width: max-content; + max-width: 90vw; + min-height: var(--toolbar-height); height: auto; - inset-inline-start: 64px; - line-height: 14px; - margin: 4px 2px; - min-width: 300px; - padding: 0 4px; position: absolute; - text-align: left; - top: var(--toolbar-height); z-index: 30000; + cursor: default; + padding: 0; + min-width: 300px; + background-color: var(--toolbar-bg-color); + box-sizing: border-box; + flex-wrap: wrap; + justify-content: flex-start; - * { - float: var(--inline-start); - position: relative; - } - - > div { + > * { height: var(--toolbar-height); + padding: var(--findbar-padding); } - :is(button, input) { - font: message-box; - outline: none; - } - - input { - &[type="checkbox"] { - pointer-events: none; + #findInputContainer { + margin-inline-start: 2px; - &:checked + .toolbarLabel { - background-color: var(--toggled-btn-bg-color) !important; - color: var(--toggled-btn-color); - } + #findPreviousButton::before { + mask-image: var(--findbarButton-previous-icon); } - } - - label { - user-select: none; - } - :is(label:hover, input:focus-visible + label) { - background-color: var(--button-hover-color); - color: var(--toggled-btn-color); - } - - #findbarInputContainer { - margin-inline-end: 4px; + #findNextButton::before { + mask-image: var(--findbarButton-next-icon); + } #findInput { width: 200px; + padding: 5px var(--input-horizontal-padding); /*#if !MOZCENTRAL*/ &::-webkit-input-placeholder { color: rgb(191 191 191); } /*#endif*/ - &::placeholder { font-style: normal; } .loadingInput:has(> &[data-status="pending"])::after { - display: block; + display: inline; visibility: visible; + inset-inline-end: calc(var(--input-horizontal-padding) + 1px); } &[data-status="notFound"] { background-color: rgb(255 102 102); } } + } - #findPreviousButton::before { - mask-image: var(--findbarButton-previous-icon); - } + #findbarMessageContainer { + display: none; + gap: 4px; - #findNextButton::before { - mask-image: var(--findbarButton-next-icon); + &:has(> :is(#findResultsCount, #findMsg):not(:empty)) { + display: inline flex; } - } - #findbarMessageContainer { #findResultsCount { background-color: rgb(217 217 217); color: rgb(82 82 82); - margin: 5px; - padding: 4px 5px; - text-align: center; + padding-block: 4px; + + &:empty { + display: none; + } } #findMsg { &[data-status="notFound"] { font-weight: bold; } - } - *:empty { - display: none; + &:empty { + display: none; + } } } &.wrapContainers { - > div { - clear: both; + flex-direction: column; + align-items: flex-start; + height: max-content; + + .toolbarLabel { + margin: 0 4px; } - > #findbarMessageContainer { - height: auto; + #findbarMessageContainer { + flex-wrap: wrap; + flex-flow: column nowrap; + align-items: flex-start; + height: max-content; - > * { - clear: both; + #findResultsCount { + height: calc(var(--toolbar-height) - 2 * var(--findbar-padding)); } - } - } - @media all and (max-width: 690px) { - & { - inset-inline-start: 34px; + #findMsg { + min-height: var(--toolbar-height); + } } } } @@ -1509,15 +1403,19 @@ dialog :link { body { background: rgb(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; @@ -1559,13 +1457,261 @@ dialog :link { display: none !important; } -@media all and (max-width: 900px) { - #toolbarViewerMiddle { - display: table; - margin: auto; - left: auto; - position: inherit; - transform: none; +.toolbarLabel { + width: max-content; + min-width: 16px; + height: 100%; + padding-inline: 4px; + margin: 2px; + border-radius: 2px; + color: var(--main-color); + font-size: 12px; + line-height: 14px; + text-align: left; + user-select: none; + cursor: default; + box-sizing: border-box; + + display: inline flex; + flex-direction: column; + align-items: center; + justify-content: center; + + > label { + width: 100%; + } +} + +.toolbarHorizontalGroup { + height: 100%; + display: inline flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 1px; + box-sizing: border-box; +} + +.dropdownToolbarButton { + display: inline flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: relative; + + width: fit-content; + min-width: 140px; + padding: 0; + background-color: var(--dropdown-btn-bg-color); + border: var(--dropdown-btn-border); + border-radius: 2px; + color: var(--main-color); + font-size: 12px; + line-height: 14px; + user-select: none; + cursor: default; + box-sizing: border-box; + outline: none; + + &:hover { + background-color: var(--button-hover-color); + } + + > select { + appearance: none; + width: inherit; + min-width: inherit; + height: 28px; + font: message-box; + font-size: 12px; + color: var(--main-color); + margin: 0; + padding-block: 1px 2px; + padding-inline: 6px 38px; + border: none; + outline: none; + background-color: var(--dropdown-btn-bg-color); + + > option { + background: var(--doorhanger-bg-color); + color: var(--main-color); + } + + &:is(:hover, :focus-visible) { + background-color: var(--button-hover-color); + color: var(--toggled-btn-color); + } + } + + &::after { + /* All matching images have a size of 16x16 + * All relevant containers have a size of 28x28 */ + position: absolute; + display: inline; + width: var(--icon-size); + height: var(--icon-size); + + content: ""; + background-color: var(--toolbar-icon-bg-color); + mask-size: cover; + + inset-inline-end: 4px; + pointer-events: none; + mask-image: var(--toolbarButton-menuArrow-icon); + } + + &:is(:hover, :focus-visible, :active)::after { + background-color: var(--toolbar-icon-hover-bg-color); + } +} + +#toolbarContainer { + --menuitem-height: calc(var(--toolbar-height) - 6px); + + height: var(--toolbar-height); + padding: var(--toolbar-vertical-padding) var(--toolbar-horizontal-padding); + position: relative; + box-sizing: border-box; + font: message-box; + background-color: var(--toolbar-bg-color); + box-shadow: var(--toolbar-box-shadow); + border-bottom: var(--toolbar-border-bottom); + + #toolbarViewer { + width: 100%; + height: 100%; + justify-content: space-between; + + > * { + flex: none; + } + + input { + font: message-box; + } + + .toolbarButtonSpacer { + width: 30px; + display: block; + height: 1px; + } + + #toolbarViewerLeft #numPages.toolbarLabel { + padding-inline-start: 3px; + flex: none; + } + } + + #loadingBar { + /* Define these variables here, and not in :root, to avoid reflowing the + entire viewer when updating progress (see issue 15958). */ + --progressBar-percent: 0%; + --progressBar-end-offset: 0; + + position: absolute; + top: var(--toolbar-height); + inset-inline: 0 var(--progressBar-end-offset); + height: 4px; + background-color: var(--progressBar-bg-color); + border-bottom: 1px solid var(--toolbar-border-color); + transition-property: inset-inline-start; + transition-duration: var(--sidebar-transition-duration); + transition-timing-function: var(--sidebar-transition-timing-function); + + .progress { + position: absolute; + top: 0; + inset-inline-start: 0; + width: 100%; + transform: scaleX(var(--progressBar-percent)); + transform-origin: calc(50% - 50% * var(--dir-factor)) 0; + height: 100%; + background-color: var(--progressBar-color); + overflow: hidden; + transition: transform 200ms; + } + + &.indeterminate .progress { + transform: none; + background-color: var(--progressBar-bg-color); + transition: none; + + .glimmer { + position: absolute; + top: 0; + inset-inline-start: 0; + height: 100%; + width: calc(100% + 150px); + background: repeating-linear-gradient( + 135deg, + var(--progressBar-blend-color) 0, + var(--progressBar-bg-color) 5px, + var(--progressBar-bg-color) 45px, + var(--progressBar-color) 55px, + var(--progressBar-color) 95px, + var(--progressBar-blend-color) 100px + ); + animation: progressIndeterminate 1s linear infinite; + } + } + } +} + +#secondaryToolbar { + #firstPage::before { + mask-image: var(--secondaryToolbarButton-firstPage-icon); + } + + #lastPage::before { + mask-image: var(--secondaryToolbarButton-lastPage-icon); + } + + #pageRotateCcw::before { + mask-image: var(--secondaryToolbarButton-rotateCcw-icon); + } + + #pageRotateCw::before { + mask-image: var(--secondaryToolbarButton-rotateCw-icon); + } + + #cursorSelectTool::before { + mask-image: var(--secondaryToolbarButton-selectTool-icon); + } + + #cursorHandTool::before { + mask-image: var(--secondaryToolbarButton-handTool-icon); + } + + #scrollPage::before { + mask-image: var(--secondaryToolbarButton-scrollPage-icon); + } + + #scrollVertical::before { + mask-image: var(--secondaryToolbarButton-scrollVertical-icon); + } + + #scrollHorizontal::before { + mask-image: var(--secondaryToolbarButton-scrollHorizontal-icon); + } + + #scrollWrapped::before { + mask-image: var(--secondaryToolbarButton-scrollWrapped-icon); + } + + #spreadNone::before { + mask-image: var(--secondaryToolbarButton-spreadNone-icon); + } + + #spreadOdd::before { + mask-image: var(--secondaryToolbarButton-spreadOdd-icon); + } + + #spreadEven::before { + mask-image: var(--secondaryToolbarButton-spreadEven-icon); + } + + #documentProperties::before { + mask-image: var(--secondaryToolbarButton-documentProperties-icon); } } @@ -1586,7 +1732,7 @@ dialog :link { display: none !important; } #outerContainer .visibleMediumView:not(.hidden, [hidden]) { - display: inherit !important; + display: inline-block !important; } } @@ -1595,7 +1741,8 @@ dialog :link { .hiddenSmallView * { display: none !important; } - .toolbarButtonSpacer { + + #toolbarContainer #toolbarViewer .toolbarButtonSpacer { width: 0; } } diff --git a/web/viewer.html b/web/viewer.html index 33004b7a2b787..0ffbb4eadc5e4 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -93,33 +93,33 @@ - +
-
+
-
- - - -
-
+
-
@@ -139,272 +139,89 @@
- - - - - - - - - - - -
-
-
-
- -
- + +
+
+
-
- - - - -
-
-
- - - - +
+ + + +
- -
- - - - - -
- -
-
-
-
- +
- @@ -421,6 +238,211 @@
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+ + + +
+ +
+ +
+ + +
+
diff --git a/web/viewer.js b/web/viewer.js index 9a6ab555a11d9..1115af56e03aa 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -37,6 +37,7 @@ window.PDFViewerApplicationOptions = AppOptions; function getViewerConfiguration() { return { appContainer: document.body, + principalContainer: document.getElementById("mainContainer"), mainContainer: document.getElementById("viewerContainer"), viewerContainer: document.getElementById("viewer"), toolbar: {