Bug 1469464 - Display the currency code with the total. r=sfoster draft
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Sat, 07 Jul 2018 23:23:43 -0700
changeset 817202 fa9cf2891af0b01e26771117573efffa7f0c9688
parent 817201 2f958be4842ff19804a034764bb22b7ae5743005
child 817203 b5686337e8e27164b45b8326cc0bb04560e8523e
push id115981
push usermozilla@noorenberghe.ca
push dateThu, 12 Jul 2018 06:45:37 +0000
reviewerssfoster
bugs1469464
milestone63.0a1
Bug 1469464 - Display the currency code with the total. r=sfoster MozReview-Commit-ID: JJIbFBAYC9U
browser/components/payments/res/components/currency-amount.js
browser/components/payments/res/paymentRequest.css
browser/components/payments/res/paymentRequest.xhtml
browser/components/payments/test/browser/browser_change_shipping.js
browser/components/payments/test/browser/browser_total.js
browser/components/payments/test/mochitest/test_currency_amount.html
--- a/browser/components/payments/res/components/currency-amount.js
+++ b/browser/components/payments/res/components/currency-amount.js
@@ -1,39 +1,74 @@
 /* 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/. */
 
 "use strict";
 
 /**
- * <currency-amount value="7.5" currency="USD"></currency-amount>
+ * <currency-amount value="7.5" currency="USD" display-code></currency-amount>
  */
 
 import ObservedPropertiesMixin from "../mixins/ObservedPropertiesMixin.js";
 
 export default class CurrencyAmount extends ObservedPropertiesMixin(HTMLElement) {
   static get observedAttributes() {
-    return ["currency", "value"];
+    return [
+      "currency",
+      "display-code",
+      "value",
+    ];
+  }
+
+  constructor() {
+    super();
+    this._currencyAmountTextNode = document.createTextNode("");
+    this._currencyCodeElement = document.createElement("span");
+    this._currencyCodeElement.classList.add("currency-code");
+  }
+
+  connectedCallback() {
+    if (super.connectedCallback) {
+      super.connectedCallback();
+    }
+
+    this.append(this._currencyAmountTextNode, this._currencyCodeElement);
   }
 
   render() {
-    let output = "";
+    let currencyAmount = "";
+    let currencyCode = "";
     try {
       if (this.value && this.currency) {
         let number = Number.parseFloat(this.value);
         if (Number.isNaN(number) || !Number.isFinite(number)) {
           throw new RangeError("currency-amount value must be a finite number");
         }
-        const formatter = new Intl.NumberFormat(navigator.languages, {
+        const symbolFormatter = new Intl.NumberFormat(navigator.languages, {
           style: "currency",
           currency: this.currency,
           currencyDisplay: "symbol",
         });
-        output = formatter.format(this.value);
+        currencyAmount = symbolFormatter.format(this.value);
+
+        if (this.displayCode !== null) {
+          // XXX: Bug 1473772 will move the separator to a Fluent string.
+          currencyAmount += " ";
+
+          const codeFormatter = new Intl.NumberFormat(navigator.languages, {
+            style: "currency",
+            currency: this.currency,
+            currencyDisplay: "code",
+          });
+          let parts = codeFormatter.formatToParts(this.value);
+          let currencyPart = parts.find(part => part.type == "currency");
+          currencyCode = currencyPart.value;
+        }
       }
     } finally {
-      this.textContent = output;
+      this._currencyAmountTextNode.textContent = currencyAmount;
+      this._currencyCodeElement.textContent = currencyCode;
     }
   }
 }
 
 customElements.define("currency-amount", CurrencyAmount);
--- a/browser/components/payments/res/paymentRequest.css
+++ b/browser/components/payments/res/paymentRequest.css
@@ -85,16 +85,21 @@ payment-dialog > footer {
   align-items: baseline;
   display: flex;
 }
 
 #total {
   flex: 1 1 auto;
   margin: 5px;
 }
+
+#total > currency-amount > .currency-code {
+  color: GrayText;
+}
+
 #view-all {
   flex: 0 1 auto;
 }
 
 #total .label {
   font-size: 15px;
   font-weight: bold;
 }
--- a/browser/components/payments/res/paymentRequest.xhtml
+++ b/browser/components/payments/res/paymentRequest.xhtml
@@ -78,18 +78,17 @@
   <script src="formautofill/autofillEditForms.js"></script>
 
   <script type="module" src="containers/payment-dialog.js"></script>
   <script type="module" src="paymentRequest.js"></script>
 
   <template id="payment-dialog-template">
     <header>
       <div id="total">
-        <h2 class="label"></h2>
-        <currency-amount></currency-amount>
+        <currency-amount display-code="display-code"></currency-amount>
         <div>&header.payTo; <span id="host-name"></span></div>
       </div>
       <div id="top-buttons" hidden="hidden">
         <button id="view-all" class="closed">&viewAllItems;</button>
       </div>
     </header>
 
     <div id="main-container">
