diff --git a/web/pdf_sidebar.js b/web/pdf_sidebar.js index 8ab42776050f1..ce6a96774a67b 100644 --- a/web/pdf_sidebar.js +++ b/web/pdf_sidebar.js @@ -16,9 +16,9 @@ import { mozL10n } from './ui_utils'; import { RenderingStates } from './pdf_rendering_queue'; -var UI_NOTIFICATION_CLASS = 'pdfSidebarNotification'; +const UI_NOTIFICATION_CLASS = 'pdfSidebarNotification'; -var SidebarView = { +const SidebarView = { NONE: 0, THUMBS: 1, OUTLINE: 2, @@ -53,15 +53,11 @@ var SidebarView = { * for documents containing outline/attachments. The default value is `false`. */ -/** - * @class - */ -var PDFSidebar = (function PDFSidebarClosure() { +class PDFSidebar { /** - * @constructs PDFSidebar * @param {PDFSidebarOptions} options */ - function PDFSidebar(options) { + constructor(options) { this.isOpen = false; this.active = SidebarView.THUMBS; this.isInitialViewSet = false; @@ -94,356 +90,350 @@ var PDFSidebar = (function PDFSidebarClosure() { this._addEventListeners(); } - PDFSidebar.prototype = { - reset: function PDFSidebar_reset() { - this.isInitialViewSet = false; - - this._hideUINotification(null); - this.switchView(SidebarView.THUMBS); - - this.outlineButton.disabled = false; - this.attachmentsButton.disabled = false; - }, + reset() { + this.isInitialViewSet = false; - /** - * @returns {number} One of the values in {SidebarView}. - */ - get visibleView() { - return (this.isOpen ? this.active : SidebarView.NONE); - }, + this._hideUINotification(null); + this.switchView(SidebarView.THUMBS); - get isThumbnailViewVisible() { - return (this.isOpen && this.active === SidebarView.THUMBS); - }, + this.outlineButton.disabled = false; + this.attachmentsButton.disabled = false; + } - get isOutlineViewVisible() { - return (this.isOpen && this.active === SidebarView.OUTLINE); - }, + /** + * @returns {number} One of the values in {SidebarView}. + */ + get visibleView() { + return (this.isOpen ? this.active : SidebarView.NONE); + } - get isAttachmentsViewVisible() { - return (this.isOpen && this.active === SidebarView.ATTACHMENTS); - }, + get isThumbnailViewVisible() { + return (this.isOpen && this.active === SidebarView.THUMBS); + } - /** - * @param {number} view - The sidebar view that should become visible, - * must be one of the values in {SidebarView}. - */ - setInitialView: function PDFSidebar_setInitialView(view) { - if (this.isInitialViewSet) { - return; - } - this.isInitialViewSet = true; + get isOutlineViewVisible() { + return (this.isOpen && this.active === SidebarView.OUTLINE); + } - if (this.isOpen && view === SidebarView.NONE) { - this._dispatchEvent(); - // If the user has already manually opened the sidebar, - // immediately closing it would be bad UX. - return; - } - var isViewPreserved = (view === this.visibleView); - this.switchView(view, /* forceOpen */ true); + get isAttachmentsViewVisible() { + return (this.isOpen && this.active === SidebarView.ATTACHMENTS); + } - if (isViewPreserved) { - // Prevent dispatching two back-to-back `sidebarviewchanged` events, - // since `this.switchView` dispatched the event if the view changed. - this._dispatchEvent(); - } - }, + /** + * @param {number} view - The sidebar view that should become visible, + * must be one of the values in {SidebarView}. + */ + setInitialView(view) { + if (this.isInitialViewSet) { + return; + } + this.isInitialViewSet = true; - /** - * @param {number} view - The sidebar view that should be switched to, - * must be one of the values in {SidebarView}. - * @param {boolean} forceOpen - (optional) Ensure that the sidebar is open. - * The default value is false. - */ - switchView: function PDFSidebar_switchView(view, forceOpen) { - if (view === SidebarView.NONE) { - this.close(); - return; - } - var isViewChanged = (view !== this.active); - var shouldForceRendering = false; + if (this.isOpen && view === SidebarView.NONE) { + this._dispatchEvent(); + // If the user has already manually opened the sidebar, + // immediately closing it would be bad UX. + return; + } + var isViewPreserved = (view === this.visibleView); + this.switchView(view, /* forceOpen */ true); + + if (isViewPreserved) { + // Prevent dispatching two back-to-back `sidebarviewchanged` events, + // since `this.switchView` dispatched the event if the view changed. + this._dispatchEvent(); + } + } - switch (view) { - case SidebarView.THUMBS: - this.thumbnailButton.classList.add('toggled'); - this.outlineButton.classList.remove('toggled'); - this.attachmentsButton.classList.remove('toggled'); - - this.thumbnailView.classList.remove('hidden'); - this.outlineView.classList.add('hidden'); - this.attachmentsView.classList.add('hidden'); - - if (this.isOpen && isViewChanged) { - this._updateThumbnailViewer(); - shouldForceRendering = true; - } - break; - case SidebarView.OUTLINE: - if (this.outlineButton.disabled) { - return; - } - this.thumbnailButton.classList.remove('toggled'); - this.outlineButton.classList.add('toggled'); - this.attachmentsButton.classList.remove('toggled'); - - this.thumbnailView.classList.add('hidden'); - this.outlineView.classList.remove('hidden'); - this.attachmentsView.classList.add('hidden'); - break; - case SidebarView.ATTACHMENTS: - if (this.attachmentsButton.disabled) { - return; - } - this.thumbnailButton.classList.remove('toggled'); - this.outlineButton.classList.remove('toggled'); - this.attachmentsButton.classList.add('toggled'); - - this.thumbnailView.classList.add('hidden'); - this.outlineView.classList.add('hidden'); - this.attachmentsView.classList.remove('hidden'); - break; - default: - console.error('PDFSidebar_switchView: "' + view + - '" is an unsupported value.'); + /** + * @param {number} view - The sidebar view that should be switched to, + * must be one of the values in {SidebarView}. + * @param {boolean} forceOpen - (optional) Ensure that the sidebar is open. + * The default value is `false`. + */ + switchView(view, forceOpen = false) { + if (view === SidebarView.NONE) { + this.close(); + return; + } + var isViewChanged = (view !== this.active); + var shouldForceRendering = false; + + switch (view) { + case SidebarView.THUMBS: + this.thumbnailButton.classList.add('toggled'); + this.outlineButton.classList.remove('toggled'); + this.attachmentsButton.classList.remove('toggled'); + + this.thumbnailView.classList.remove('hidden'); + this.outlineView.classList.add('hidden'); + this.attachmentsView.classList.add('hidden'); + + if (this.isOpen && isViewChanged) { + this._updateThumbnailViewer(); + shouldForceRendering = true; + } + break; + case SidebarView.OUTLINE: + if (this.outlineButton.disabled) { return; - } - // Update the active view *after* it has been validated above, - // in order to prevent setting it to an invalid state. - this.active = view | 0; - - if (forceOpen && !this.isOpen) { - this.open(); - return; // NOTE: Opening will trigger rendering, and dispatch the event. - } - if (shouldForceRendering) { - this._forceRendering(); - } - if (isViewChanged) { - this._dispatchEvent(); - } - this._hideUINotification(this.active); - }, - - open: function PDFSidebar_open() { - if (this.isOpen) { + } + this.thumbnailButton.classList.remove('toggled'); + this.outlineButton.classList.add('toggled'); + this.attachmentsButton.classList.remove('toggled'); + + this.thumbnailView.classList.add('hidden'); + this.outlineView.classList.remove('hidden'); + this.attachmentsView.classList.add('hidden'); + break; + case SidebarView.ATTACHMENTS: + if (this.attachmentsButton.disabled) { + return; + } + this.thumbnailButton.classList.remove('toggled'); + this.outlineButton.classList.remove('toggled'); + this.attachmentsButton.classList.add('toggled'); + + this.thumbnailView.classList.add('hidden'); + this.outlineView.classList.add('hidden'); + this.attachmentsView.classList.remove('hidden'); + break; + default: + console.error('PDFSidebar_switchView: "' + view + + '" is an unsupported value.'); return; - } - this.isOpen = true; - this.toggleButton.classList.add('toggled'); - - this.outerContainer.classList.add('sidebarMoving'); - this.outerContainer.classList.add('sidebarOpen'); - - if (this.active === SidebarView.THUMBS) { - this._updateThumbnailViewer(); - } + } + // Update the active view *after* it has been validated above, + // in order to prevent setting it to an invalid state. + this.active = view | 0; + + if (forceOpen && !this.isOpen) { + this.open(); + return; // NOTE: Opening will trigger rendering, and dispatch the event. + } + if (shouldForceRendering) { this._forceRendering(); + } + if (isViewChanged) { this._dispatchEvent(); + } + this._hideUINotification(this.active); + } - this._hideUINotification(this.active); - }, + open() { + if (this.isOpen) { + return; + } + this.isOpen = true; + this.toggleButton.classList.add('toggled'); - close: function PDFSidebar_close() { - if (!this.isOpen) { - return; - } - this.isOpen = false; - this.toggleButton.classList.remove('toggled'); + this.outerContainer.classList.add('sidebarMoving'); + this.outerContainer.classList.add('sidebarOpen'); - this.outerContainer.classList.add('sidebarMoving'); - this.outerContainer.classList.remove('sidebarOpen'); + if (this.active === SidebarView.THUMBS) { + this._updateThumbnailViewer(); + } + this._forceRendering(); + this._dispatchEvent(); - this._forceRendering(); - this._dispatchEvent(); - }, + this._hideUINotification(this.active); + } - toggle: function PDFSidebar_toggle() { - if (this.isOpen) { - this.close(); - } else { - this.open(); - } - }, + close() { + if (!this.isOpen) { + return; + } + this.isOpen = false; + this.toggleButton.classList.remove('toggled'); - /** - * @private - */ - _dispatchEvent: function PDFSidebar_dispatchEvent() { - this.eventBus.dispatch('sidebarviewchanged', { - source: this, - view: this.visibleView, - }); - }, + this.outerContainer.classList.add('sidebarMoving'); + this.outerContainer.classList.remove('sidebarOpen'); - /** - * @private - */ - _forceRendering: function PDFSidebar_forceRendering() { - if (this.onToggled) { - this.onToggled(); - } else { // Fallback - this.pdfViewer.forceRendering(); - this.pdfThumbnailViewer.forceRendering(); - } - }, + this._forceRendering(); + this._dispatchEvent(); + } - /** - * @private - */ - _updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() { - var pdfViewer = this.pdfViewer; - var thumbnailViewer = this.pdfThumbnailViewer; - - // Use the rendered pages to set the corresponding thumbnail images. - var pagesCount = pdfViewer.pagesCount; - for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) { - var pageView = pdfViewer.getPageView(pageIndex); - if (pageView && pageView.renderingState === RenderingStates.FINISHED) { - var thumbnailView = thumbnailViewer.getThumbnail(pageIndex); - thumbnailView.setImage(pageView); - } - } - thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); - }, + toggle() { + if (this.isOpen) { + this.close(); + } else { + this.open(); + } + } - /** - * @private - */ - _showUINotification: function (view) { - if (this.disableNotification) { - return; - } + /** + * @private + */ + _dispatchEvent() { + this.eventBus.dispatch('sidebarviewchanged', { + source: this, + view: this.visibleView, + }); + } - this.toggleButton.title = mozL10n.get('toggle_sidebar_notification.title', - null, 'Toggle Sidebar (document contains outline/attachments)'); + /** + * @private + */ + _forceRendering() { + if (this.onToggled) { + this.onToggled(); + } else { // Fallback + this.pdfViewer.forceRendering(); + this.pdfThumbnailViewer.forceRendering(); + } + } - if (!this.isOpen) { - // Only show the notification on the `toggleButton` if the sidebar is - // currently closed, to avoid unnecessarily bothering the user. - this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); - } else if (view === this.active) { - // If the sidebar is currently open *and* the `view` is visible, do not - // bother the user with a notification on the corresponding button. - return; + /** + * @private + */ + _updateThumbnailViewer() { + var pdfViewer = this.pdfViewer; + var thumbnailViewer = this.pdfThumbnailViewer; + + // Use the rendered pages to set the corresponding thumbnail images. + var pagesCount = pdfViewer.pagesCount; + for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) { + var pageView = pdfViewer.getPageView(pageIndex); + if (pageView && pageView.renderingState === RenderingStates.FINISHED) { + var thumbnailView = thumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); } + } + thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); + } + /** + * @private + */ + _showUINotification(view) { + if (this.disableNotification) { + return; + } + + this.toggleButton.title = mozL10n.get('toggle_sidebar_notification.title', + null, 'Toggle Sidebar (document contains outline/attachments)'); + + if (!this.isOpen) { + // Only show the notification on the `toggleButton` if the sidebar is + // currently closed, to avoid unnecessarily bothering the user. + this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); + } else if (view === this.active) { + // If the sidebar is currently open *and* the `view` is visible, do not + // bother the user with a notification on the corresponding button. + return; + } + + switch (view) { + case SidebarView.OUTLINE: + this.outlineButton.classList.add(UI_NOTIFICATION_CLASS); + break; + case SidebarView.ATTACHMENTS: + this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS); + break; + } + } + + /** + * @private + */ + _hideUINotification(view) { + if (this.disableNotification) { + return; + } + + var removeNotification = (view) => { switch (view) { case SidebarView.OUTLINE: - this.outlineButton.classList.add(UI_NOTIFICATION_CLASS); + this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); break; case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS); + this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS); break; } - }, - - /** - * @private - */ - _hideUINotification: function (view) { - if (this.disableNotification) { - return; - } - - var removeNotification = function (view) { - switch (view) { - case SidebarView.OUTLINE: - this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - } - }.bind(this); + }; + + if (!this.isOpen && view !== null) { + // Only hide the notifications when the sidebar is currently open, + // or when it is being reset (i.e. `view === null`). + return; + } + this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); + + if (view !== null) { + removeNotification(view); + return; + } + for (view in SidebarView) { // Remove all sidebar notifications on reset. + removeNotification(SidebarView[view]); + } + + this.toggleButton.title = mozL10n.get('toggle_sidebar.title', null, + 'Toggle Sidebar'); + } - if (!this.isOpen && view !== null) { - // Only hide the notifications when the sidebar is currently open, - // or when it is being reset (i.e. `view === null`). - return; + /** + * @private + */ + _addEventListeners() { + this.mainContainer.addEventListener('transitionend', (evt) => { + if (evt.target === this.mainContainer) { + this.outerContainer.classList.remove('sidebarMoving'); } - this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); + }); - if (view !== null) { - removeNotification(view); - return; - } - for (view in SidebarView) { // Remove all sidebar notifications on reset. - removeNotification(SidebarView[view]); + // Buttons for switching views. + this.thumbnailButton.addEventListener('click', () => { + this.switchView(SidebarView.THUMBS); + }); + + this.outlineButton.addEventListener('click', () => { + this.switchView(SidebarView.OUTLINE); + }); + this.outlineButton.addEventListener('dblclick', () => { + this.pdfOutlineViewer.toggleOutlineTree(); + }); + + this.attachmentsButton.addEventListener('click', () => { + this.switchView(SidebarView.ATTACHMENTS); + }); + + // Disable/enable views. + this.eventBus.on('outlineloaded', (evt) => { + var outlineCount = evt.outlineCount; + + this.outlineButton.disabled = !outlineCount; + + if (outlineCount) { + this._showUINotification(SidebarView.OUTLINE); + } else if (this.active === SidebarView.OUTLINE) { + // If the outline view was opened during document load, switch away + // from it if it turns out that the document has no outline. + this.switchView(SidebarView.THUMBS); } + }); - this.toggleButton.title = mozL10n.get('toggle_sidebar.title', null, - 'Toggle Sidebar'); - }, - - /** - * @private - */ - _addEventListeners: function PDFSidebar_addEventListeners() { - var self = this; - - self.mainContainer.addEventListener('transitionend', function(evt) { - if (evt.target === /* mainContainer */ this) { - self.outerContainer.classList.remove('sidebarMoving'); - } - }); - - // Buttons for switching views. - self.thumbnailButton.addEventListener('click', function() { - self.switchView(SidebarView.THUMBS); - }); - - self.outlineButton.addEventListener('click', function() { - self.switchView(SidebarView.OUTLINE); - }); - self.outlineButton.addEventListener('dblclick', function() { - self.pdfOutlineViewer.toggleOutlineTree(); - }); - - self.attachmentsButton.addEventListener('click', function() { - self.switchView(SidebarView.ATTACHMENTS); - }); - - // Disable/enable views. - self.eventBus.on('outlineloaded', function(e) { - var outlineCount = e.outlineCount; - - self.outlineButton.disabled = !outlineCount; - - if (outlineCount) { - self._showUINotification(SidebarView.OUTLINE); - } else if (self.active === SidebarView.OUTLINE) { - // If the outline view was opened during document load, switch away - // from it if it turns out that the document has no outline. - self.switchView(SidebarView.THUMBS); - } - }); - - self.eventBus.on('attachmentsloaded', function(e) { - var attachmentsCount = e.attachmentsCount; + this.eventBus.on('attachmentsloaded', (evt) => { + var attachmentsCount = evt.attachmentsCount; - self.attachmentsButton.disabled = !attachmentsCount; + this.attachmentsButton.disabled = !attachmentsCount; - if (attachmentsCount) { - self._showUINotification(SidebarView.ATTACHMENTS); - } else if (self.active === SidebarView.ATTACHMENTS) { - // If the attachment view was opened during document load, switch away - // from it if it turns out that the document has no attachments. - self.switchView(SidebarView.THUMBS); - } - }); - - // Update the thumbnailViewer, if visible, when exiting presentation mode. - self.eventBus.on('presentationmodechanged', function(e) { - if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) { - self._updateThumbnailViewer(); - } - }); - }, - }; + if (attachmentsCount) { + this._showUINotification(SidebarView.ATTACHMENTS); + } else if (this.active === SidebarView.ATTACHMENTS) { + // If the attachment view was opened during document load, switch away + // from it if it turns out that the document has no attachments. + this.switchView(SidebarView.THUMBS); + } + }); - return PDFSidebar; -})(); + // Update the thumbnailViewer, if visible, when exiting presentation mode. + this.eventBus.on('presentationmodechanged', (evt) => { + if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) { + this._updateThumbnailViewer(); + } + }); + } +} export { SidebarView,