Bug 583890 - Add visibleLabel attribute/property and tests. r=ttaubert,jaws
authorAdam Dane [:hobophobe] <unusualtears@gmail.com>
Thu, 23 Aug 2012 20:15:50 -0500
changeset 105301 ecaff5097b0b0b775e56f23bb65734b7658c46e7
parent 105300 a3b7774cb5be105704f09a5f36169acf7c86354b
child 105302 9c2c1987abc41cacfda266117d7cd8bfced5d03f
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersttaubert, jaws
bugs583890
milestone17.0a1
Bug 583890 - Add visibleLabel attribute/property and tests. r=ttaubert,jaws
browser/base/content/tabbrowser.xml
browser/base/content/test/Makefile.in
browser/base/content/test/browser_bug583890_label.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1212,21 +1212,16 @@
 
             var t = document.createElementNS(
               "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                                              "tab");
 
             var uriIsBlankPage = !aURI || isBlankPageURL(aURI);
             var uriIsNotAboutBlank = aURI && aURI != "about:blank";
 
-            if (uriIsBlankPage)
-              t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
-            else
-              t.setAttribute("label", aURI);
-
             t.setAttribute("crop", "end");
             t.setAttribute("validate", "never");
             t.setAttribute("onerror", "this.removeAttribute('image');");
             t.className = "tabbrowser-tab";
 
             this.tabContainer._unlockTabSizing();
 
             // When overflowing, new tabs are scrolled into view smoothly, which
@@ -1322,16 +1317,24 @@
 
             // NB: this appendChild call causes us to run constructors for the
             // browser element, which fires off a bunch of notifications. Some
             // of those notifications can cause code to run that inspects our
             // state, so it is important that the tab element is fully
             // initialized by this point.
             this.mPanelContainer.appendChild(notificationbox);
 
+            // Happens after the browser is in the DOM: the TabTitleAbridger
+            // classifies tabs by domains, requiring access to the browser.
+            if (uriIsBlankPage) {
+              t.label = this.mStringBundle.getString("tabs.emptyTabTitle");
+            } else {
+              t.label = aURI;
+            }
+
             this.tabContainer.updateVisibility();
 
             if (uriIsNotAboutBlank) {
               // Stop the existing about:blank load.  Otherwise, if aURI
               // doesn't stop in-progress loads on its own, we'll get into
               // trouble with multiple parallel loads running at once.
               b.stop();
             }
@@ -2814,18 +2817,17 @@
     <implementation implements="nsIDOMEventListener">
       <constructor>
         <![CDATA[
           this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
           this.mCloseButtons = Services.prefs.getIntPref("browser.tabs.closeButtons");
           this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
 
           var tab = this.firstChild;
-          tab.setAttribute("label",
-                           this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"));
+          tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
           tab.setAttribute("crop", "end");
           tab.setAttribute("validate", "never");
           tab.setAttribute("onerror", "this.removeAttribute('image');");
           this.adjustTabstrip();
 
           Services.prefs.addObserver("browser.tabs.", this._prefObserver, false);
           window.addEventListener("resize", this, false);
           window.addEventListener("load", this, false);
@@ -3838,27 +3840,52 @@
                   class="tab-content" align="center">
           <xul:image xbl:inherits="fadein,pinned,busy,progress,selected"
                      class="tab-throbber"
                      role="presentation"/>
           <xul:image xbl:inherits="validate,src=image,fadein,pinned,selected"
                      class="tab-icon-image"
                      role="presentation"/>
           <xul:label flex="1"
-                     xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected"
+                     anonid="tab-label"
+                     xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected"
                      class="tab-text tab-label"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
                              xbl:inherits="fadein,pinned,selected"
                              class="tab-close-button"/>
         </xul:hbox>
       </xul:stack>
     </content>
 
     <implementation>
+      <property name="label">
+        <getter>
+          return this.getAttribute("label");
+        </getter>
+        <setter>
+          this.setAttribute("label", val);
+          let event = new CustomEvent("TabLabelModified", {
+            bubbles: true,
+            cancelable: true
+          });
+          this.dispatchEvent(event);
+
+          if (!event.defaultPrevented)
+            this.visibleLabel = val;
+        </setter>
+      </property>
+      <property name="visibleLabel">
+        <getter>
+          return this.getAttribute("visibleLabel");
+        </getter>
+        <setter>
+          this.setAttribute("visibleLabel", val);
+        </setter>
+      </property>
       <property name="pinned" readonly="true">
         <getter>
           return this.getAttribute("pinned") == "true";
         </getter>
       </property>
       <property name="hidden" readonly="true">
         <getter>
           return this.getAttribute("hidden") == "true";
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -129,16 +129,17 @@ endif
                  browser_bug577121.js \
                  browser_bug578534.js \
                  browser_bug579872.js \
                  browser_bug580638.js \
                  browser_bug580956.js \
                  browser_bug581242.js \
                  browser_bug581253.js \
                  browser_bug581947.js \
+                 browser_bug583890_label.js \
                  browser_bug585785.js \
                  browser_bug585830.js \
                  browser_bug590206.js \
                  browser_bug592338.js \
                  browser_bug594131.js \
                  browser_bug595507.js \
                  browser_bug596687.js \
                  browser_bug597218.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug583890_label.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Tests:
+ *   verify that the visibleLabel attribute works
+ *   verify the TabLabelModified event works
+ */
+
+function test() {
+  waitForExplicitFinish();
+  let tab = gBrowser.addTab("about:newtab",
+                            {skipAnimation: true});
+  tab.linkedBrowser.addEventListener("load", function onLoad(event) {
+    event.currentTarget.removeEventListener("load", onLoad, true);
+    gBrowser.selectedTab = tab;
+    executeSoon(afterLoad);
+  }, true);
+  tab.addEventListener("TabLabelModified", handleInTest, true);
+}
+
+// Prevent interference
+function handleInTest(aEvent) {
+  aEvent.preventDefault();
+  aEvent.stopPropagation();
+  aEvent.target.visibleLabel = aEvent.target.label;
+}
+
+function afterLoad() {
+  let tab = gBrowser.selectedTab;
+  let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
+                                                         "tab-label");
+  // Verify we're starting out on the right foot
+  is(tab.label, "New Tab", "Initial tab label is default");
+  is(xulLabel.value, "New Tab", "Label element is default");
+  is(tab.visibleLabel, "New Tab", "visibleLabel is default");
+
+  // Check that a normal label setting works correctly
+  tab.label = "Hello, world!";
+  is(tab.label, "Hello, world!", "tab label attribute set via tab.label");
+  is(xulLabel.value, "Hello, world!", "xul:label set via tab.label");
+  is(tab.visibleLabel, "Hello, world!", "visibleLabel set via tab.label");
+
+  // Check that setting visibleLabel only affects the label element
+  tab.visibleLabel = "Goodnight, Irene";
+  is(tab.label, "Hello, world!", "Tab.label unaffected by visibleLabel setter");
+  is(xulLabel.value, "Goodnight, Irene",
+     "xul:label set by visibleLabel setter");
+  is(tab.visibleLabel, "Goodnight, Irene",
+     "visibleLabel attribute set by visibleLabel setter");
+
+  // Check that setting the label property hits everything
+  tab.label = "One more label";
+  is(tab.label, "One more label",
+     "Tab label set via label property after diverging from visibleLabel");
+  is(xulLabel.value, "One more label",
+     "xul:label set via label property after diverging from visibleLabel");
+  is(tab.visibleLabel, "One more label",
+     "visibleLabel set from label property after diverging from visibleLabel");
+
+  tab.removeEventListener("TabLabelModified", handleInTest, true);
+  tab.addEventListener("TabLabelModified", handleTabLabel, true);
+  tab.label = "This won't be the visibleLabel";
+}
+
+function handleTabLabel(aEvent) {
+  aEvent.target.removeEventListener("TabLabelModified", handleTabLabel, true);
+  aEvent.preventDefault();
+  aEvent.stopPropagation();
+  aEvent.target.visibleLabel = "Handler set this as the visible label";
+  executeSoon(checkTabLabelModified);
+}
+
+function checkTabLabelModified() {
+  let tab = gBrowser.selectedTab;
+  let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
+                                                         "tab-label");
+
+  is(tab.label, "This won't be the visibleLabel",
+     "Tab label set via label property that triggered event");
+  is(xulLabel.value, "Handler set this as the visible label",
+     "xul:label set by TabLabelModified handler");
+  is(tab.visibleLabel, "Handler set this as the visible label",
+     "visibleLabel set by TabLabelModified handler");
+
+  gBrowser.removeCurrentTab({animate: false});
+  finish();
+}
+