Bug 1495530 - Use card icons in form autofill card preferences screen. r=MattN
authorSam Foster <sfoster@mozilla.com>
Wed, 03 Oct 2018 15:58:16 +0000
changeset 487788 32cde67dd330391a0fb6735be8309a64e646a5f7
parent 487787 ba9d952a37de83181cbf5e2ab3f35032401c75c8
child 487789 b58cfd180ba7f5d7daeb419b1c038c7ca182c9a4
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewersMattN
bugs1495530
milestone64.0a1
Bug 1495530 - Use card icons in form autofill card preferences screen. r=MattN Differential Revision: https://phabricator.services.mozilla.com/D7334
browser/extensions/formautofill/content/manageDialog.css
browser/extensions/formautofill/content/manageDialog.js
browser/extensions/formautofill/test/browser/browser_manageCreditCardsDialog.js
--- a/browser/extensions/formautofill/content/manageDialog.css
+++ b/browser/extensions/formautofill/content/manageDialog.css
@@ -67,13 +67,65 @@ option:nth-child(even) {
 
 #edit {
   margin-inline-end: 0;
 }
 
 #credit-cards > option::before {
   content: "";
   background: url("icon-credit-card-generic.svg") no-repeat;
+  background-size: contain;
   float: left;
   width: 16px;
   height: 16px;
   padding-inline-end: 10px;
 }
+
+/*
+  We use .png / @2x.png images where we don't yet have a vector version of a logo
+*/
+#credit-cards.branded > option[cc-type="amex"]::before {
+  background-image: url("third-party/cc-logo-amex.png");
+}
+
+#credit-cards.branded > option[cc-type="cartebancaire"]::before {
+  background-image: url("third-party/cc-logo-cartebancaire.png");
+}
+
+#credit-cards.branded > option[cc-type="diners"]::before {
+  background-image: url("third-party/cc-logo-diners.svg");
+}
+
+#credit-cards.branded > option[cc-type="discover"]::before {
+  background-image: url("third-party/cc-logo-discover.png");
+}
+
+#credit-cards.branded > option[cc-type="jcb"]::before {
+  background-image: url("third-party/cc-logo-jcb.svg");
+}
+
+#credit-cards.branded > option[cc-type="mastercard"]::before {
+  background-image: url("third-party/cc-logo-mastercard.svg");
+}
+
+#credit-cards.branded > option[cc-type="mir"]::before {
+  background-image: url("third-party/cc-logo-mir.svg");
+}
+
+#credit-cards.branded > option[cc-type="unionpay"]::before {
+  background-image: url("third-party/cc-logo-unionpay.svg");
+}
+
+#credit-cards.branded > option[cc-type="visa"]::before {
+  background-image: url("third-party/cc-logo-visa.svg");
+}
+
+@media (min-resolution: 1.1dppx) {
+  #credit-cards.branded > option[cc-type="amex"]::before {
+    background-image: url("third-party/cc-logo-amex@2x.png");
+  }
+  #credit-cards.branded > option[cc-type="cartebancaire"]::before {
+    background-image: url("third-party/cc-logo-cartebancaire@2x.png");
+  }
+  #credit-cards.branded > option[cc-type="discover"]::before {
+    background-image: url("third-party/cc-logo-discover@2x.png");
+  }
+}
--- a/browser/extensions/formautofill/content/manageDialog.js
+++ b/browser/extensions/formautofill/content/manageDialog.js
@@ -6,16 +6,17 @@
 
 "use strict";
 
 const EDIT_ADDRESS_URL = "chrome://formautofill/content/editAddress.xhtml";
 const EDIT_CREDIT_CARD_URL = "chrome://formautofill/content/editCreditCard.xhtml";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://formautofill/FormAutofill.jsm");
+ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 ChromeUtils.defineModuleGetter(this, "CreditCard",
                                "resource://gre/modules/CreditCard.jsm");
 ChromeUtils.defineModuleGetter(this, "formAutofillStorage",
                                "resource://formautofill/FormAutofillStorage.jsm");
 ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
                                "resource://formautofill/FormAutofillUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "MasterPassword",
