Bug 1448213 - Merge text-base, text-label, label-control, text-link bindings into the text binding draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Sun, 25 Mar 2018 11:48:56 +0800
changeset 772900 6de796e0c0f9a0a68b0cbec482fb7d33e04dc54a
parent 772787 de32269720d056972b85f4eec5f0a8286de6e3af
push id104080
push usertimdream@gmail.com
push dateTue, 27 Mar 2018 05:06:53 +0000
bugs1448213
milestone61.0a1
Bug 1448213 - Merge text-base, text-label, label-control, text-link bindings into the text binding MozReview-Commit-ID: DiI2fPtkb3m
toolkit/content/minimal-xul.css
toolkit/content/widgets/text.xml
--- a/toolkit/content/minimal-xul.css
+++ b/toolkit/content/minimal-xul.css
@@ -45,33 +45,24 @@
 /* hide the content, but don't destroy the frames */
 [collapsed="true"],
 [moz-collapsed="true"] {
   visibility: collapse;
 }
 
 /********** label **********/
 
-description {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#text-base");
-}
-
-label {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
+label, description {
+  -moz-binding: url("chrome://global/content/bindings/text.xml#text");
 }
 
 label.text-link, label[onclick] {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#text-link");
   -moz-user-focus: normal;
 }
 
-label[control], label.radio-label, label.checkbox-label, label.toolbarbutton-multiline-text {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#label-control");
-}
-
 html|span.accesskey {
   text-decoration: underline;
 }
 
 /********** resizer **********/
 
 resizer {
   -moz-binding: url("chrome://global/content/bindings/resizer.xml#resizer");
--- a/toolkit/content/widgets/text.xml
+++ b/toolkit/content/widgets/text.xml
@@ -4,32 +4,117 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 
 <bindings id="textBindings"
    xmlns="http://www.mozilla.org/xbl"
    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:html="http://www.w3.org/1999/xhtml">
 
-  <!-- bound to <description>s -->
-  <binding id="text-base">
-    <implementation implements="nsIDOMXULDescriptionElement">
+  <!-- bound to <label>s and <description>s -->
+  <binding id="text">
+    <content>
+      <children/><html:span anonid="accessKeyParens"></html:span>
+    </content>
+    <implementation implements="nsIDOMXULLabelElement, nsIDOMXULDescriptionElement">
+      <constructor>
+        <![CDATA[
+          if (this.tagName !== "label" && this.tagName !== "xul:label") {
+            // Features are not available to <description>s.
+            return;
+          }
+
+          if (this.hasAttribute("control") ||
+              this.classList.contains("radio-label") ||
+              this.classList.contains("checkbox-label") ||
+              this.classList.contains("toolbarbutton-multiline-text")) {
+            this.isControlLabel = true;
+            this.formatAccessKey(true);
+          } else if (this.hasAttribute("onclick") ||
+                     this.classList.contains("text-link")) {
+            this.isTextLink = true;
+          }
+
+          this._setupEventListeners();
+        ]]>
+      </constructor>
+
+      <method name="_setupEventListeners">
+        <body>
+          <![CDATA[
+            if (this.isControlLabel) {
+              this.addEventListener("click", this);
+            }
+            if (this.isTextLink) {
+              this.addEventListener("click", this, true);
+              this.addEventListener("keypress", this, true);
+            }
+          ]]>
+        </body>
+      </method>
+
+      <method name="handleEvent">
+        <parameter name="aEvent"/>
+        <body>
+          <![CDATA[
+            switch (aEvent.type) {
+              case "click":
+                if (this.isControlLabel) {
+                  if (this.disabled) {
+                    break;
+                  }
+                  var controlElement = this.labeledControlElement;
+                  if (controlElement) {
+                    controlElement.focus();
+                  }
+
+                  break;
+                }
+                if (this.isTextLink) {
+                  switch (aEvent.button) {
+                    case 0:
+                    case 1:
+                      this.open(aEvent);
+                      break;
+                  }
+                }
+                break;
+              case "keypress":
+                if (aEvent.keyCode !== aEvent.DOM_VK_RETURN) {
+                  break;
+                }
+                this.click();
+                aEvent.preventDefault();
+                break;
+            }
+          ]]>
+        </body>
+      </method>
+
+      <destructor>
+        <![CDATA[
+          this.removeEventListener("click", this);
+          this.removeEventListener("click", this, true);
+          this.removeEventListener("keypress", this, true);
+        ]]>
+      </destructor>
+
+      <!-- common implementations -->
+
       <property name="disabled" onset="if (val) this.setAttribute('disabled', 'true');
                                        else this.removeAttribute('disabled');
                                        return val;"
                                 onget="return this.getAttribute('disabled') == 'true';"/>
       <property name="value" onget="return this.getAttribute('value');"
                              onset="this.setAttribute('value', val); return val;"/>
       <property name="crop" onget="return this.getAttribute('crop');"
                             onset="this.setAttribute('crop', val); return val;"/>
-    </implementation>
-  </binding>
 
-  <binding id="text-label" extends="chrome://global/content/bindings/text.xml#text-base">
-    <implementation implements="nsIDOMXULLabelElement">
+      <!-- text label implementations -->
+
       <property name="accessKey">
         <getter>
           <![CDATA[
             var accessKey = this.getAttribute("accesskey");
             return accessKey ? accessKey[0] : null;
           ]]>
         </getter>
         <setter>
@@ -38,35 +123,26 @@
             return val;
           ]]>
         </setter>
       </property>
 
       <property name="control" onget="return getAttribute('control');">
         <setter>
           <![CDATA[
-            // After this gets set, the label will use the binding #label-control
+            if (this.parentNode) {
+              throw new Error("Cannot mutate the control attribute while attached.");
+            }
             this.setAttribute("control", val);
             return val;
           ]]>
         </setter>
       </property>
