Bug 1476769 - Migrate tabpanels to a Custom Element r=dao
authorBrian Grinstead <bgrinstead@mozilla.com>
Fri, 12 Oct 2018 17:52:09 +0000
changeset 489384 8c9dd41737f597ecd80989e32a0164447636a96e
parent 489383 3edf43a3f1a4d167ad1334e9bf09db438de6a55e
child 489385 96f72bd042922a7fe7245c6517f1c8b1b1762bc6
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersdao
bugs1476769
milestone64.0a1
Bug 1476769 - Migrate tabpanels to a Custom Element r=dao Differential Revision: https://phabricator.services.mozilla.com/D8458
toolkit/content/widgets/tabbox.js
toolkit/content/widgets/tabbox.xml
toolkit/content/xul.css
--- a/toolkit/content/widgets/tabbox.js
+++ b/toolkit/content/widgets/tabbox.js
@@ -56,53 +56,53 @@ class MozTabbox extends MozXULElement {
 
   get tabpanels() {
     return this.getElementsByTagNameNS(
       "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
       "tabpanels").item(0);
   }
 
   set selectedIndex(val) {
-    var tabs = this.tabs;
+    let tabs = this.tabs;
     if (tabs)
       tabs.selectedIndex = val;
     this.setAttribute("selectedIndex", val);
     return val;
   }
 
   get selectedIndex() {
-    var tabs = this.tabs;
+    let tabs = this.tabs;
     return tabs ? tabs.selectedIndex : -1;
   }
 
   set selectedTab(val) {
     if (val) {
-      var tabs = this.tabs;
+      let tabs = this.tabs;
       if (tabs)
         tabs.selectedItem = val;
     }
     return val;
   }
 
   get selectedTab() {
-    var tabs = this.tabs;
+    let tabs = this.tabs;
     return tabs && tabs.selectedItem;
   }
 
   set selectedPanel(val) {
     if (val) {
-      var tabpanels = this.tabpanels;
+      let tabpanels = this.tabpanels;
       if (tabpanels)
         tabpanels.selectedPanel = val;
     }
     return val;
   }
 
   get selectedPanel() {
-    var tabpanels = this.tabpanels;
+    let tabpanels = this.tabpanels;
     return tabpanels && tabpanels.selectedPanel;
   }
 
   handleEvent(event) {
     if (!event.isTrusted) {
       // Don't let untrusted events mess with tabs.
       return;
     }
@@ -130,30 +130,134 @@ class MozTabbox extends MozXULElement {
           this.tabs) {
           this.tabs.advanceSelectedTab(1, true);
           event.preventDefault();
         }
         break;
       case event.DOM_VK_LEFT:
         if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
           if (this.tabs && this._handleMetaAltArrows) {
-            var offset = window.getComputedStyle(this)
+            let offset = window.getComputedStyle(this)
               .direction == "ltr" ? -1 : 1;
             this.tabs.advanceSelectedTab(offset, true);
             event.preventDefault();
           }
         break;
       case event.DOM_VK_RIGHT:
         if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
           if (this.tabs && this._handleMetaAltArrows) {
-            offset = window.getComputedStyle(this)
+            let offset = window.getComputedStyle(this)
               .direction == "ltr" ? 1 : -1;
             this.tabs.advanceSelectedTab(offset, true);
             event.preventDefault();
           }
         break;
     }
   }
 }
 
 customElements.define("tabbox", MozTabbox);
 
+class MozTabpanels extends MozXULElement {
+  connectedCallback() {
+    if (this.delayConnectedCallback()) {
+      return;
+    }
+
+    this._tabbox = null;
+    this._selectedPanel = this.children.item(this.selectedIndex);
+  }
+
+  get tabbox() {
+    // Memoize the result rather than replacing this getter, so that
+    // it can be reset if the parent changes.
+    if (this._tabbox) {
+      return this._tabbox;
+    }
+
+    let parent = this.parentNode;
+    while (parent) {
+      if (parent.localName == "tabbox") {
+        break;
+      }
+      parent = parent.parentNode;
+    }
+
+    return this._tabbox = parent;
+  }
+
+  set selectedIndex(val) {
+    if (val < 0 || val >= this.children.length)
+      return val;
+
+    let panel = this._selectedPanel;
+    this._selectedPanel = this.children[val];
+
+    if (this.getAttribute("async") != "true") {
+      this.setAttribute("selectedIndex", val);
+    }
+
+    if (this._selectedPanel != panel) {
+      let event = document.createEvent("Events");
+      event.initEvent("select", true, true);
+      this.dispatchEvent(event);
+    }
+    return val;
+  }
+
+  get selectedIndex() {
+    let indexStr = this.getAttribute("selectedIndex");
+    return indexStr ? parseInt(indexStr) : -1;
+  }
+
+  set selectedPanel(val) {
+    let selectedIndex = -1;
+    for (let panel = val; panel != null; panel = panel.previousElementSibling)
+      ++selectedIndex;
+    this.selectedIndex = selectedIndex;
+    return val;
+  }
+
+  get selectedPanel() {
+    return this._selectedPanel;
+  }
+
+  /**
+   * nsIDOMXULRelatedElement
+   */
+  getRelatedElement(aTabPanelElm) {
+    if (!aTabPanelElm)
+      return null;
+
+    let tabboxElm = this.tabbox;
+    if (!tabboxElm)
+      return null;
+
+    let tabsElm = tabboxElm.tabs;
+    if (!tabsElm)
+      return null;
+
+    // Return tab element having 'linkedpanel' attribute equal to the id
+    // of the tab panel or the same index as the tab panel element.
+    let tabpanelIdx = Array.indexOf(this.children, aTabPanelElm);
+    if (tabpanelIdx == -1)
+      return null;
+
+    let tabElms = tabsElm.children;
+    let tabElmFromIndex = tabElms[tabpanelIdx];
+
+    let tabpanelId = aTabPanelElm.id;
+    if (tabpanelId) {
+      for (let idx = 0; idx < tabElms.length; idx++) {
+        let tabElm = tabElms[idx];
+        if (tabElm.linkedPanel == tabpanelId)
+          return tabElm;
+      }
+    }
+
+    return tabElmFromIndex;
+  }
 }
