// This file is loaded into the browser window scope. /* eslint-env mozilla/browser-window */ // -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ customElements.define( "printpreview-pagination", class PrintPreviewPagination extends HTMLElement { static get markup() { return ` `; } static get defaultProperties() { return { currentPage: 1, sheetCount: 1, }; } get previewBrowser() { if (!this._previewBrowser) { // Assuming we're a sibling of our preview browser. this._previewBrowser = this.parentNode.querySelector( ".printPreviewBrowser" ); } return this._previewBrowser; } set previewBrowser(aBrowser) { this._previewBrowser = aBrowser; } connectedCallback() { MozXULElement.insertFTLIfNeeded("toolkit/printing/printPreview.ftl"); const shadowRoot = this.attachShadow({ mode: "open" }); document.l10n.connectRoot(shadowRoot); let fragment = MozXULElement.parseXULToFragment(this.constructor.markup); this.shadowRoot.append(fragment); this.elements = { sheetIndicator: shadowRoot.querySelector("#sheetIndicator"), homeButton: shadowRoot.querySelector("#navigateHome"), previousButton: shadowRoot.querySelector("#navigatePrevious"), nextButton: shadowRoot.querySelector("#navigateNext"), endButton: shadowRoot.querySelector("#navigateEnd"), }; this.shadowRoot.addEventListener("click", this); let knownAttrs = { "sheet-count": "sheetCount", "current-page": "currentPage", }; this.mutationObserver = new MutationObserver(changes => { let opts = {}; for (let change of changes) { let { attributeName, target, type } = change; if (type == "attributes" && attributeName in knownAttrs) { opts[knownAttrs[attributeName]] = parseInt( target.getAttribute(attributeName), 10 ); } } if (opts.sheetCount || opts.currentPage) { this.update(opts); } }); this.mutationObserver.observe(this.previewBrowser, { attributes: ["current-page", "sheet-count"], }); this.currentPreviewBrowserObserver = new MutationObserver(changes => { for (let change of changes) { if (change.attributeName == "previewtype") { let previewType = change.target.getAttribute("previewtype"); this.previewBrowser = change.target.querySelector( `browser[previewtype="${previewType}"]` ); this.mutationObserver.disconnect(); this.mutationObserver.observe(this.previewBrowser, { attributes: ["current-page", "sheet-count"], }); } } }); this.currentPreviewBrowserObserver.observe(this.parentNode, { attributes: ["previewtype"], }); // Initial render with some default values // We'll be updated with real values when available this.update(this.constructor.defaultProperties); } disconnectedCallback() { document.l10n.disconnectRoot(this.shadowRoot); this.shadowRoot.textContent = ""; this.mutationObserver?.disconnect(); delete this.mutationObserver; this.currentPreviewBrowserObserver?.disconnect(); delete this.currentPreviewBrowserObserver; } handleEvent(event) { if (event.type == "click" && event.button != 0) { return; } event.stopPropagation(); switch (event.target) { case this.elements.homeButton: this.navigate(0, 0, "home"); break; case this.elements.previousButton: this.navigate(-1, 0, 0); break; case this.elements.nextButton: this.navigate(1, 0, 0); break; case this.elements.endButton: this.navigate(0, 0, "end"); break; } } navigate(aDirection, aPageNum, aHomeOrEnd) { const nsIWebBrowserPrint = Ci.nsIWebBrowserPrint; let targetNum; let navType; // we use only one of aHomeOrEnd, aDirection, or aPageNum if (aHomeOrEnd) { // We're going to either the very first page ("home"), or the // very last page ("end"). if (aHomeOrEnd == "home") { targetNum = 1; navType = nsIWebBrowserPrint.PRINTPREVIEW_HOME; } else { targetNum = this.sheetCount; navType = nsIWebBrowserPrint.PRINTPREVIEW_END; } } else if (aPageNum) { // We're going to a specific page (aPageNum) targetNum = Math.min(Math.max(1, aPageNum), this.sheetCount); navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM; } else { // aDirection is either +1 or -1, and allows us to increment // or decrement our currently viewed page. targetNum = Math.min( Math.max(1, this.currentSheet + aDirection), this.sheetCount ); navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM; } // Preemptively update our own state, rather than waiting for the message from the child process // This allows subsequent clicks of next/back to advance 1 page per click if possible // and keeps the UI feeling more responsive this.update({ currentPage: targetNum }); this.previewBrowser.sendMessageToActor( "Printing:Preview:Navigate", { navType, pageNum: targetNum, }, "Printing" ); } update(data = {}) { if (data.sheetCount) { if (this.sheetCount !== data.sheetCount || this.currentSheet !== 1) { // when sheet count changes, scroll position will get reset this.currentSheet = 1; } this.sheetCount = data.sheetCount; } if (data.currentPage) { this.currentSheet = data.currentPage; } document.l10n.setAttributes( this.elements.sheetIndicator, this.elements.sheetIndicator.dataset.l10nId, { sheetNum: this.currentSheet, sheetCount: this.sheetCount, } ); } } );