Bug 1385221 - Implement Permission sorting in the Permissions dialog. r?johannh draft
authorPrathiksha <prathikshaprasadsuman@gmail.com>
Wed, 16 Aug 2017 21:27:02 +0530
changeset 661459 2de1a8b71901f609ad2e3558c6abf1a8594318b0
parent 661321 50857982881ae7803ceb438fee90650a282f7f05
child 730571 fc3daee84248b03ca63056e6fccc2958e8396e9a
push id78758
push userbmo:prathikshaprasadsuman@gmail.com
push dateFri, 08 Sep 2017 13:12:40 +0000
reviewersjohannh
bugs1385221
milestone57.0a1
Bug 1385221 - Implement Permission sorting in the Permissions dialog. r?johannh MozReview-Commit-ID: 1F9eZ54ppbB
browser/components/preferences/in-content/tests/browser_permissions_dialog.js
browser/components/preferences/sitePermissions.js
browser/components/preferences/sitePermissions.xul
--- a/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
+++ b/browser/components/preferences/in-content/tests/browser_permissions_dialog.js
@@ -225,13 +225,52 @@ add_task(async function onSearch() {
   SitePermissions.set(u, "desktop-notification", SitePermissions.ALLOW);
 
   Assert.equal(doc.getElementsByAttribute("origin", "http://www.test.com")[0], null);
   Assert.equal(doc.getElementsByAttribute("origin", "http://www.example.com")[0],
                richlistbox.getItemAtIndex(0));
 
   SitePermissions.remove(URI, "desktop-notification");
   SitePermissions.remove(u, "desktop-notification");
+
+  doc.getElementById("cancel").click();
+});
+
+add_task(async function onPermissionsSort() {
+  SitePermissions.set(URI, "desktop-notification", SitePermissions.ALLOW);
+  let u = Services.io.newURI("http://www.test.com");
+  SitePermissions.set(u, "desktop-notification", SitePermissions.BLOCK);
+
+  await openPermissionsDialog();
+  let doc = sitePermissionsDialog.document;
+  let richlistbox = doc.getElementById("permissionsBox");
+
+  // Test default arrangement(Allow followed by Block).
+  Assert.equal(richlistbox.getItemAtIndex(0).getAttribute("origin"), "http://www.example.com");
+  Assert.equal(richlistbox.getItemAtIndex(1).getAttribute("origin"), "http://www.test.com");
+
+  doc.getElementById("statusCol").click();
+
+  // Test the rearrangement(Block followed by Allow).
+  Assert.equal(richlistbox.getItemAtIndex(0).getAttribute("origin"), "http://www.test.com");
+  Assert.equal(richlistbox.getItemAtIndex(1).getAttribute("origin"), "http://www.example.com");
+
+  doc.getElementById("siteCol").click();
+
+  // Test the rearrangement(Website names arranged in alphabhetical order).
+  Assert.equal(richlistbox.getItemAtIndex(0).getAttribute("origin"), "http://www.example.com");
+  Assert.equal(richlistbox.getItemAtIndex(1).getAttribute("origin"), "http://www.test.com");
+
+  doc.getElementById("siteCol").click();
+
+  // Test the rearrangement(Website names arranged in reverse alphabhetical order).
+  Assert.equal(richlistbox.getItemAtIndex(0).getAttribute("origin"), "http://www.test.com");
+  Assert.equal(richlistbox.getItemAtIndex(1).getAttribute("origin"), "http://www.example.com");
+
+  SitePermissions.remove(URI, "desktop-notification");
+  SitePermissions.remove(u, "desktop-notification");
+
+  doc.getElementById("cancel").click();
 });
 
 add_task(async function removeTab() {
   gBrowser.removeCurrentTab();
 });
