Bug 1652861 - Rough in UI for printer selection and print settings. r=mstriemer,fluent-reviewers,flod
☠☠ backed out by bad2c20d6a8c ☠ ☠
authorSam Foster <sfoster@mozilla.com>
Mon, 20 Jul 2020 23:25:03 +0000
changeset 541380 bd60589d467800389ce50d06dc0e1fd341e29435
parent 541379 1b2a23e03483491a338610413b0993220e73180c
child 541381 cd5b31b3b27ceac4815595b6b48e286b2c56a594
push id122205
push usersfoster@mozilla.com
push dateMon, 20 Jul 2020 23:36:31 +0000
treeherderautoland@bd60589d4678 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstriemer, fluent-reviewers, flod
bugs1652861
milestone80.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
toolkit/components/printing/content/print.css
toolkit/components/printing/content/print.html
toolkit/components/printing/content/print.js
toolkit/locales/en-US/toolkit/printing/printUI.ftl
--- a/toolkit/components/printing/content/print.css
+++ b/toolkit/components/printing/content/print.css
@@ -1,3 +1,101 @@
 /* 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/. */
+
+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;
+}
--- a/toolkit/components/printing/content/print.html
+++ b/toolkit/components/printing/content/print.html
@@ -1,17 +1,110 @@
 <!doctype html>
 <!-- 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/. -->
 <html>
   <head>
+    <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/printDialogs.ftl">
+    <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/content/print.css">
-    <link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
     <script defer src="chrome://global/content/print.js"></script>
   </head>
 
   <body>
-    <h1>Print</h1>
-    <h2 id="tab-title"></h2>
-    <a href="#" id="open-dialog-link">Open Native Dialog...</a>
+    <template id="page-range-template">
+      <select id="range-picker" name="page-range-type" data-l10n-id="printui-page-range-picker">
+        <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>
 </html>
--- a/toolkit/components/printing/content/print.js
+++ b/toolkit/components/printing/content/print.js
@@ -1,20 +1,80 @@
 /* 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/. */
 
 const { gBrowser, PrintUtils } = window.docShell.chromeEventHandler.ownerGlobal;
 
-function initialize(sourceBrowser) {
-  document.getElementById("tab-title").textContent = sourceBrowser.contentTitle;
-  document.getElementById("open-dialog-link").addEventListener("click", e => {
-    PrintUtils.printWindow(sourceBrowser.browsingContext);
-  });
-}
+const PrintUI = {
+  initialize(sourceBrowser) {
+    this.sourceBrowser = sourceBrowser;
+
+    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() {
   let params = new URLSearchParams(location.search);
   let browsingContextId = params.get("browsingContextId");
   if (!browsingContextId) {
     return null;
   }
   let browsingContext = BrowsingContext.get(browsingContextId);
@@ -22,13 +82,138 @@ function getSourceBrowser() {
     return null;
   }
   return browsingContext.embedderElement;
 }
 
 document.addEventListener("DOMContentLoaded", e => {
   let sourceBrowser = getSourceBrowser();
   if (sourceBrowser) {
-    initialize(sourceBrowser);
+    PrintUI.initialize(sourceBrowser);
   } else {
     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);
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/toolkit/printing/printUI.ftl
@@ -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
+