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 647692 7e200f59f1316842228d27f616a8d94bd4c9b47b
parent 646672 5ab5511100233277a760550ac509283278a0e3d9
child 726604 5333eef66aea58585a55105c83e2a3ef378dcf0d
push id74510
push userbmo:prathikshaprasadsuman@gmail.com
push dateWed, 16 Aug 2017 20:07:54 +0000
reviewersjohannh
bugs1385221
milestone57.0a1
Bug 1385221 - Implement Permission sorting in the Permissions dialog. r?johannh MozReview-Commit-ID: BkuC6W1wW02
browser/components/preferences/sitePermissions.js
browser/components/preferences/sitePermissions.xul
--- a/browser/components/preferences/sitePermissions.js
+++ b/browser/components/preferences/sitePermissions.js
@@ -47,16 +47,18 @@ 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();
+    let sortColumn = document.querySelector("treecol[data-isCurrentSortCol=true]");
+    this._buildPermissionsList(sortColumn);
 
     this._searchBox.focus();
   },
 
   uninit() {
     if (this._isObserving) {
       Services.obs.removeObserver(this, "perm-changed");
       this._isObserving = false;
@@ -68,26 +70,26 @@ var gSitePermissionsManager = {
       return;
 
     let permission = subject.QueryInterface(Components.interfaces.nsIPermission);
 
     // Ignore unrelated permission types.
     if (permission.type !== this._type)
       return;
 
+    let sortColumn = document.querySelector("treecol[data-isCurrentSortCol=true]");
     if (data == "added") {
       this._addPermissionToList(permission);
-      if (this._searchBox.value != "") {
-        this.filterPermissionsList();
-      }
+      this._buildPermissionsList(sortColumn);
     } 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(sortColumn);
     } 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 +115,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 +253,106 @@ 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 sites = this._constructSortArray();
+    let sortedSites = this._sortSites(sites, sortCol);
+    this._permissions = new Map(sortedSites);
+
     let keyword = this._searchBox.value.toLowerCase().trim();
     let permissions = this._permissions;
     for (let [origin, permission] of permissions) {
       if (keyword && !origin.includes(keyword)) {
         continue;
       }
 
       this._createPermissionListItem(permission);
     }
+
     this._setRemoveButtonState();
   },
+
+  _sortSites(sites, column) {
+    let isCurrentSortCol = column.getAttribute("data-isCurrentSortCol");
+    let sortDirection = column.getAttribute("data-last-sortDirection") || "ascending";
+    if (isCurrentSortCol) {
+      // Sort on the current column, flip the sorting direction
+      sortDirection = sortDirection === "ascending" ? "descending" : "ascending";
+    }
+
+    let sortFunc = null;
+    switch (column.id) {
+      case "siteCol":
+        sortFunc = (a, b) => {
+          let aOrigin = a[0].toLowerCase();
+          let bOrigin = b[0].toLowerCase();
+          if (aOrigin < bOrigin) {
+            return -1;
+          }
+          if (aOrigin > bOrigin) {
+            return 1;
+          }
+          return 0;
+        };
+        break;
+
+      case "statusCol":
+        sortFunc = (a, b) => {
+          let aCapabilityString = a[1].capabilityString;
+          let bCapabilityString = b[1].capabilityString;
+          if (aCapabilityString < bCapabilityString) {
+            return 1;
+          } else if (aCapabilityString > bCapabilityString) {
+            return -1;
+          }
+          return 0;
+        };
+        break;
+    }
+    if (sortDirection === "descending") {
+      sites.sort((a, b) => sortFunc(b, a));
+    } else {
+      sites.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 sites;
+  },
+
+  _constructSortArray() {
+    let sites = [];
+    for (var [key, value] of this._permissions.entries()) {
+      sites.push([key, value]);
+    }
+
+    return sites;
+  },
+
+  onClickTreeCol(event) {
+    this._buildPermissionsList(event.target);
+  },
+
+  onCommandSearch() {
+    let sortColumn = document.querySelector("treecol[data-isCurrentSortCol=true]");
+    this._buildPermissionsList(sortColumn);
+  },
 };
--- a/browser/components/preferences/sitePermissions.xul
+++ b/browser/components/preferences/sitePermissions.xul
@@ -28,29 +28,32 @@
     <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.onCommandSearch();"/>
     </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"/>
+                 data-field-name="origin" persist="width" width="50"
+                 onclick="gSitePermissionsManager.onClickTreeCol(event);"/>
         <splitter class="tree-splitter"/>
         <treecol id="statusCol" label="&treehead.status.label;" flex="1"
-                 data-field-name="capability" persist="width" width="50"/>
+                 data-field-name="capability" persist="width" width="50"
+                 data-isCurrentSortCol="true"
+                 onclick="gSitePermissionsManager.onClickTreeCol(event);"/>
       </listheader>
     </richlistbox>
   </vbox>
   <vbox>
     <hbox class="actionButtons" align="left" flex="1">
       <button id="removePermission" disabled="true"
               accesskey="&removepermission2.accesskey;"
               icon="remove" label="&removepermission2.label;"