+
+MozXULElement.implementCustomInterface(MozTabpanels, [Ci.nsIDOMXULRelatedElement]);
+customElements.define("tabpanels", MozTabpanels);
+
+}
--- a/toolkit/content/widgets/tabbox.xml
+++ b/toolkit/content/widgets/tabbox.xml
@@ -365,131 +365,16 @@
 
         event.stopPropagation();
       ]]>
       </handler>
     </handlers>
 #endif
   </binding>
 
-  <binding id="tabpanels">
-    <implementation implements="nsIDOMXULRelatedElement">
-      <!-- nsIDOMXULRelatedElement -->
-      <method name="getRelatedElement">
-        <parameter name="aTabPanelElm"/>
-        <body>
-        <![CDATA[
-          if (!aTabPanelElm)
-            return null;
-
-          let tabboxElm = this.tabbox;
-          if (!tabboxElm)
-            return null;
-
-          let tabsElm = tabboxElm.tabs;
-          if (!tabsElm)
-            return null;
-
-          // Return tab element having 'linkedpanel' attribute equal to the id
-          // of the tab panel or the same index as the tab panel element.
-          let tabpanelIdx = Array.indexOf(this.children, aTabPanelElm);
-          if (tabpanelIdx == -1)
-            return null;
-
-          let tabElms = tabsElm.children;
-          let tabElmFromIndex = tabElms[tabpanelIdx];
-
-          let tabpanelId = aTabPanelElm.id;
-          if (tabpanelId) {
-            for (let idx = 0; idx < tabElms.length; idx++) {
-              var tabElm = tabElms[idx];
-              if (tabElm.linkedPanel == tabpanelId)
-                return tabElm;
-            }
-          }
-
-          return tabElmFromIndex;
-        ]]>
-        </body>
-      </method>
-
-      <!-- public -->
-      <field name="_tabbox">null</field>
-      <property name="tabbox" readonly="true">
-        <getter><![CDATA[
-          // Memoize the result in a field rather than replacing this property,
-          // so that it can be reset along with the binding.
-          if (this._tabbox) {
-            return this._tabbox;
-          }
-
-          let parent = this.parentNode;
-          while (parent) {
-            if (parent.localName == "tabbox") {
-              break;
-            }
-            parent = parent.parentNode;
-          }
-
-          return this._tabbox = parent;
-        ]]></getter>
-      </property>
-
-      <field name="_selectedPanel">this.children.item(this.selectedIndex)</field>
-
-      <property name="selectedIndex">
-        <getter>
-        <![CDATA[
-          var indexStr = this.getAttribute("selectedIndex");
-          return indexStr ? parseInt(indexStr) : -1;
-        ]]>
-        </getter>
-
-        <setter>
-        <![CDATA[
-          if (val < 0 || val >= this.children.length)
-            return val;
-
-          var panel = this._selectedPanel;
-          this._selectedPanel = this.children[val];
-
-          if (this.getAttribute("async") != "true") {
-            this.setAttribute("selectedIndex", val);
-          }
-
-          if (this._selectedPanel != panel) {
-            var event = document.createEvent("Events");
-            event.initEvent("select", true, true);
-            this.dispatchEvent(event);
-          }
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-      <property name="selectedPanel">
-        <getter>
-          <![CDATA[
-            return this._selectedPanel;
-          ]]>
-        </getter>
-
-        <setter>
-          <![CDATA[
-            var selectedIndex = -1;
-            for (var panel = val; panel != null; panel = panel.previousElementSibling)
-              ++selectedIndex;
-            this.selectedIndex = selectedIndex;
-            return val;
-          ]]>
-        </setter>
-      </property>
-    </implementation>
-  </binding>
-
   <binding id="tab" display="xul:button"
            extends="chrome://global/content/bindings/general.xml#basetext">
     <content>
       <xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected,visuallyselected" flex="1">
         <xul:image class="tab-icon"
                    xbl:inherits="validate,src=image"
                    role="presentation"/>
         <xul:label class="tab-text"
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -570,17 +570,16 @@ tab {
   -moz-box-pack: center;
 }
 
 tab[selected="true"]:not([ignorefocus="true"]) {
   -moz-user-focus: normal;
 }
 
 tabpanels {
-  -moz-binding: url("chrome://global/content/bindings/tabbox.xml#tabpanels");
   display: -moz-deck;
 }
 
 /********** tooltip *********/
 
 tooltip[titletip="true"] {
   /* The width of the tooltip isn't limited on cropped <tree> cells. */
   max-width: none;