Bug 1457021 - Migrate the JS of Preferences::SitePermissions to Fluent. r=flod,jaws
authorZibi Braniecki <zbraniecki@mozilla.com>
Wed, 25 Apr 2018 16:24:39 -0700
changeset 417618 3beeaf20f46a
parent 417617 4d66223323b4
child 417619 34bc72be5d28
push id63776
push userzbraniecki@mozilla.com
push dateWed, 09 May 2018 20:03:09 +0000
treeherderautoland@af2f85201ec2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflod, jaws
bugs1457021
milestone62.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 1457021 - Migrate the JS of Preferences::SitePermissions to Fluent. r=flod,jaws MozReview-Commit-ID: Fe4Q6CnTcuj
browser/components/preferences/in-content/privacy.js
browser/components/preferences/in-content/tests/browser_permissions_dialog.js
browser/components/preferences/in-content/tests/siteData/browser_siteData3.js
browser/components/preferences/sitePermissions.js
browser/components/preferences/sitePermissions.xul
browser/locales/en-US/browser/preferences/permissions.ftl
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -317,18 +317,16 @@ var gPrivacyPane = {
       gPrivacyPane.showCameraExceptions);
     setEventListener("microphoneSettingsButton", "command",
       gPrivacyPane.showMicrophoneExceptions);
     setEventListener("popupPolicyButton", "command",
       gPrivacyPane.showPopupExceptions);
     setEventListener("notificationsDoNotDisturb", "command",
       gPrivacyPane.toggleDoNotDisturbNotifications);
 
