Bug 1476769 - Migrate tabpanels to a Custom Element r=dao
authorBrian Grinstead <bgrinstead@mozilla.com>
Fri, 12 Oct 2018 17:52:09 +0000
changeset 499371 8c9dd41737f597ecd80989e32a0164447636a96e
parent 499370 3edf43a3f1a4d167ad1334e9bf09db438de6a55e
child 499372 96f72bd042922a7fe7245c6517f1c8b1b1762bc6
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs1476769
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;