-    </implementation>
-  </binding>
 
-  <binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label">
-    <content>
-      <children/><html:span anonid="accessKeyParens"></html:span>
-    </content>
-    <implementation implements="nsIDOMXULLabelElement">
-      <constructor>
-        <![CDATA[
-          this.formatAccessKey(true);
-        ]]>
-      </constructor>
+      <!-- control label implementions -->
 
       <method name="formatAccessKey">
         <parameter name="firstTime"/>
         <body>
           <![CDATA[
             var control = this.labeledControlElement;
             if (!control) {
               var bindingParent = document.getBindingParent(this);
@@ -271,29 +347,18 @@
             }
             this.setAttribute("control", val);
             this.formatAccessKey(false);
             return val;
           ]]>
         </setter>
       </property>
 
-    </implementation>
+      <!-- text link implementations -->
 
-    <handlers>
-      <handler event="click" action="if (this.disabled) return;
-                                     var controlElement = this.labeledControlElement;
-                                     if(controlElement)
-                                       controlElement.focus();
-                                    "/>
-    </handlers>
-  </binding>
-
-  <binding id="text-link" extends="chrome://global/content/bindings/text.xml#text-label">
-    <implementation>
       <property name="href" onget="return this.getAttribute('href');"
                             onset="this.setAttribute('href', val); return val;" />
       <method name="open">
         <parameter name="aEvent"/>
         <body>
         <![CDATA[
           var href = this.href;
           if (!href || this.disabled || aEvent.defaultPrevented)
@@ -365,18 +430,14 @@
           if (window.isChromeWindow) {
             while (win.opener && !win.opener.closed)
               win = win.opener;
           }
           win.open(href);
         ]]>
         </body>
       </method>
+
     </implementation>
 
-    <handlers>
-      <handler event="click" phase="capturing" button="0" action="this.open(event)"/>
-      <handler event="click" phase="capturing" button="1" action="this.open(event)"/>
-      <handler event="keypress" preventdefault="true" keycode="VK_RETURN" action="this.click()" />
-    </handlers>
   </binding>
 
 </bindings>