-    let bundlePrefs = document.getElementById("bundlePreferences");
-
     if (AlertsServiceDND) {
       let notificationsDoNotDisturbBox =
         document.getElementById("notificationsDoNotDisturbBox");
       notificationsDoNotDisturbBox.removeAttribute("hidden");
       let checkbox = document.getElementById("notificationsDoNotDisturb");
       document.l10n.setAttributes(checkbox, "permissions-notification-pause");
       if (AlertsServiceDND.manualDoNotDisturb) {
         let notificationsDoNotDisturb =
--- a/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
+++ b/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
@@ -14,29 +14,32 @@ var sitePermissionsDialog;
 
 function checkPermissionItem(origin, state) {
   let doc = sitePermissionsDialog.document;
 
   let label = doc.getElementsByTagName("label")[0];
   Assert.equal(label.value, origin);
 
   let menulist = doc.getElementsByTagName("menulist")[0];
-  Assert.equal(menulist.label, state);
+  let selectedIndex = menulist.selectedIndex;
+  let selectedItem = menulist.querySelectorAll("menuitem")[selectedIndex];
+  Assert.equal(selectedItem.value, state);
 }
 
 async function openPermissionsDialog() {
   let dialogOpened = promiseLoadSubDialog(PERMISSIONS_URL);
 
   await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     let doc = content.document;
     let settingsButton = doc.getElementById("notificationSettingsButton");
     settingsButton.click();
   });
 
   sitePermissionsDialog = await dialogOpened;
+  await sitePermissionsDialog.document.mozSubdialogReady;
 }
 
 add_task(async function openSitePermissionsDialog() {
   await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
   await openPermissionsDialog();
 });
 
 add_task(async function addPermission() {
@@ -47,28 +50,28 @@ add_task(async function addPermission() 
   Assert.equal(richlistbox.itemCount, 0,
                "Number of permission items is 0 initially");
 
   // Add notification permission for a website.
   SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
 
   // Observe the added permission changes in the dialog UI.
   Assert.equal(richlistbox.itemCount, 1);
-  checkPermissionItem(URL, "Allow");
+  checkPermissionItem(URL, Services.perms.ALLOW_ACTION);
 
   SitePermissions.remove(URL, "desktop-notification");
 });
 
 add_task(async function observePermissionChange() {
   SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
 
   // Change the permission.
   SitePermissions.set(URI, "desktop-notification", SitePermissions.BLOCK);
 
-  checkPermissionItem(URL, "Block");
+  checkPermissionItem(URL, Services.perms.DENY_ACTION);
 
   SitePermissions.remove(URL, "desktop-notification");
 });
 
 add_task(async function observePermissionDelete() {
   let doc = sitePermissionsDialog.document;
   let richlistbox = doc.getElementById("permissionsBox");
 
--- a/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js
+++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js
@@ -86,20 +86,21 @@ add_task(async function() {
 
   let columns = siteItems[0].querySelectorAll(".item-box > label");
 
   let expected = "account.xyz.com";
   is(columns[0].value, expected, "Should group and list sites by host");
 
   is(columns[1].value, "5", "Should group cookies across scheme, port and origin attributes");
 
-  let prefStrBundle = frameDoc.getElementById("bundlePreferences");
-  expected = prefStrBundle.getFormattedString("siteUsagePersistent",
-    DownloadUtils.convertByteUnits(quotaUsage * mockSiteDataManager.fakeSites.length));
-  is(columns[2].value, expected, "Should sum up usages across scheme, port, origin attributes and persistent status");
+  let [value, unit] = DownloadUtils.convertByteUnits(quotaUsage * mockSiteDataManager.fakeSites.length);
+  Assert.deepEqual(frameDoc.l10n.getAttributes(columns[2]), {
+    id: "site-usage-persistent",
+    args: { value, unit }
+  }, "Should sum up usages across scheme, port, origin attributes and persistent status");
 
   await mockSiteDataManager.unregister();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 // Test sorting
 add_task(async function() {
   mockSiteDataManager.register(SiteDataManager, [
--- a/browser/components/preferences/sitePermissions.js
+++ b/browser/components/preferences/sitePermissions.js
@@ -28,34 +28,33 @@ const sitePermissionsL10n = {
   "microphone": {
     window: "permissions-site-microphone-window",
     description: "permissions-site-microphone-desc",
     disableLabel: "permissions-site-microphone-disable-label",
     disableDescription: "permissions-site-microphone-disable-desc",
   },
 };
 
-function Permission(principal, type, capability, capabilityString) {
+function Permission(principal, type, capability, l10nId) {
   this.principal = principal;
   this.origin = principal.origin;
   this.type = type;
   this.capability = capability;
-  this.capabilityString = capabilityString;
+  this.l10nId = l10nId;
 }
 
 const PERMISSION_STATES = [SitePermissions.ALLOW, SitePermissions.BLOCK, SitePermissions.PROMPT];
 
 var gSitePermissionsManager = {
   _type: "",
   _isObserving: false,
   _permissions: new Map(),
   _permissionsToChange: new Map(),
   _permissionsToDelete: new Map(),
   _list: null,
-  _bundle: null,
   _removeButton: null,
   _removeAllButton: null,
   _searchBox: null,
   _checkbox: null,
   _currentDefaultPermissionsState: null,
   _defaultPermissionStatePrefName: null,
 
   onLoad() {
@@ -64,17 +63,16 @@ var gSitePermissionsManager = {
   },
 
   async init(params) {
     if (!this._isObserving) {
       Services.obs.addObserver(this, "perm-changed");
       this._isObserving = true;
     }
 
-    this._bundle = document.getElementById("bundlePreferences");
     this._type = params.permissionType;
     this._list = document.getElementById("permissionsBox");
     this._removeButton = document.getElementById("removePermission");
     this._removeAllButton = document.getElementById("removeAllPermissions");
     this._searchBox = document.getElementById("searchBox");
     this._checkbox = document.getElementById("permissionsDisableCheckbox");
 
     let permissionsDisableDescription = document.getElementById("permissionsDisableDescription");
@@ -105,17 +103,17 @@ var gSitePermissionsManager = {
       permissionsDisableDescription.setAttribute("hidden", true);
     } else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
       this._checkbox.checked = true;
     } else {
       this._checkbox.checked = false;
     }
 
     this._loadPermissions();
-    this.buildPermissionsList();
+    await this.buildPermissionsList();
 
     this._searchBox.focus();
   },
 
   uninit() {
     if (this._isObserving) {
       Services.obs.removeObserver(this, "perm-changed");
       this._isObserving = false;
@@ -133,17 +131,17 @@ var gSitePermissionsManager = {
       return;
 
     if (data == "added") {
       this._addPermissionToList(permission);
       this.buildPermissionsList();
     } else if (data == "changed") {
       let p = this._permissions.get(permission.principal.origin);
       p.capability = permission.capability;
-      p.capabilityString = this._getCapabilityString(permission.capability);
+      p.l10nId = this._getCapabilityString(permission.capability);
       this._handleCapabilityChange(p);
       this.buildPermissionsList();
     } else if (data == "deleted") {
       this._removePermissionFromList(permission.principal.origin);
     }
   },
 
   _handleCapabilityChange(perm) {
@@ -152,35 +150,36 @@ var gSitePermissionsManager = {
     menulist.selectedItem =
       menulist.getElementsByAttribute("value", perm.capability)[0];
   },
 
   _getCapabilityString(capability) {
     let stringKey = null;
     switch (capability) {
     case Services.perms.ALLOW_ACTION:
-      stringKey = "can";
+      stringKey = "permissions-capabilities-allow";
       break;
     case Services.perms.DENY_ACTION:
-      stringKey = "cannot";
+      stringKey = "permissions-capabilities-block";
       break;
     case Services.perms.PROMPT_ACTION:
-      stringKey = "prompt";
+      stringKey = "permissions-capabilities-prompt";
       break;
+    default:
+        throw new Error(`Unknown capability: ${capability}`);
     }
-    return this._bundle.getString(stringKey);
+    return stringKey;
   },
 
   _addPermissionToList(perm) {
     // Ignore unrelated permission types and permissions with unknown states.
     if (perm.type !== this._type || !PERMISSION_STATES.includes(perm.capability))
       return;
-    let capabilityString = this._getCapabilityString(perm.capability);
-    let p = new Permission(perm.principal, perm.type, perm.capability,
-                           capabilityString);
+    let l10nId = this._getCapabilityString(perm.capability);
+    let p = new Permission(perm.principal, perm.type, perm.capability, l10nId);
     this._permissions.set(p.origin, p);
   },
 
   _removePermissionFromList(origin) {
     this._permissions.delete(origin);
     let permissionlistitem = document.getElementsByAttribute("origin", origin)[0];
     if (permissionlistitem) {
       permissionlistitem.remove();
@@ -223,30 +222,30 @@ var gSitePermissionsManager = {
       // PROMPT permission set for an origin.
       if (state == SitePermissions.UNKNOWN &&
           permission.capability == SitePermissions.PROMPT) {
         state = SitePermissions.PROMPT;
       } else if (state == SitePermissions.UNKNOWN) {
         continue;
       }
       let m = document.createElement("menuitem");
-      m.setAttribute("label", this._getCapabilityString(state));
+      document.l10n.setAttributes(m, this._getCapabilityString(state));
       m.setAttribute("value", state);
       menupopup.appendChild(m);
     }
     menulist.value = permission.capability;
 
     menulist.addEventListener("select", () => {
       this.onPermissionChange(permission, Number(menulist.selectedItem.value));
     });
 
     row.appendChild(hbox);
     row.appendChild(menulist);
     richlistitem.appendChild(row);
-    this._list.appendChild(richlistitem);
+    return richlistitem;
   },
 
   onWindowKeyPress(event) {
     if (event.keyCode == KeyEvent.DOM_VK_ESCAPE)
       window.close();
   },
 
   onPermissionKeyPress(event) {
@@ -295,17 +294,17 @@ var gSitePermissionsManager = {
     this._setRemoveButtonState();
   },
 
   onPermissionChange(perm, capability) {
     let p = this._permissions.get(perm.origin);
     if (p.capability == capability)
       return;
     p.capability = capability;
-    p.capabilityString = this._getCapabilityString(capability);
+    p.l10nId = this._getCapabilityString(capability);
     this._permissionsToChange.set(p.origin, p);
 
     // enable "remove all" button as needed
     this._setRemoveButtonState();
   },
 
   onApplyChanges() {
     // Stop observing permission changes since we are about
@@ -327,75 +326,88 @@ var gSitePermissionsManager = {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.BLOCK);
     } else if (this._currentDefaultPermissionsState == SitePermissions.BLOCK) {
       Services.prefs.setIntPref(this._defaultPermissionStatePrefName, SitePermissions.UNKNOWN);
     }
 
     window.close();
   },
 
-  buildPermissionsList(sortCol) {
+  async buildPermissionsList(sortCol) {
     // Clear old entries.
     let oldItems = this._list.querySelectorAll("richlistitem");
     for (let item of oldItems) {
       item.remove();
     }
+    let frag = document.createDocumentFragment();
 
-    // Sort permissions.
-    let sortedPermissions = this._sortPermissions(sortCol);
+    let permissions = Array.from(this._permissions.values());
 
     let keyword = this._searchBox.value.toLowerCase().trim();
-    for (let permission of sortedPermissions) {
+    for (let permission of permissions) {
       if (keyword && !permission.origin.includes(keyword)) {
         continue;
       }
 
-      this._createPermissionListItem(permission);
+      let richlistitem = this._createPermissionListItem(permission);
+      frag.appendChild(richlistitem);
     }
 
+    // Sort permissions.
+    this._sortPermissions(this._list, frag, sortCol);
+
+    this._list.appendChild(frag);
+
     this._setRemoveButtonState();
   },
 
-  _sortPermissions(column) {
-    let permissions = Array.from(this._permissions.values());
+  _sortPermissions(list, frag, column) {
     let sortDirection;
 
     if (!column) {
       column = document.querySelector("treecol[data-isCurrentSortCol=true]");
       sortDirection = column.getAttribute("data-last-sortDirection") || "ascending";
     } else {
       sortDirection = column.getAttribute("data-last-sortDirection");
       sortDirection = sortDirection === "ascending" ? "descending" : "ascending";
     }
 
     let sortFunc = null;
     switch (column.id) {
       case "siteCol":
         sortFunc = (a, b) => {
-          return a.origin.localeCompare(b.origin);
+          return comp.compare(a.getAttribute("origin"), b.getAttribute("origin"));
         };
         break;
 
       case "statusCol":
         sortFunc = (a, b) => {
-          return a.capabilityString.localeCompare(b.capabilityString);
+          return parseInt(a.querySelector("menulist").value) >
+            parseInt(b.querySelector("menulist").value);
         };
         break;
     }
 
+    let comp = new Services.intl.Collator(undefined, {
+      usage: "sort"
+    });
+
+    let items = Array.from(frag.querySelectorAll("richlistitem"));
+
     if (sortDirection === "descending") {
-      permissions.sort((a, b) => sortFunc(b, a));
+      items.sort((a, b) => sortFunc(b, a));
     } else {
-      permissions.sort(sortFunc);
+      items.sort(sortFunc);
     }
 
-    let cols = this._list.querySelectorAll("treecol");
+    // Re-append items in the correct order:
+    items.forEach(item => frag.appendChild(item));
+
+    let cols = list.querySelectorAll("treecol");
     cols.forEach(c => {
       c.removeAttribute("data-isCurrentSortCol");
       c.removeAttribute("sortDirection");
     });
     column.setAttribute("data-isCurrentSortCol", "true");
     column.setAttribute("sortDirection", sortDirection);
     column.setAttribute("data-last-sortDirection", sortDirection);
-
-    return permissions;
   },
 };
--- a/browser/components/preferences/sitePermissions.xul
+++ b/browser/components/preferences/sitePermissions.xul
@@ -18,19 +18,16 @@
         persist="screenX screenY width height"
         onkeypress="gSitePermissionsManager.onWindowKeyPress(event);">
 
   <link rel="localization" href="browser/preferences/permissions.ftl"/>
   <script type="application/javascript" src="chrome://global/content/l10n.js"></script>
 
   <script src="chrome://browser/content/preferences/sitePermissions.js"/>
 
-  <stringbundle id="bundlePreferences"
-                src="chrome://browser/locale/preferences/preferences.properties"/>
-
   <keyset>
     <key data-l10n-id="permissions-close-key" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="contentPane largeDialogContainer" flex="1">
     <description id="permissionsText" control="url"/>
     <separator class="thin"/>
     <hbox align="start">
--- a/browser/locales/en-US/browser/preferences/permissions.ftl
+++ b/browser/locales/en-US/browser/preferences/permissions.ftl
@@ -44,16 +44,22 @@ permissions-button-cancel =
 
 permissions-button-ok =
     .label = Save Changes
     .accesskey = S
 
 permissions-searchbox =
     .placeholder = Search Website
 
+permissions-capabilities-allow =
+    .label = Allow
+permissions-capabilities-block =
+    .label = Block
+permissions-capabilities-prompt =
+    .label = Always Ask
 
 ## Invalid Hostname Dialog
 
 permissions-invalid-uri-title = Invalid Hostname Entered
 permissions-invalid-uri-label = Please enter a valid hostname
 
 ## Exceptions - Tracking Protection