Bug 1534685 - make all custom elements to use the attribute inheritance base implementation, r=bgrins
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 14 Mar 2019 21:44:54 +0000
changeset 464910 787bf156ee91f2cd9a986dfcdae97ce32b15fe21
parent 464909 143fe24df3a9ffb261f2684cd00bd3929f57bf71
child 464911 88a8be92d7ae625c67fb3023c690cf5ae82a0214
push id35727
push userdvarga@mozilla.com
push dateTue, 19 Mar 2019 09:48:59 +0000
treeherdermozilla-central@70baa37ae1eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins
bugs1534685
milestone68.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 1534685 - make all custom elements to use the attribute inheritance base implementation, r=bgrins Differential Revision: https://phabricator.services.mozilla.com/D23541
browser/extensions/formautofill/content/customElements.js
toolkit/content/customElements.js
toolkit/content/tests/chrome/test_custom_element_base.xul
toolkit/content/widgets/menu.js
toolkit/content/widgets/tree.js
--- a/browser/extensions/formautofill/content/customElements.js
+++ b/browser/extensions/formautofill/content/customElements.js
@@ -85,34 +85,24 @@
         </div>
       `));
 
       this._itemBox = this.querySelector(".autofill-item-box");
       this._labelAffix = this.querySelector(".profile-label-affix");
       this._label = this.querySelector(".profile-label");
       this._comment = this.querySelector(".profile-comment");
 
-      this._updateAttributes();
+      this.initializeAttributeInheritance();
       this._adjustAcItem();
     }
 
-    static get observedAttributes() {
-      return [
-        "ac-image",
-      ];
-    }
-
-    attributeChangedCallback(name, oldValue, newValue) {
-      if (this.isConnectedAndReady && name == "ac-image" && oldValue != newValue) {
-        this._updateAttributes();
-      }
-    }
-
-    _updateAttributes() {
-      this.inheritAttribute(this._itemBox, "ac-image");
+    static get inheritedAttributes() {
+      return {
+        ".autofill-item-box": "ac-image",
+      };
     }
 
     set selected(val) {
       if (val) {
         this.setAttribute("selected", "true");
       } else {
         this.removeAttribute("selected");
       }
--- a/toolkit/content/customElements.js
+++ b/toolkit/content/customElements.js
@@ -113,17 +113,18 @@ const MozElementMixin = Base => class Mo
   initializeAttributeInheritance() {
     let {inheritedAttributes} = this.constructor;
     if (!inheritedAttributes) {
       return;
     }
     this._inheritedAttributesValuesCache = null;
     this.inheritedAttributesCache = new Map();
     for (let selector in inheritedAttributes) {
-      let el = this.querySelector(selector);
+      let parent = this.shadowRoot || this;
+      let el = parent.querySelector(selector);
       // Skip unmatched selectors in case an element omits some elements in certain cases:
       if (!el) {
         continue;
       }
       if (this.inheritedAttributesCache.has(el)) {
         console.error(`Error: duplicate element encountered with ${selector}`);
       }
 
--- a/toolkit/content/tests/chrome/test_custom_element_base.xul
+++ b/toolkit/content/tests/chrome/test_custom_element_base.xul
@@ -12,16 +12,17 @@
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
   <button id="one"/>
   <simpleelement id="two" style="-moz-user-focus: normal;"/>
   <simpleelement id="three" disabled="true" style="-moz-user-focus: normal;"/>
   <button id="four"/>
   <inherited-element-declarative foo="fuagra"></inherited-element-declarative>
+  <inherited-element-shadowdom-declarative foo="fuagra"></inherited-element-shadowdom-declarative>
   <inherited-element-imperative foo="fuagra"></inherited-element-imperative>
 
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
   SimpleTest.waitForExplicitFinish();
 
@@ -109,16 +110,35 @@
         this.label = this.querySelector("label");
         this.initializeAttributeInheritance();
       }
     }
     customElements.define("inherited-element-declarative", InheritsElementDeclarative);
     let declarativeEl = document.querySelector("inherited-element-declarative");
     ok(declarativeEl, "declarative inheritance element exists");
 
+    class InheritsElementShadowDOMDeclarative extends MozXULElement {
+      static get inheritedAttributes() {
+        return {
+          "label": "text=label,foo,boo,bardo=bar",
+          "unmatched": "foo", // Make sure we don't throw on unmatched selectors
+        };
+      }
+
+      connectedCallback() {
+        this.attachShadow({ mode: "open" });
+        this.shadowRoot.append(MozXULElement.parseXULToFragment(`<label />`));
+        this.label = this.shadowRoot.querySelector("label");
+        this.initializeAttributeInheritance();
+      }
+    }
+    customElements.define("inherited-element-shadowdom-declarative", InheritsElementShadowDOMDeclarative);
+    let shadowDOMDeclarativeEl = document.querySelector("inherited-element-shadowdom-declarative");
+    ok(shadowDOMDeclarativeEl, "declarative inheritance element with shadow DOM exists");
+
     class InheritsElementImperative extends MozXULElement {
       static get observedAttributes() {
         return [ "label", "foo", "boo", "bar" ];
       }
 
       attributeChangedCallback(name, oldValue, newValue) {
         if (this.label && oldValue != newValue) {
           this.inherit();
@@ -137,17 +157,17 @@
         this.inherit();
       }
     }
 
     customElements.define("inherited-element-imperative", InheritsElementImperative);
     let imperativeEl = document.querySelector("inherited-element-imperative");
     ok(imperativeEl, "imperative inheritance element exists");
 
-    for (let el of [declarativeEl, imperativeEl]) {
+    for (let el of [declarativeEl, shadowDOMDeclarativeEl, imperativeEl]) {
       info(`Running checks for ${el.tagName}`);
       is(el.label.getAttribute("foo"), "fuagra", "predefined attribute @foo");
       ok(!el.label.hasAttribute("boo"), "predefined attribute @boo");
       ok(!el.label.hasAttribute("bardo"), "predefined attribute @bardo");
       ok(!el.label.textContent, "predefined attribute @label");
 
       el.setAttribute("boo", "boo-test");
       is(el.label.getAttribute("boo"), "boo-test",
--- a/toolkit/content/widgets/menu.js
+++ b/toolkit/content/widgets/menu.js
@@ -115,36 +115,16 @@ class MozMenuCaption extends MozMenuBase
     return {
       ".menu-iconic-left": "selected,disabled,checked",
       ".menu-iconic-icon": "src=image,validate,src",
       ".menu-iconic-text": "value=label,crop,highlightable",
       ".menu-iconic-highlightable-text": "text=label,crop,highlightable",
     };
   }
 
-  _updateAttributes() {
-    if (!this._inheritedAttributeMap) {
-      return;
-    }
-
-    for (let [ el, attrs ] of this._inheritedAttributeMap.entries()) {
-      for (let attr of attrs) {
-        this.inheritAttribute(el, attr);
-      }
-    }
-  }
-
-  attributeChangedCallback(name, oldValue, newValue) {
-    if (oldValue === newValue) {
-      return;
-    }
-
-    this._updateAttributes();
-  }
-
   connectedCallback() {
     this.textContent = "";
     this.appendChild(MozXULElement.parseXULToFragment(`
       <hbox class="menu-iconic-left" align="center" pack="center" role="none">
         <image class="menu-iconic-icon" role="none"></image>
       </hbox>
       <label class="menu-iconic-text" flex="1" crop="right" role="none"></label>
       <label class="menu-iconic-highlightable-text" crop="right" role="none"></label>
