Bug 1652861 - Rough in UI for printer selection and print settings. r=mstriemer,fluent-reviewers,flod

* New printUI strings
* First pass at layout styling
* Minimal controller and view code
  - UI components are templated and rendered but not populated by print/printer data
  - No view logic or user interaction handling

Differential Revision: https://phabricator.services.mozilla.com/D83603
This commit is contained in:
Sam Foster 2020-07-21 10:31:10 +00:00
Родитель 4a597e3019
Коммит 82ca67dee0
4 изменённых файлов: 432 добавлений и 11 удалений

Просмотреть файл

@ -1,3 +1,101 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
justify-content: flex-start;
overflow: hidden;
}
.row {
padding-inline-start: 34px;
margin-block: 18px;
}
.row .block-label {
display: block;
margin-bottom: 4px;
}
.row .block-label + input,
.row .block-label + select,
.row .block-label + .page-range-input select {
margin-inline-start: 0;
}
.header-container {
display: flex;
flex-direction: row;
flex: 0 1 auto;
border-bottom: 1px solid var(--in-content-border-color);
margin-block: 18px 0;
}
.header-container > h2 {
margin-top: 0;
}
.header-container > #sheets-count {
display: none;
}
form#print {
display: flex;
flex: 1 1 auto;
flex-direction: column;
justify-content: flex-start;
overflow: hidden;
}
.body-container {
flex: 1 1 auto;
overflow: auto;
}
#more-settings {
border-top: 1px solid var(--in-content-border-color);
}
#more-settings.twisty > summary {
list-style: none;
display: flex;
cursor: pointer;
padding-inline-end: 8px;
}
#more-settings > summary > .twisty {
background-image: url("chrome://global/skin/icons/twisty-expanded.svg");
background-repeat: no-repeat;
background-position: center;
width: 20px;
scale: 1 1;
}
#more-settings > summary > .label {
flex-grow: 1;
}
#more-settings[open] > summary > .twisty {
/* flip arrow to point up for the open state */
scale: 1 -1;
}
#open-dialog-link {
display: block;
}
.footer-container {
border-top: 1px solid var(--in-content-border-color);
flex: 0 1 auto;
}
#button-container > button:first-child {
margin-inline-start: 0;
}
.page-range-input:not(.custom-input-selected) #custom-range {
display: none;
}

Просмотреть файл