--- a/browser/components/preferences/sitePermissions.js
+++ b/browser/components/preferences/sitePermissions.js
@@ -47,16 +47,17 @@ var gSitePermissionsManager = {
     let permissionsText = document.getElementById("permissionsText");
     while (permissionsText.hasChildNodes())
       permissionsText.firstChild.remove();
     permissionsText.appendChild(document.createTextNode(params.introText));
 
     document.title = params.windowTitle;
 
     this._loadPermissions();
+    this.buildPermissionsList();
 
     this._searchBox.focus();
   },
 
   uninit() {
     if (this._isObserving) {
       Services.obs.removeObserver(this, "perm-changed");
       this._isObserving = false;
@@ -70,24 +71,23 @@ var gSitePermissionsManager = {
     let permission = subject.QueryInterface(Components.interfaces.nsIPermission);
 
     // Ignore unrelated permission types.
     if (permission.type !== this._type)
       return;
 
     if (data == "added") {
       this._addPermissionToList(permission);
-      if (this._searchBox.value != "") {
-        this.filterPermissionsList();
-      }
+      this.buildPermissionsList();
     } else if (data == "changed") {
       let p = this._permissions.get(permission.principal.origin);
       p.capability = permission.capability;
       p.capabilityString = this._getCapabilityString(permission.capability);
       this._handleCapabilityChange(p);
+      this.buildPermissionsList();
     } else if (data == "deleted") {
       this._removePermissionFromList(permission.principal.origin);
     }
   },
 
   _handleCapabilityChange(perm) {
     let permissionlistitem = document.getElementsByAttribute("origin", perm.origin)[0];
     let menulist = permissionlistitem.getElementsByTagName("menulist")[0];
@@ -113,35 +113,31 @@ var gSitePermissionsManager = {
 
   _addPermissionToList(perm) {
     if (perm.type !== this._type)
       return;
     let capabilityString = this._getCapabilityString(perm.capability);
     let p = new Permission(perm.principal, perm.type, perm.capability,
                            capabilityString);
     this._permissions.set(p.origin, p);
-    this._createPermissionListItem(p);
   },
 
   _removePermissionFromList(origin) {
     this._permissions.delete(origin);
     let permissionlistitem = document.getElementsByAttribute("origin", origin)[0];
     this._list.removeItemAt(this._list.getIndexOfItem(permissionlistitem));
   },
 
   _loadPermissions() {
     // load permissions into a table.
     let enumerator = Services.perms.enumerator;
     while (enumerator.hasMoreElements()) {
       let nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
       this._addPermissionToList(nextPermission);
     }
-
-    // disable "remove all" button if there are none
-    this._setRemoveButtonState();
   },
 
   _createPermissionListItem(permission) {
     let richlistitem = document.createElement("richlistitem");
     richlistitem.setAttribute("origin", permission.origin);
     let row = document.createElement("hbox");
     row.setAttribute("flex", "1");
 
@@ -255,27 +251,75 @@ var gSitePermissionsManager = {
 
     for (let p of this._permissionsToDelete.values()) {
       let uri = Services.io.newURI(p.origin);
       SitePermissions.remove(uri, p.type);
     }
     window.close();
   },
 
-  filterPermissionsList() {
+  buildPermissionsList(sortCol) {
     // Clear old entries.
     let oldItems = this._list.querySelectorAll("richlistitem");
     for (let item of oldItems) {
       item.remove();
     }
 
+    // Sort permissions.
+    let sortedPermissions = this._sortPermissions(sortCol);
+
     let keyword = this._searchBox.value.toLowerCase().trim();
-    let permissions = this._permissions;
-    for (let [origin, permission] of permissions) {
-      if (keyword && !origin.includes(keyword)) {
+    for (let permission of sortedPermissions) {
+      if (keyword && !permission.origin.includes(keyword)) {
         continue;
       }
 
       this._createPermissionListItem(permission);
     }
+
     this._setRemoveButtonState();
   },
+
+  _sortPermissions(column) {
+    let permissions = Array.from(this._permissions.values());
+    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);
+        };
+        break;
+
+      case "statusCol":
+        sortFunc = (a, b) => {
+          return a.capabilityString.localeCompare(b.capabilityString);
+        };
+        break;
+    }
+
+    if (sortDirection === "descending") {
+      permissions.sort((a, b) => sortFunc(b, a));
+    } else {
+      permissions.sort(sortFunc);
+    }
+
+    let cols = this._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
@@ -28,29 +28,31 @@
     <key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="contentPane largeDialogContainer" flex="1">
     <description id="permissionsText" control="url"/>
     <separator class="thin"/>
     <hbox align="start">
       <textbox id="searchBox" flex="1" placeholder="&searchbox.placeholder;"
-               type="search" oncommand="gSitePermissionsManager.filterPermissionsList();"/>
+               type="search" oncommand="gSitePermissionsManager.buildPermissionsList();"/>
     </hbox>
     <separator class="thin"/>
     <richlistbox id="permissionsBox" selected="false"
                  hidecolumnpicker="true" flex="1"
                  onkeypress="gSitePermissionsManager.onPermissionKeyPress(event);"
                  onselect="gSitePermissionsManager.onPermissionSelect();">
       <listheader>
         <treecol id="siteCol" label="&treehead.sitename2.label;" flex="3"
-                 data-field-name="origin" persist="width" width="50"/>
+                 persist="width" width="50"
+                 onclick="gSitePermissionsManager.buildPermissionsList(event.target)"/>
         <splitter class="tree-splitter"/>
         <treecol id="statusCol" label="&treehead.status.label;" flex="1"
-                 data-field-name="capability" persist="width" width="50"/>
+                 persist="width" width="50" data-isCurrentSortCol="true"
+                 onclick="gSitePermissionsManager.buildPermissionsList(event.target);"/>
       </listheader>
     </richlistbox>
   </vbox>
   <vbox>
     <hbox class="actionButtons" align="left" flex="1">
       <button id="removePermission" disabled="true"
               accesskey="&removepermission2.accesskey;"
               icon="remove" label="&removepermission2.label;"