// 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,
}
);
}
}
);