@ -4,14 +4,106 @@
- You can obtain one at http://mozilla.org/MPL/2.0/. --> - You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html> <html>
<head> <head>
<link rel="stylesheet" href="chrome://global/content/print.css"> <meta charset="utf-8">
<title data-l10n-id="printui-title"></title>
<meta http-equiv="Content-Security-Policy" content="default-src chrome:;img-src data:; object-src 'none'">
<link rel="localization" href="toolkit/printing/printUI.ftl">
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css"> <link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
<link rel="stylesheet" href="chrome://global/content/print.css">
<script defer src="chrome://global/content/print.js"></script> <script defer src="chrome://global/content/print.js"></script>
</head> </head>
<body> <body>
<h1>Print</h1> <template id="page-range-template">
<h2 id="tab-title"></h2> <select id="range-picker" name="page-range-type" data-l10n-id="printui-page-range-picker">
<a href="#" id="open-dialog-link">Open Native Dialog...</a> <option value="all" selected data-l10n-id="printui-page-range-all"></option>
<option value="custom" data-l10n-id="printui-page-range-custom"></option>
</select>
<input id="custom-range" name="page-range" pattern="\d(-\d)?" type="text" hidden data-l10n-id="printui-page-custom-range">
</template>
<template id="orientation-template">
<span>
<input type="radio" name="orientation" id="portrait" value="0" checked>
<label for="portrait" data-l10n-id="printui-portrait"></label>
</span>
<span>
<input type="radio" name="orientation" id="landscape" value="1">
<label for="landscape" data-l10n-id="printui-landscape"></label>
</span>
</template>
<template id="twisty-summary-template">
<span class="label"></span>
<span class="twisty"></span>
</template>
<template id="scale-template">
<div role="radiogroup" aria-labelledby="scale-label">
<div>
<input type="radio" name="scale-choice" id="fit-choice" value="fit" checked>
<label for="fit-choice" data-l10n-id="printui-scale-fit-to-page"></label>
</div>
<div>
<input type="radio" name="scale-choice" id="percent-scale-choice">
<label for="percent-scale-choice" data-l10n-id="printui-scale-pcent"></label>
<input id="percent-scale" type="text" placeholder="100%" disabled>
</div>
</div>
</template>
<header class="row header-container">
<h2 data-l10n-id="printui-title"></h2>
<p id="sheets-count" data-deferred-l10n-id="printui-sheets-count"></p>
</header>
<form id="print">
<section class="body-container">
<section id="destination" class="row">
<label for="printer-picker" class="block-label" data-l10n-id="printui-destination-label"></label>
<select is="destination-picker" id="printer-picker"></select>
</section>
<section id="settings">
<section id="copies" class="row">
<label for="copies-count" class="block-label" data-l10n-id="printui-copies-label"></label>
<input id="copies-count" type="number" min="1">
</section>
<section id="orientation" class="row">
<div role="radiogroup" aria-labelledby="orientation-label">
<label class="block-label" data-l10n-id="printui-orientation"></label>
<span id="orientation-input" is="orientation-input" class="orientation-input"></span>
</div>
</section>
<section id="pages" class="row">
<label for="page-range-input" class="block-label" data-l10n-id="printui-page-range-label"></label>
<span id="page-range-input" is="page-range-input" class="page-range-input"></span>
</section>
<details id="more-settings" class="twisty">
<summary class="block-label row" is="twisty-summary"
data-open-l10n-id="printui-less-settings"
data-closed-l10n-id="printui-more-settings"></summary>
<section id="scale" class="row">
<label for="scale-control" class="block-label" data-l10n-id="printui-scale"></label>
<div is="scale-input" id="scale-control" role="radiogroup"></div>
</section>
</details>
</section>
</section>
<footer class="footer-container">
<section id="system-print" class="row">
<a href="#" id="open-dialog-link" data-l10n-id="printui-system-dialog-link"></a>
</section>
<section id="button-container" class="row">
<button class="primary" name="print" data-l10n-id="printui-primary-button"></button>
<button name="cancel" data-l10n-id="printui-cancel-button"></button>
</section>
</footer>
</form>
</body> </body>
</html> </html>

Просмотреть файл