--- a/toolkit/content/widgets/tree.js
+++ b/toolkit/content/widgets/tree.js
@@ -514,72 +514,59 @@
       this.shadowRoot.appendChild(MozXULElement.parseXULToFragment(`
         <html:link rel="stylesheet" href="chrome://global/content/widgets.css" />
         <html:slot name="treecols"></html:slot>
         <stack class="tree-stack" flex="1">
           <hbox class="tree-rows" flex="1">
             <hbox flex="1" class="tree-bodybox">
               <html:slot name="treechildren"></html:slot>
             </hbox>
-            <scrollbar height="0" minwidth="0" minheight="0" orient="vertical" inherits="collapsed=hidevscroll" style="position:relative; z-index:2147483647;" oncontextmenu="event.stopPropagation(); event.preventDefault();" onclick="event.stopPropagation(); event.preventDefault();" ondblclick="event.stopPropagation();" oncommand="event.stopPropagation();"></scrollbar>
+            <scrollbar height="0" minwidth="0" minheight="0" orient="vertical"
+                       class="hidevscroll-scrollbar"
+                       style="position:relative; z-index:2147483647;"
+                       oncontextmenu="event.stopPropagation(); event.preventDefault();"
+                       onclick="event.stopPropagation(); event.preventDefault();"
+                       ondblclick="event.stopPropagation();"
+                       oncommand="event.stopPropagation();"></scrollbar>
           </hbox>
           <textbox class="tree-input" left="0" top="0" hidden="true"></textbox>
         </stack>
-        <hbox inherits="collapsed=hidehscroll">
+        <hbox class="hidehscroll-box">
           <scrollbar orient="horizontal" flex="1" increment="16" style="position:relative; z-index:2147483647;" oncontextmenu="event.stopPropagation(); event.preventDefault();" onclick="event.stopPropagation(); event.preventDefault();" ondblclick="event.stopPropagation();" oncommand="event.stopPropagation();"></scrollbar>
-          <scrollcorner inherits="collapsed=hidevscroll" oncontextmenu="event.stopPropagation(); event.preventDefault();" onclick="event.stopPropagation(); event.preventDefault();" ondblclick="event.stopPropagation();" oncommand="event.stopPropagation();"></scrollcorner>
+          <scrollcorner class="hidevscroll-scrollcorner"
+                        oncontextmenu="event.stopPropagation(); event.preventDefault();"
+                        onclick="event.stopPropagation(); event.preventDefault();"
+                        ondblclick="event.stopPropagation();"
+                        oncommand="event.stopPropagation();"></scrollcorner>
         </hbox>
       `));
     }
 
