Bug 1459556 - Part 1 - Remove the implementation from the "handler" binding. r=bgrins draft
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Mon, 07 May 2018 12:03:29 +0100
changeset 792015 66f180126bb275c1bc187f42146ef188250ecfed
parent 792014 380cb9eb707998db595cbf6d9bc1a75f09d01749
child 792026 5f3c55ce17f7c25071b07952e40ee8c28366cdde
child 792028 fddcc955ead8e125bc9f9670ac8429ecb2717592
push id108948
push userpaolo.mozmail@amadzone.org
push dateMon, 07 May 2018 11:04:25 +0000
reviewersbgrins
bugs1459556
milestone61.0a1
Bug 1459556 - Part 1 - Remove the implementation from the "handler" binding. r=bgrins MozReview-Commit-ID: IN1C5NC9Rzb
browser/components/preferences/handlers.xml
browser/components/preferences/in-content/main.js
--- a/browser/components/preferences/handlers.xml
+++ b/browser/components/preferences/handlers.xml
@@ -6,39 +6,16 @@
 <!-- import-globals-from in-content/main.js -->
 
 <bindings id="handlerBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="handler" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <implementation>
-      <property name="type" readonly="true">
-        <getter>
-          return this.getAttribute("type");
-        </getter>
-      </property>
-      <!-- Overriding listitem -->
-      <property name="selected" onget="return this.getAttribute('selected') == 'true';">
-        <setter><![CDATA[
-          if (val) {
-            this.setAttribute("selected", "true");
-            gMainPane.rebuildActionsMenu();
-          } else {
-            this.removeAttribute("selected");
-          }
-
-          document.getAnonymousElementByAttribute(this, "anonid", "selected").setAttribute("hidden", !val);
-          document.getAnonymousElementByAttribute(this, "anonid", "not-selected").setAttribute("hidden", !!val);
-
-          return val;
-        ]]></setter>
-      </property>
-    </implementation>
     <content>
       <xul:hbox flex="1" equalsize="always">
         <xul:hbox flex="1" align="center" xbl:inherits="tooltiptext=typeDescription">
           <xul:image src="moz-icon://goat?size=16" class="typeIcon"
                      xbl:inherits="src=typeIcon" height="16" width="16"/>
           <xul:label flex="1" crop="end" xbl:inherits="value=typeDescription"/>
         </xul:hbox>
         <xul:hbox anonid="not-selected" flex="1" align="center" xbl:inherits="tooltiptext=actionDescription">
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1354,16 +1354,37 @@ var gMainPane = {
 
   // Composed Model Construction
 
   _loadData() {
     this._loadFeedHandler();
     this._loadInternalHandlers();
     this._loadPluginHandlers();
     this._loadApplicationHandlers();
+
+    this._list.addEventListener("select", event => {
+      if (event.target != this._list) {
+        return;
+      }
+
+      let handlerListItem = this._list.selectedItem &&
+                            HandlerListItem.forNode(this._list.selectedItem);
+      if (this.selectedHandlerListItem == handlerListItem) {
+        return;
+      }
+
+      if (this.selectedHandlerListItem) {
+        this.selectedHandlerListItem.showActionsMenu = false;
+      }
+      this.selectedHandlerListItem = handlerListItem;
+      if (handlerListItem) {
+        this.rebuildActionsMenu();
+        handlerListItem.showActionsMenu = true;
+      }
+    });
   },
 
   _loadFeedHandler() {
     this._handledTypes[TYPE_MAYBE_FEED] = feedHandlerInfo;
     feedHandlerInfo.handledOnlyByPlugin = false;
 
     this._handledTypes[TYPE_MAYBE_VIDEO_FEED] = videoFeedHandlerInfo;
     videoFeedHandlerInfo.handledOnlyByPlugin = false;
@@ -1501,18 +1522,19 @@ var gMainPane = {
         // add the type to the description on both HandlerInfoWrapper objects.
         handlerInfo.disambiguateDescription = true;
         otherHandlerInfo.disambiguateDescription = true;
       }
     }
   },
 
   _rebuildView() {
-    let lastSelectedType = this._list.selectedItem &&
-      HandlerListItem.forNode(this._list.selectedItem).handlerInfoWrapper.type;
+    let lastSelectedType = this.selectedHandlerListItem &&
+                           this.selectedHandlerListItem.handlerInfoWrapper.type;
+    this.selectedHandlerListItem = null;
 
     // Clear the list of entries.
     while (this._list.childNodes.length > 1)
       this._list.removeChild(this._list.lastChild);
 
     var visibleTypes = this._visibleTypes;
 
     // If the user is filtering the list, then only show matching types.
@@ -1580,19 +1602,20 @@ var gMainPane = {
   },
 
   /**
    * Rebuild the actions menu for the selected entry.  Gets called by
    * the richlistitem constructor when an entry in the list gets selected.
    */
   rebuildActionsMenu() {
     var typeItem = this._list.selectedItem;
-    var handlerInfo = this._handledTypes[typeItem.type];
+    var handlerInfo = this.selectedHandlerListItem.handlerInfoWrapper;
     var menu =
       document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
+
     var menuPopup = menu.menupopup;
 
     // Clear out existing items.
     while (menuPopup.hasChildNodes())
       menuPopup.removeChild(menuPopup.lastChild);
 
     let internalMenuItem;
     // Add the "Preview in Firefox" option for optional internal handlers.
@@ -1694,17 +1717,17 @@ var gMainPane = {
 
       menuPopup.appendChild(menuItem);
       possibleAppMenuItems.push(menuItem);
     }
     // Add gio handlers
     if (Cc["@mozilla.org/gio-service;1"]) {
       let gIOSvc = Cc["@mozilla.org/gio-service;1"].
                    getService(Ci.nsIGIOService);
-      var gioApps = gIOSvc.getAppsForURIScheme(typeItem.type);
+      var gioApps = gIOSvc.getAppsForURIScheme(handlerInfo.type);
       let enumerator = gioApps.enumerate();
       let possibleHandlers = handlerInfo.possibleApplicationHandlers;
       while (enumerator.hasMoreElements()) {
         let handler = enumerator.getNext().QueryInterface(Ci.nsIHandlerApp);
         // OS handler share the same name, it's most likely the same app, skipping...
         if (handler.name == handlerInfo.defaultDescription) {
           continue;
         }
@@ -1901,18 +1924,17 @@ var gMainPane = {
     try {
       this._storeAction(aActionItem);
     } finally {
       this._storingAction = false;
     }
   },
 
   _storeAction(aActionItem) {
-    var typeItem = this._list.selectedItem;
-    var handlerInfo = this._handledTypes[typeItem.type];
+    var handlerInfo = this.selectedHandlerListItem.handlerInfoWrapper;
 
     let action = parseInt(aActionItem.getAttribute("action"));
 
     // Set the plugin state if we're enabling or disabling a plugin.
     if (action == kActionUsePlugin)
       handlerInfo.enablePluginType();
     else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
       handlerInfo.disablePluginType();
@@ -1937,34 +1959,33 @@ var gMainPane = {
 
     handlerInfo.store();
 
     // Make sure the handler info object is flagged to indicate that there is
     // now some user configuration for the type.
     handlerInfo.handledOnlyByPlugin = false;
 
     // Update the action label and image to reflect the new preferred action.
-    HandlerListItem.forNode(typeItem).refreshAction();
+    this.selectedHandlerListItem.refreshAction();
   },
 
   manageApp(aEvent) {
     // Don't let the normal "on select action" handler get this event,
     // as we handle it specially ourselves.
     aEvent.stopPropagation();
 
-    var typeItem = this._list.selectedItem;
-    var handlerInfo = this._handledTypes[typeItem.type];
+    var handlerInfo = this.selectedHandlerListItem.handlerInfoWrapper;
 
     let onComplete = () => {
       // Rebuild the actions menu so that we revert to the previous selection,
       // or "Always ask" if the previous default application has been removed
       this.rebuildActionsMenu();
 
       // update the richlistitem too. Will be visible when selecting another row
-      HandlerListItem.forNode(typeItem).refreshAction();
+      this.selectedHandlerListItem.refreshAction();
     };
 
     gSubDialog.open("chrome://browser/content/preferences/applicationManager.xul",
       "resizable=no", handlerInfo, onComplete);
 
   },
 
   chooseApp(aEvent) {
@@ -1993,17 +2014,17 @@ var gMainPane = {
             break;
           }
         }
       }
     };
 
     if (AppConstants.platform == "win") {
       var params = {};
-      var handlerInfo = this._handledTypes[this._list.selectedItem.type];
+      var handlerInfo = this.selectedHandlerListItem.handlerInfoWrapper;
 
       if (isFeedType(handlerInfo.type)) {
         // MIME info will be null, create a temp object.
         params.mimeInfo = gMIMEService.getFromTypeAndExtension(handlerInfo.type,
           handlerInfo.primaryExtension);
       } else {
         params.mimeInfo = handlerInfo.wrappedHandlerInfo;
       }
@@ -2033,17 +2054,17 @@ var gMainPane = {
         if (aResult == Ci.nsIFilePicker.returnOK && fp.file &&
           this._isValidHandlerExecutable(fp.file)) {
           handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
             createInstance(Ci.nsILocalHandlerApp);
           handlerApp.name = getFileDisplayName(fp.file);
           handlerApp.executable = fp.file;
 
           // Add the app to the type's list of possible handlers.
-          let handler = this._handledTypes[this._list.selectedItem.type];
+          let handler = this.selectedHandlerListItem.handlerInfoWrapper;
           handler.addPossibleApplicationHandler(handlerApp);
 
           chooseAppCallback(handlerApp);
         }
       };
 
       // Prompt the user to pick an app.  If they pick one, and it's a valid
       // selection, then add it to the list of possible handlers.
@@ -2459,16 +2480,23 @@ class HandlerListItem {
       this.node.setAttribute(APP_ICON_ATTR_NAME,
                              this.handlerInfoWrapper.actionIconClass);
       this.node.removeAttribute("actionIcon");
     } else {
       this.node.removeAttribute(APP_ICON_ATTR_NAME);
       this.node.setAttribute("actionIcon", this.handlerInfoWrapper.actionIcon);
     }
   }
+
+  set showActionsMenu(value) {
+    document.getAnonymousElementByAttribute(this.node, "anonid", "selected")
+            .setAttribute("hidden", !value);
+    document.getAnonymousElementByAttribute(this.node, "anonid", "not-selected")
+            .setAttribute("hidden", !!value);
+  }
 }
 
 /**
  * This object wraps nsIHandlerInfo with some additional functionality
  * the Applications prefpane needs to display and allow modification of
  * the list of handled types.
  *
  * We create an instance of this wrapper for each entry we might display