--- a/browser/components/payments/test/browser/browser_change_shipping.js
+++ b/browser/components/payments/test/browser/browser_change_shipping.js
@@ -64,17 +64,17 @@ add_task(async function test_change_ship
     await spawnPaymentDialogTask(frame, async function() {
       let {
         PaymentTestUtils: PTU,
       } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
       // verify update of total
       // Note: The update includes a modifier, and modifiers must include a total
       // so the expected total is that one
       is(content.document.querySelector("#total > currency-amount").textContent,
-         "\u20AC2.50",
+         "\u20AC2.50 EUR",
          "Check updated total currency amount");
 
       let btn = content.document.querySelector("#view-all");
       btn.click();
       await PTU.DialogContentUtils.waitForState(content, (state) => {
         return state.orderDetailsShowing;
       }, "Order details show be showing now");
 
--- a/browser/components/payments/test/browser/browser_total.js
+++ b/browser/components/payments/test/browser/browser_total.js
@@ -1,45 +1,45 @@
 "use strict";
 
 add_task(async function test_total() {
   const testTask = ({methodData, details}) => {
     is(content.document.querySelector("#total > currency-amount").textContent,
-       "$60.00",
+       "$60.00 USD",
        "Check total currency amount");
   };
   const args = {
     methodData: [PTU.MethodData.basicCard],
     details: PTU.Details.total60USD,
   };
   await spawnInDialogForMerchantTask(PTU.ContentTasks.createAndShowRequest, testTask, args);
 });
 
 add_task(async function test_modifier_with_no_method_selected() {
   const testTask = async ({methodData, details}) => {
     // There are no payment methods installed/setup so we expect the original (unmodified) total.
     is(content.document.querySelector("#total > currency-amount").textContent,
-       "$2.00",
+       "$2.00 USD",
        "Check unmodified total currency amount");
   };
   const args = {
     methodData: [PTU.MethodData.bobPay, PTU.MethodData.basicCard],
     details: Object.assign({}, PTU.Details.bobPayPaymentModifier, PTU.Details.total2USD),
   };
   await spawnInDialogForMerchantTask(PTU.ContentTasks.createAndShowRequest, testTask, args);
 });
 
 add_task(async function test_modifier_with_no_method_selected() {
   info("adding a basic-card");
   await addSampleAddressesAndBasicCard();
 
   const testTask = async ({methodData, details}) => {
     // We expect the *only* payment method (the one basic-card) to be selected initially.
     is(content.document.querySelector("#total > currency-amount").textContent,
-       "$2.50",
+       "$2.50 USD",
        "Check modified total currency amount");
   };
   const args = {
     methodData: [PTU.MethodData.bobPay, PTU.MethodData.basicCard],
     details: Object.assign({}, PTU.Details.bobPayPaymentModifier, PTU.Details.total2USD),
   };
   await spawnInDialogForMerchantTask(PTU.ContentTasks.createAndShowRequest, testTask, args);
   await cleanupFormAutofillStorage();
--- a/browser/components/payments/test/mochitest/test_currency_amount.html
+++ b/browser/components/payments/test/mochitest/test_currency_amount.html
@@ -75,16 +75,36 @@ add_task(async function test_valid_curre
 
   is(amount1.getAttribute("value"), "12.34", "Check @value");
   is(amount1.value, "12.34", "Check .value");
   is(amount1.getAttribute("currency"), "CAD", "Check @currency");
   is(amount1.currency, "CAD", "Check .currency");
   is(amount1.textContent, "CA$12.34", "Check output format");
 });
 
+add_task(async function test_valid_currency_amount_displayCode() {
+  amount1.value = 12.34;
+  info("showing the currency code");
+  await asyncElementRendered();
+  amount1.currency = "CAD";
+  await asyncElementRendered();
+  amount1.displayCode = true;
+  await asyncElementRendered();
+
+  is(amount1.getAttribute("value"), "12.34", "Check @value");
+  is(amount1.value, "12.34", "Check .value");
+  is(amount1.getAttribute("currency"), "CAD", "Check @currency");
+  is(amount1.currency, "CAD", "Check .currency");
+  is(amount1.textContent, "CA$12.34 CAD", "Check output format");
+
+  amount1.displayCode = false;
+  await asyncElementRendered();
+});
+
+
 add_task(async function test_valid_currency_amount_eur_batched_prop() {
   info("setting two properties in a row synchronously");
   amount1.value = 98.76;
   amount1.currency = "EUR";
   await asyncElementRendered();
 
   is(amount1.getAttribute("value"), "98.76", "Check @value");
   is(amount1.value, "98.76", "Check .value");