-    static get observedAttributes() {
-      return [
-        "hidehscroll",
-        "hidevscroll",
-      ];
-    }
-
-    attributeChangedCallback(name, oldValue, newValue) {
-      if (this.isConnectedAndReady && oldValue != newValue) {
-        this._updateAttributes();
-      }
-    }
-
-    _updateAttributes() {
-      for (let [ el, attrs ] of this._inheritedAttributeMap.entries()) {
-        for (let attr of attrs) {
-          this.inheritAttribute(el, attr);
-        }
-      }
-    }
-
-    get _inheritedAttributeMap() {
-      if (!this.__inheritedAttributeMap) {
-        this.__inheritedAttributeMap = new Map();
-        for (let el of this.shadowRoot.querySelectorAll("[inherits]")) {
-          this.__inheritedAttributeMap.set(el, el.getAttribute("inherits").split(","));
-        }
-      }
-      return this.__inheritedAttributeMap;
+    static get inheritedAttributes() {
+      return {
+        ".hidehscroll-box": "collapsed=hidehscroll",
+        ".hidevscroll-scrollbar": "collapsed=hidevscroll",
+        ".hidevscroll-scrollcorner": "collapsed=hidevscroll",
+      };
     }
 
     connectedCallback() {
       if (this.delayConnectedCallback()) {
         return;
       }
       if (!this._eventListenersSetup) {
         this._eventListenersSetup = true;
         this.setupEventListeners();
       }
 
       this.setAttribute("hidevscroll", "true");
       this.setAttribute("hidehscroll", "true");
       this.setAttribute("clickthrough", "never");
 
-      this._updateAttributes();
+      this.initializeAttributeInheritance();
 
       this.pageUpOrDownMovesSelection = !/Mac/.test(navigator.platform);
 
       this._inputField = null;
 
       this._editingRow = -1;
 
       this._editingColumn = null;