@@ -363,17 +364,29 @@ class ManageCreditCards extends ManageRe
     }
     // For testing only: Notify when credit cards labels have been updated
     this._elements.records.dispatchEvent(new CustomEvent("LabelsUpdated"));
   }
 
   async renderRecordElements(records) {
     // Revert back to encrypted form when re-rendering happens
     this._isDecrypted = false;
+    // Display third-party card icons when possible
+    this._elements.records.classList.toggle("branded", AppConstants.MOZILLA_OFFICIAL);
     await super.renderRecordElements(records);
+
+    let options = this._elements.records.options;
+    for (let option of options) {
+      let record = option.record;
+      if (record && record["cc-type"]) {
+        option.setAttribute("cc-type", record["cc-type"]);
+      } else {
+        option.removeAttribute("cc-type");
+      }
+    }
   }
 
   updateButtonsStates(selectedCount) {
     this.updateShowHideButtonState();
     super.updateButtonsStates(selectedCount);
   }
 
   updateShowHideButtonState() {
--- a/browser/extensions/formautofill/test/browser/browser_manageCreditCardsDialog.js
+++ b/browser/extensions/formautofill/test/browser/browser_manageCreditCardsDialog.js
@@ -153,16 +153,52 @@ add_task(async function test_showCreditC
   await removeCreditCards([selRecords.options[1].value]);
   await removeCreditCards([selRecords.options[0].value]);
   await BrowserTestUtils.waitForEvent(selRecords, "RecordsLoaded");
   is(btnShowHideCreditCards.disabled, true, "Show credit cards button is disabled when there is no card");
 
   win.close();
 });
 
+add_task(async function test_showCreditCardIcons() {
+  await SpecialPowers.pushPrefEnv({"set": [["privacy.reduceTimerPrecision", false]]});
+  await saveCreditCard(TEST_CREDIT_CARD_1);
+  let unknownCard = Object.assign({}, TEST_CREDIT_CARD_3, {"cc-type": "gringotts"});
+  await saveCreditCard(unknownCard);
+
+  let win = window.openDialog(MANAGE_CREDIT_CARDS_DIALOG_URL, null, DIALOG_SIZE);
+  await waitForFocusAndFormReady(win);
+
+  let selRecords = win.document.querySelector(TEST_SELECTORS.selRecords);
+
+  is(selRecords.classList.contains("branded"), AppConstants.MOZILLA_OFFICIAL,
+     "record picker has 'branded' class in an MOZILLA_OFFICIAL build");
+
+  let option0 = selRecords.options[0];
+  let icon0Url = win.getComputedStyle(option0, "::before").backgroundImage;
+  let option1 = selRecords.options[1];
+  let icon1Url = win.getComputedStyle(option1, "::before").backgroundImage;
+
+  is(option0.getAttribute("cc-type"), "gringotts", "Option has the expected cc-type");
+  is(option1.getAttribute("cc-type"), "visa", "Option has the expected cc-type");
+
+  if (AppConstants.MOZILLA_OFFICIAL) {
+    ok(icon0Url.includes("icon-credit-card-generic.svg"),
+       "unknown network option ::before element has the generic icon as backgroundImage: " + icon0Url);
+    ok(icon1Url.includes("cc-logo-visa.svg"),
+       "visa option ::before element has the visa icon as backgroundImage " + icon1Url);
+  }
+
+  await removeCreditCards([option0.value, option1.value]);
+  await BrowserTestUtils.waitForEvent(selRecords, "RecordsLoaded");
+  is(selRecords.length, 0, "Credit card is removed");
+  win.close();
+});
+
+
 add_task(async function test_hasMasterPassword() {
   await saveCreditCard(TEST_CREDIT_CARD_1);
   LoginTestUtils.masterPassword.enable();
 
   let win = window.openDialog(MANAGE_CREDIT_CARDS_DIALOG_URL, null, DIALOG_SIZE);
   await waitForFocusAndFormReady(win);
 
   let selRecords = win.document.querySelector(TEST_SELECTORS.selRecords);