@ -4,12 +4,72 @@
const { gBrowser, PrintUtils } = window.docShell.chromeEventHandler.ownerGlobal; const { gBrowser, PrintUtils } = window.docShell.chromeEventHandler.ownerGlobal;
function initialize(sourceBrowser) { const PrintUI = {
document.getElementById("tab-title").textContent = sourceBrowser.contentTitle; initialize(sourceBrowser) {
document.getElementById("open-dialog-link").addEventListener("click", e => { this.sourceBrowser = sourceBrowser;
PrintUtils.printWindow(sourceBrowser.browsingContext);
}); this.form = document.querySelector("form#print");
} this._openDialogLink = document.querySelector("#open-dialog-link");
this._settingsSection = document.querySelector("#settings");
this._printerPicker = document.querySelector("#printer-picker");
this._sheetsCount = document.querySelector("#sheets-count");
this.form.addEventListener("submit", this);
this._openDialogLink.addEventListener("click", event => {
event.preventDefault();
PrintUtils.printWindow(sourceBrowser.browsingContext);
});
this._printerPicker.addEventListener("change", this);
this._settingsSection.addEventListener("change", this);
this.printDestinations = [];
this.printSettings = PrintUtils.getPrintSettings();
// TODO: figure out where this data comes from
this.numSheets = 1;
this.render();
},
render() {
console.log(
"TODO: populate the UI with printer listing with printDestinations:",
this.printDestinations
);
// TODO: populate the settings controls with an nsIPrintSettings
document.l10n.setAttributes(
this._sheetsCount,
this._sheetsCount.getAttribute("data-deferred-l10n-id"),
{
sheetCount: this.numSheets,
}
);
},
handleEvent(event) {
if (event.type == "submit" && event.target == this.form) {
event.preventDefault();
switch (event.submitter.name) {
case "print":
PrintUtils.printWindow(this.sourceBrowser.browsingContext, {
printSilent: true,
printerName: this._printerPicker.value,
});
break;
case "cancel":
console.log(
"TODO: trigger any teardown, exit the print preview and close the tab-modal"
);
break;
}
}
/* TODO:
* handle clicks to the system dialog link
* handle change of the selected printer/destination
* handle changes from each of the print settings controls
*/
},
};
function getSourceBrowser() { function getSourceBrowser() {
let params = new URLSearchParams(location.search); let params = new URLSearchParams(location.search);
@ -27,8 +87,133 @@ function getSourceBrowser() {
document.addEventListener("DOMContentLoaded", e => { document.addEventListener("DOMContentLoaded", e => {
let sourceBrowser = getSourceBrowser(); let sourceBrowser = getSourceBrowser();
if (sourceBrowser) { if (sourceBrowser) {
initialize(sourceBrowser); PrintUI.initialize(sourceBrowser);
} else { } else {
console.error("No source browser"); console.error("No source browser");
} }
}); });
/*
* Custom elements ----------------------------------------------------
*/
function PrintUIControlMixin(superClass) {
return class PrintUIControl extends superClass {
connectedCallback() {
this.initialize();
this.render();
}
initialize() {
if (this._initialized) {
return;
}
this._initialized = true;
if (this.templateId) {
let template = this.ownerDocument.getElementById(this.templateId);
let templateContent = template.content;
this.appendChild(templateContent.cloneNode(true));
}
}
render() {}
};
}
class DestinationPicker extends HTMLSelectElement {
setOptions(optionValues = []) {
console.log("DestinationPicker, setOptions:", optionValues);
this.textContent = "";
for (let optionData of optionValues) {
let opt = new Option(
optionData.name,
"value" in optionData ? optionData.value : optionData.name
);
if (optionData.selected) {
opt.selected = true;
}
this.options.add(opt);
}
}
}
customElements.define("destination-picker", DestinationPicker, {
extends: "select",
});
class OrientationInput extends PrintUIControlMixin(HTMLElement) {
get templateId() {
return "orientation-template";
}
constructor() {
super();
this._orientation = null;
}
render() {
console.log(
"TODO: populate/set orientation state from the current print settings"
);
}
}
customElements.define("orientation-input", OrientationInput);
class ScaleInput extends PrintUIControlMixin(HTMLElement) {
get templateId() {
return "scale-template";
}
render() {
console.log(
"TODO: populate/set print scale state from the current print settings"
);
}
}
customElements.define("scale-input", ScaleInput);
class PageRangeInput extends PrintUIControlMixin(HTMLElement) {
get templateId() {
return "page-range-template";
}
render() {
console.log(
"TODO: populate/set page-range state from the current print settings"
);
}
}
customElements.define("page-range-input", PageRangeInput);
class TwistySummary extends PrintUIControlMixin(HTMLElement) {
get isOpen() {
return this.closest("details")?.hasAttribute("open");
}
get templateId() {
return "twisty-summary-template";
}
initialize() {
if (this._initialized) {
return;
}
super.initialize();
this.label = this.querySelector(".label");
this.addEventListener("click", this);
this.updateSummary();
}
handleEvent(event) {
let willOpen = !this.isOpen;
this.updateSummary(willOpen);
}
updateSummary(open = false) {
document.l10n.setAttributes(
this.label,
open
? this.getAttribute("data-open-l10n-id")
: this.getAttribute("data-closed-l10n-id")
);
}
}
customElements.define("twisty-summary", TwistySummary);

Просмотреть файл

@ -0,0 +1,46 @@
# 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/.
printui-title = Print
# Variables
# $sheetCount (integer) - Number of paper sheets
printui-sheets-count =
{ $sheetCount ->
[one] { $sheetCount } sheet of paper
*[other] { $sheetCount } sheets of paper
}
printui-page-range-all = All
printui-page-range-custom = Custom
printui-page-range-label = Pages
printui-page-range-picker =
.aria-label = Pick page range
printui-page-custom-range =
.aria-label = Enter custom page range
# Section title for the number of copies to print
printui-copies-label = Copies
printui-orientation = Orientation
printui-landscape = Landscape
printui-portrait = Portrait
# Section title for the printer or destination device to target
printui-destination-label = Destination
printui-more-settings = More settings
printui-less-settings = Fewer settings
# Section title (noun) for the print scaling options
printui-scale = Scale
printui-scale-fit-to-page = Fit to page
# Label for input control where user can set the scale percentage
printui-scale-pcent = Scale
printui-system-dialog-link = Print using the system dialog…
printui-primary-button = Print
printui-cancel-button = Cancel