diff --git a/gulpfile.js b/gulpfile.js index c49839163ee79..26e36252d5d4f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -245,7 +245,6 @@ function createWebpackConfig( "web-pdf_outline_viewer": "web/pdf_outline_viewer.js", "web-pdf_presentation_mode": "web/pdf_presentation_mode.js", "web-pdf_sidebar": "web/pdf_sidebar.js", - "web-pdf_sidebar_resizer": "web/pdf_sidebar_resizer.js", "web-pdf_thumbnail_viewer": "web/pdf_thumbnail_viewer.js", "web-print_service": "", "web-secondary_toolbar": "web/secondary_toolbar.js", diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html index 54b49cc77605f..d9980f18f8045 100644 --- a/test/unit/unit_test.html +++ b/test/unit/unit_test.html @@ -28,7 +28,6 @@ "web-pdf_outline_viewer": "../../web/pdf_outline_viewer.js", "web-pdf_presentation_mode": "../../web/pdf_presentation_mode.js", "web-pdf_sidebar": "../../web/pdf_sidebar.js", - "web-pdf_sidebar_resizer": "../../web/pdf_sidebar_resizer.js", "web-pdf_thumbnail_viewer": "../../web/pdf_thumbnail_viewer.js", "web-print_service": "../../web/pdf_print_service.js", "web-secondary_toolbar": "../../web/secondary_toolbar.js", diff --git a/web/app.js b/web/app.js index 3a01bfa257e92..15795f723e9db 100644 --- a/web/app.js +++ b/web/app.js @@ -71,7 +71,6 @@ import { PDFPresentationMode } from "web-pdf_presentation_mode"; import { PDFRenderingQueue } from "./pdf_rendering_queue.js"; import { PDFScriptingManager } from "./pdf_scripting_manager.js"; import { PDFSidebar } from "web-pdf_sidebar"; -import { PDFSidebarResizer } from "web-pdf_sidebar_resizer"; import { PDFThumbnailViewer } from "web-pdf_thumbnail_viewer"; import { PDFViewer } from "./pdf_viewer.js"; import { SecondaryToolbar } from "web-secondary_toolbar"; @@ -177,8 +176,6 @@ const PDFViewerApplication = { pdfHistory: null, /** @type {PDFSidebar} */ pdfSidebar: null, - /** @type {PDFSidebarResizer} */ - pdfSidebarResizer: null, /** @type {PDFOutlineViewer} */ pdfOutlineViewer: null, /** @type {PDFAttachmentViewer} */ @@ -656,12 +653,6 @@ const PDFViewerApplication = { l10n: this.l10n, }); this.pdfSidebar.onToggled = this.forceRendering.bind(this); - - this.pdfSidebarResizer = new PDFSidebarResizer( - appConfig.sidebarResizer, - eventBus, - this.l10n - ); } }, diff --git a/web/pdf_sidebar.js b/web/pdf_sidebar.js index 3dd99fd4fdc6c..f1eabd6f0c087 100644 --- a/web/pdf_sidebar.js +++ b/web/pdf_sidebar.js @@ -14,6 +14,7 @@ */ import { + docStyle, PresentationModeState, RenderingStates, SidebarView, @@ -21,6 +22,9 @@ import { toggleExpandedBtn, } from "./ui_utils.js"; +const SIDEBAR_WIDTH_VAR = "--sidebar-width"; +const SIDEBAR_MIN_WIDTH = 200; // pixels +const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; /** @@ -40,6 +44,8 @@ const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; * (in which the views are placed). * @property {HTMLButtonElement} toggleButton - The button used for * opening/closing the sidebar. + * @property {HTMLDivElement} resizer - The DOM element that can be dragged in + * order to adjust the width of the sidebar. * @property {HTMLButtonElement} thumbnailButton - The button used to show * the thumbnail view. * @property {HTMLButtonElement} outlineButton - The button used to show @@ -63,6 +69,16 @@ const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; */ class PDFSidebar { + #isRTL = false; + + #mouseMoveBound = this.#mouseMove.bind(this); + + #mouseUpBound = this.#mouseUp.bind(this); + + #outerContainerWidth = null; + + #width = null; + /** * @param {PDFSidebarOptions} options */ @@ -84,6 +100,7 @@ class PDFSidebar { this.outerContainer = elements.outerContainer; this.sidebarContainer = elements.sidebarContainer; this.toggleButton = elements.toggleButton; + this.resizer = elements.resizer; this.thumbnailButton = elements.thumbnailButton; this.outlineButton = elements.outlineButton; @@ -101,6 +118,9 @@ class PDFSidebar { this.eventBus = eventBus; this.l10n = l10n; + l10n.getDirection().then(dir => { + this.#isRTL = dir === "rtl"; + }); this.#addEventListeners(); } @@ -275,8 +295,8 @@ class PDFSidebar { } #dispatchEvent() { - if (this.isInitialViewSet && !this.isInitialEventDispatched) { - this.isInitialEventDispatched = true; + if (this.isInitialViewSet) { + this.isInitialEventDispatched ||= true; } this.eventBus.dispatch("sidebarviewchanged", { @@ -411,6 +431,100 @@ class PDFSidebar { this.#updateThumbnailViewer(); } }); + + // Handle resizing of the sidebar. + this.resizer.addEventListener("mousedown", evt => { + if (evt.button !== 0) { + return; + } + // Disable the `transition-duration` rules when sidebar resizing begins, + // in order to improve responsiveness and to avoid visual glitches. + this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); + + window.addEventListener("mousemove", this.#mouseMoveBound); + window.addEventListener("mouseup", this.#mouseUpBound); + }); + + this.eventBus._on("resize", evt => { + // When the *entire* viewer is resized, such that it becomes narrower, + // ensure that the sidebar doesn't end up being too wide. + if (evt.source !== window) { + return; + } + // Always reset the cached width when the viewer is resized. + this.#outerContainerWidth = null; + + if (!this.#width) { + // The sidebar hasn't been resized, hence no need to adjust its width. + return; + } + // NOTE: If the sidebar is closed, we don't need to worry about + // visual glitches nor ensure that rendering is triggered. + if (!this.isOpen) { + this.#updateWidth(this.#width); + return; + } + this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); + const updated = this.#updateWidth(this.#width); + + Promise.resolve().then(() => { + this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); + // Trigger rendering if the sidebar width changed, to avoid + // depending on the order in which 'resize' events are handled. + if (updated) { + this.eventBus.dispatch("resize", { source: this }); + } + }); + }); + } + + /** + * @type {number} + */ + get outerContainerWidth() { + return (this.#outerContainerWidth ||= this.outerContainer.clientWidth); + } + + /** + * returns {boolean} Indicating if the sidebar width was updated. + */ + #updateWidth(width = 0) { + // Prevent the sidebar from becoming too narrow, or from occupying more + // than half of the available viewer width. + const maxWidth = Math.floor(this.outerContainerWidth / 2); + if (width > maxWidth) { + width = maxWidth; + } + if (width < SIDEBAR_MIN_WIDTH) { + width = SIDEBAR_MIN_WIDTH; + } + // Only update the UI when the sidebar width did in fact change. + if (width === this.#width) { + return false; + } + this.#width = width; + + docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); + return true; + } + + #mouseMove(evt) { + let width = evt.clientX; + // For sidebar resizing to work correctly in RTL mode, invert the width. + if (this.#isRTL) { + width = this.outerContainerWidth - width; + } + this.#updateWidth(width); + } + + #mouseUp(evt) { + // Re-enable the `transition-duration` rules when sidebar resizing ends... + this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); + // ... and ensure that rendering will always be triggered. + this.eventBus.dispatch("resize", { source: this }); + + window.removeEventListener("mousemove", this.#mouseMoveBound); + window.removeEventListener("mouseup", this.#mouseUpBound); } } diff --git a/web/pdf_sidebar_resizer.js b/web/pdf_sidebar_resizer.js deleted file mode 100644 index 79e857d74db5e..0000000000000 --- a/web/pdf_sidebar_resizer.js +++ /dev/null @@ -1,168 +0,0 @@ -/* Copyright 2017 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 { docStyle } from "./ui_utils.js"; - -const SIDEBAR_WIDTH_VAR = "--sidebar-width"; -const SIDEBAR_MIN_WIDTH = 200; // pixels -const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; - -/** - * @typedef {Object} PDFSidebarResizerOptions - * @property {HTMLDivElement} outerContainer - The outer container - * (encasing both the viewer and sidebar elements). - * @property {HTMLDivElement} resizer - The DOM element that can be dragged in - * order to adjust the width of the sidebar. - */ - -class PDFSidebarResizer { - /** - * @param {PDFSidebarResizerOptions} options - * @param {EventBus} eventBus - The application event bus. - * @param {IL10n} l10n - Localization service. - */ - constructor(options, eventBus, l10n) { - this.isRTL = false; - this.sidebarOpen = false; - this._width = null; - this._outerContainerWidth = null; - this._boundEvents = Object.create(null); - - this.outerContainer = options.outerContainer; - this.resizer = options.resizer; - this.eventBus = eventBus; - - l10n.getDirection().then(dir => { - this.isRTL = dir === "rtl"; - }); - this._addEventListeners(); - } - - /** - * @type {number} - */ - get outerContainerWidth() { - return (this._outerContainerWidth ||= this.outerContainer.clientWidth); - } - - /** - * @private - * returns {boolean} Indicating if the sidebar width was updated. - */ - _updateWidth(width = 0) { - // Prevent the sidebar from becoming too narrow, or from occupying more - // than half of the available viewer width. - const maxWidth = Math.floor(this.outerContainerWidth / 2); - if (width > maxWidth) { - width = maxWidth; - } - if (width < SIDEBAR_MIN_WIDTH) { - width = SIDEBAR_MIN_WIDTH; - } - // Only update the UI when the sidebar width did in fact change. - if (width === this._width) { - return false; - } - this._width = width; - - docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); - return true; - } - - /** - * @private - */ - _mouseMove(evt) { - let width = evt.clientX; - // For sidebar resizing to work correctly in RTL mode, invert the width. - if (this.isRTL) { - width = this.outerContainerWidth - width; - } - this._updateWidth(width); - } - - /** - * @private - */ - _mouseUp(evt) { - // Re-enable the `transition-duration` rules when sidebar resizing ends... - this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); - // ... and ensure that rendering will always be triggered. - this.eventBus.dispatch("resize", { source: this }); - - const _boundEvents = this._boundEvents; - window.removeEventListener("mousemove", _boundEvents.mouseMove); - window.removeEventListener("mouseup", _boundEvents.mouseUp); - } - - /** - * @private - */ - _addEventListeners() { - const _boundEvents = this._boundEvents; - _boundEvents.mouseMove = this._mouseMove.bind(this); - _boundEvents.mouseUp = this._mouseUp.bind(this); - - this.resizer.addEventListener("mousedown", evt => { - if (evt.button !== 0) { - return; - } - // Disable the `transition-duration` rules when sidebar resizing begins, - // in order to improve responsiveness and to avoid visual glitches. - this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); - - window.addEventListener("mousemove", _boundEvents.mouseMove); - window.addEventListener("mouseup", _boundEvents.mouseUp); - }); - - this.eventBus._on("sidebarviewchanged", evt => { - this.sidebarOpen = !!evt?.view; - }); - - this.eventBus._on("resize", evt => { - // When the *entire* viewer is resized, such that it becomes narrower, - // ensure that the sidebar doesn't end up being too wide. - if (evt?.source !== window) { - return; - } - // Always reset the cached width when the viewer is resized. - this._outerContainerWidth = null; - - if (!this._width) { - // The sidebar hasn't been resized, hence no need to adjust its width. - return; - } - // NOTE: If the sidebar is closed, we don't need to worry about - // visual glitches nor ensure that rendering is triggered. - if (!this.sidebarOpen) { - this._updateWidth(this._width); - return; - } - this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); - const updated = this._updateWidth(this._width); - - Promise.resolve().then(() => { - this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); - // Trigger rendering if the sidebar width changed, to avoid - // depending on the order in which 'resize' events are handled. - if (updated) { - this.eventBus.dispatch("resize", { source: this }); - } - }); - }); - } -} - -export { PDFSidebarResizer }; diff --git a/web/stubs-geckoview.js b/web/stubs-geckoview.js index c55696f0f60a4..38cacc9580431 100644 --- a/web/stubs-geckoview.js +++ b/web/stubs-geckoview.js @@ -22,7 +22,6 @@ const PDFLayerViewer = null; const PDFOutlineViewer = null; const PDFPresentationMode = null; const PDFSidebar = null; -const PDFSidebarResizer = null; const PDFThumbnailViewer = null; const SecondaryToolbar = null; const Toolbar = null; @@ -37,7 +36,6 @@ export { PDFOutlineViewer, PDFPresentationMode, PDFSidebar, - PDFSidebarResizer, PDFThumbnailViewer, SecondaryToolbar, Toolbar, diff --git a/web/viewer-geckoview.html b/web/viewer-geckoview.html index 4c4997f674fe6..eb341739e0006 100644 --- a/web/viewer-geckoview.html +++ b/web/viewer-geckoview.html @@ -60,7 +60,6 @@ "web-pdf_outline_viewer": "./stubs-geckoview.js", "web-pdf_presentation_mode": "./stubs-geckoview.js", "web-pdf_sidebar": "./stubs-geckoview.js", - "web-pdf_sidebar_resizer": "./stubs-geckoview.js", "web-pdf_thumbnail_viewer": "./stubs-geckoview.js", "web-print_service": "./stubs-geckoview.js", "web-secondary_toolbar": "./stubs-geckoview.js", diff --git a/web/viewer.html b/web/viewer.html index afee3100d12b9..132595629599d 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -71,7 +71,6 @@ "web-pdf_outline_viewer": "./pdf_outline_viewer.js", "web-pdf_presentation_mode": "./pdf_presentation_mode.js", "web-pdf_sidebar": "./pdf_sidebar.js", - "web-pdf_sidebar_resizer": "./pdf_sidebar_resizer.js", "web-pdf_thumbnail_viewer": "./pdf_thumbnail_viewer.js", "web-print_service": "./pdf_print_service.js", "web-secondary_toolbar": "./secondary_toolbar.js", diff --git a/web/viewer.js b/web/viewer.js index 6e2a2e16a19cc..a96653f1fe81d 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -96,6 +96,7 @@ function getViewerConfiguration() { outerContainer: document.getElementById("outerContainer"), sidebarContainer: document.getElementById("sidebarContainer"), toggleButton: document.getElementById("sidebarToggle"), + resizer: document.getElementById("sidebarResizer"), // Buttons thumbnailButton: document.getElementById("viewThumbnail"), outlineButton: document.getElementById("viewOutline"), @@ -112,10 +113,6 @@ function getViewerConfiguration() { ), currentOutlineItemButton: document.getElementById("currentOutlineItem"), }, - sidebarResizer: { - outerContainer: document.getElementById("outerContainer"), - resizer: document.getElementById("sidebarResizer"), - }, findBar: { bar: document.getElementById("findbar"), toggleButton: document.getElementById("viewFind"),