Bug 1457021 - Migrate the JS of Preferences::SitePermissions to Fluent. r?jaws,flod draft
authorZibi Braniecki <zbraniecki@mozilla.com>
Wed, 25 Apr 2018 16:24:39 -0700
changeset 793213 1d73e7eb2647bf912dfd0c59868895b417d9a457
parent 793212 b78569950e09025d2b6ef95ea144773ac9314fe1
child 793214 77a286768b7f2a4e534a7e78dfc4eaf3342b743b
push id109319
push userbmo:gandalf@aviary.pl
push dateWed, 09 May 2018 19:05:09 +0000
reviewersjaws, flod
bugs1457021
milestone62.0a1
Bug 1457021 - Migrate the JS of Preferences::SitePermissions to Fluent. r?jaws,flod 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