Bug 603588 - Can't edit the input fields for bookmark [r=mfinkle]
authorVivien Nicolas <21@vingtetun.org>
Thu, 14 Oct 2010 19:19:04 +0200
changeset 66833 cb131a9ce6f1b01846d3a0385e074b20a2709da3
parent 66832 0e168f65c3578a2b1f1d5fa29e0b47ef25018327
child 66834 43a96c377053f5cf98a80c4c51879ee082e38a35
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs603588
Bug 603588 - Can't edit the input fields for bookmark [r=mfinkle]
mobile/chrome/content/bindings.xml
mobile/chrome/content/browser-ui.js
mobile/chrome/tests/browser_awesomescreen.js
mobile/themes/core/browser.css
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -7,32 +7,47 @@
 
 <bindings
     xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:svg="http://www.w3.org/2000/svg"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="autocomplete-aligned" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
-    <implementation>
+    <implementation implements="nsIDOMEventListener">
+      <constructor>
+        <![CDATA[
+          window.addEventListener("keydown", this, true);
+          window.addEventListener("PopupChanged", this, true);
+          window.addEventListener("PanBegin", this, true);
+        ]]>
+      </constructor>
+      <desctructor>
+        <![CDATA[
+          window.removeEventListener("keydown", this, true);
+          window.removeEventListener("PopupChanged", this, true);
+          window.removeEventListener("PanBegin", this, true);
+        ]]>
+      </desctructor>
       <property name="mIgnoreFocus" onget="return true;" onset="val;"/>
       <property name="mIgnoreClick" onget="return true;" onset="val;"/>
       <property name="readOnly" onget="return this.inputField.readOnly;">
         <setter><![CDATA[
           if (val == this.inputField.readOnly)
             return;
 
           this.inputField.readOnly = val;
           val ? this.setAttribute("readonly", "true")
               : this.removeAttribute("readonly");
 
           // This is a workaround needed to cycle focus for the IME state
           // to be set properly (bug 488420)
           this.inputField.blur();
           this.inputField.focus();
+
           return val;
         ]]></setter>
       </property>
 
       <method name="openPopup">
         <body><![CDATA[
           this.popup.openAutocompletePopup(this, null);
         ]]></body>
@@ -42,17 +57,49 @@
         <body><![CDATA[
           // hack! we want to revert to the "all results" popup when the
           // controller would otherwise close us because of an empty search
           // string.
           if (this.value == "")
             this.showHistoryPopup();
         ]]></body>
       </method>
+
+      <method name="handleEvent">
+        <parameter name="aEvent"/>
+        <body><![CDATA[
+          switch (aEvent.type) {
+            case "keydown":
+              // If there is no VKB the user won't be able to enter any letter,
+              // but if the urlbar receive a keydown when it is readOnly this
+              // could be because of a hardware keyboard or a user generated event.
+              // In this case we want the text to be taken into account.
+              if (this.hasAttribute("open") && !this.hasAttribute("inactive") && this.readOnly &&
+                  !(aEvent.originalTarget instanceof HTMLInputElement))
+                this.readOnly = false;
+
+              break;
+            case "PopupChanged":
+              if (aEvent.detail)
+                this.setAttribute("inactive", "true");
+              else
+                this.removeAttribute("inactive");
+              break;
+
+            case "PanBegin":
+              if (this.hasAttribute("open") && !this.readOnly) {
+                this.readOnly = true;
+                this.blur();
+              }
+            break;
+          }
+        ]]></body>
+      </method>
     </implementation>
+
     <handlers>
       <handler event="text" phase="bubbling">
         <![CDATA[
           if (this.mController.input == this)
             this.mController.handleText();
         ]]>
       </handler>
 
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -333,28 +333,28 @@ var BrowserUI = {
       Elements.contentShowing.removeAttribute("disabled");
     }
   },
 
   pushPopup: function pushPopup(aPanel, aElements) {
     this._hidePopup();
     this._popup =  { "panel": aPanel,
                      "elements": (aElements instanceof Array) ? aElements : [aElements] };
-    this._dispatchPopupChanged();
+    this._dispatchPopupChanged(true);
   },
 
   popPopup: function popPopup() {
     this._popup = null;
-    this._dispatchPopupChanged();
+    this._dispatchPopupChanged(false);
   },
 
-  _dispatchPopupChanged: function _dispatchPopupChanged() {
+  _dispatchPopupChanged: function _dispatchPopupChanged(aVisible) {
     let stack = document.getElementById("stack");
-    let event = document.createEvent("Events");
-    event.initEvent("PopupChanged", true, false);
+    let event = document.createEvent("UIEvents");
+    event.initUIEvent("PopupChanged", true, true, window, aVisible);
     event.popup = this._popup;
     stack.dispatchEvent(event);
   },
 
   _hidePopup: function _hidePopup() {
     if (!this._popup)
       return;
     let panel = this._popup.panel;
@@ -422,46 +422,40 @@ var BrowserUI = {
     this._favicon = document.getElementById("urlbar-favicon");
     this._favicon.addEventListener("error", this, false);
 
     this._edit.addEventListener("click", this, false);
     this._edit.addEventListener("mousedown", this, false);
 
     BadgeHandlers.register(this._edit.popup);
 
-    let awesomePopup = document.getElementById("popup_autocomplete");
-    awesomePopup.addEventListener("popupshown", this, false);
-    awesomePopup.addEventListener("popuphidden", this, false);
+    window.addEventListener("NavigationPanelShown", this, false);
+    window.addEventListener("NavigationPanelHidden", this, false);
 
     document.getElementById("toolbar-main").ignoreDrag = true;
 
     let tabs = document.getElementById("tabs");
     tabs.addEventListener("TabSelect", this, true);
     tabs.addEventListener("TabOpen", this, true);
-    window.addEventListener("PanBegin", this, true);
     window.addEventListener("PanFinished", this, true);
 
     // listen content messages
     messageManager.addMessageListener("DOMLinkAdded", this);
     messageManager.addMessageListener("DOMTitleChanged", this);
     messageManager.addMessageListener("DOMWillOpenModalDialog", this);
     messageManager.addMessageListener("DOMWindowClose", this);
     // XXX bug 604192
     messageManager.addMessageListener("pagehide", this);
 
     messageManager.addMessageListener("Browser:OpenURI", this);
     messageManager.addMessageListener("Browser:SaveAs:Return", this);
 
     // listening mousedown for automatically dismiss some popups (e.g. larry)
     window.addEventListener("mousedown", this, true);
 
-    // listening mousedown to let devices with an hardware keyboard do direct
-    // input to the awesome bar
-    window.addEventListener("keydown", this, true);
-
     // listening escape to dismiss dialog on VK_ESCAPE
     window.addEventListener("keypress", this, true);
 
     // listening AppCommand to handle special keys
     window.addEventListener("AppCommand", this, true);
 
     // We can delay some initialization until after startup.  We wait until
     // the first page is shown, then dispatch a UIReadyDelayed event.
@@ -606,16 +600,17 @@ var BrowserUI = {
     if (this.isAutoCompleteOpen())
       return;
 
     this._hidePopup();
     this.activePanel = AllPagesList;
   },
 
   closeAutoComplete: function closeAutoComplete() {
+    dump("=========================== called\n");
     if (this.isAutoCompleteOpen())
       this._edit.popup.closePopup();
 
     this.activePanel = null;
   },
 
   isAutoCompleteOpen: function isAutoCompleteOpen() {
     return this.activePanel == AllPagesList;
@@ -813,36 +808,22 @@ var BrowserUI = {
 
         // Workaround to hide the tabstrip if it is partially visible
         // See bug 524469
         if (tabsVisibility > 0.0 && tabsVisibility < 1.0)
           Browser.hideSidebars();
 
         break;
       }
-      case "PanBegin":
-        if (this.activePanel && !this._edit.readOnly) {
-          this._edit.readOnly = true;
-          this._edit.blur();
-        }
-        break;
       case "PanFinished":
         let [tabsVisibility,,,] = Browser.computeSidebarVisibility();
         if (tabsVisibility == 0.0)
           document.getElementById("tabs").removeClosedTab();
         break;
       // Window events
-      case "keydown":
-        // If there is no VKB the user won't be able to enter any letter,
-        // but if the urlbar receive a keydown when it is readOnly this
-        // could be because of a hardware keyboard or a user generated event.
-        // In this case we want the text to be taken into account.
-        if (this.activePanel && this._edit.readOnly)
-          this._edit.readOnly = false;
-        break;
       case "keypress":
         if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE)
           this.handleEscape(aEvent);
         break;
       case "AppCommand":
         aEvent.stopPropagation();
         switch (aEvent.command) {
           case "Menu":
@@ -873,20 +854,20 @@ var BrowserUI = {
           aEvent.preventDefault();
         }
         break;
       // Favicon events
       case "error":
         this._favicon.src = "";
         break;
       // Awesome popup event
-      case "popupshown":
+      case "NavigationPanelShown":
         this._edit.setAttribute("open", "true");
         break;
-      case "popuphidden":
+      case "NavigationPanelHidden":
         this._edit.removeAttribute("open");
         break;
     }
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     let browser = aMessage.target;
     let json = aMessage.json;
@@ -1042,17 +1023,17 @@ var BrowserUI = {
           autoClose = true;
         }
 
         // Show/hide bookmark popup
         BookmarkPopup.toggle(autoClose);
         break;
       }
       case "cmd_opensearch":
-        this._edit.blur();
+        this.blurFocusedElement();
 
         MenuListHelperUI.show({
           title: Elements.browserBundle.getString("opensearch.searchWith"),
           menupopup: { children: BrowserSearch.engines },
           set selectedIndex(aIndex) {
             let name = this.menupopup.children[aIndex].label;
             BrowserUI.doOpenSearch(name);
           }
--- a/mobile/chrome/tests/browser_awesomescreen.js
+++ b/mobile/chrome/tests/browser_awesomescreen.js
@@ -29,16 +29,51 @@ function runNextTest() {
   }
   else {
     BrowserUI.closeAutoComplete();
     finish();
   }
 }
 
 //------------------------------------------------------------------------------
+// Case: Test awesome bar open attribute
+gTests.push({
+  desc: "Test awesome bar open attribute",
+
+  run: function() {
+    window.addEventListener("NavigationPanelShown", function(aEvent) {
+      window.removeEventListener(aEvent.type, arguments.callee, false);
+      gCurrentTest.onPopupShown();
+    }, false);
+
+    AllPagesList.doCommand();
+  },
+
+  onPopupShown: function() {
+    is(BrowserUI.activePanel == AllPagesList, true, "AllPagesList should be visible");
+    is(BrowserUI._edit.hasAttribute("open"), true, "The urlbar edit element should have the open attribute");
+
+    window.addEventListener("NavigationPanelHidden", function(aEvent) {
+      window.removeEventListener(aEvent.type, arguments.callee, false);
+      gCurrentTest.onPopupHidden();
+    }, false);
+
+    EventUtils.synthesizeKey("VK_ESCAPE", {}, window);
+  },
+
+  onPopupHidden: function() {
+    is(BrowserUI.activePanel == null, true, "AllPagesList should be dismissed");
+    is(BrowserUI._edit.hasAttribute("open"), false, "The urlbar edit element should not have the open attribute");
+
+    runNextTest();
+  }
+});
+
+
+//------------------------------------------------------------------------------
 // Case: Test typing a character should dismiss the awesome header
 gTests.push({
   desc: "Test typing a character should dismiss the awesome header",
 
   run: function() {
     window.addEventListener("NavigationPanelShown", function(aEvent) {
       window.removeEventListener(aEvent.type, arguments.callee, true);
       gCurrentTest.onPopupReady();
@@ -76,19 +111,19 @@ gTests.push({
 
 //------------------------------------------------------------------------------
 // Case: Test typing a character should open the awesome bar
 gTests.push({
   desc: "Test typing a character should open the All Pages List",
 
   run: function() {
     window.addEventListener("NavigationPanelShown", function(aEvent) {
-      window.removeEventListener(aEvent.type, arguments.callee, true);
+      window.removeEventListener(aEvent.type, arguments.callee, false);
       gCurrentTest.onPopupReady();
-    }, true);
+    }, false);
     BookmarkList.doCommand();
   },
 
   onPopupReady: function() {
     BrowserUI._edit.addEventListener("onsearchbegin", function(aEvent) {
       BrowserUI._edit.removeEventListener(aEvent.type, arguments.callee, false);
       gCurrentTest.onSearchBegin();
     }, false);
@@ -97,19 +132,19 @@ gTests.push({
 
   onSearchBegin: function() {
     let awesomeHeader = document.getElementById("awesome-header");
     is(awesomeHeader.hidden, true, "Awesome header should be hidden");
     is(BrowserUI.activePanel == AllPagesList, true, "AllPagesList should be opened on a keydown");
     is(BrowserUI._edit.readOnly, false, "urlbar should not be readonly after an input");
 
     window.addEventListener("NavigationPanelHidden", function(aEvent) {
-      window.removeEventListener(aEvent.type, arguments.callee, true);
+      window.removeEventListener(aEvent.type, arguments.callee, false);
       gCurrentTest.onPopupHidden();
-    }, true);
+    }, false);
 
     EventUtils.synthesizeKey("VK_ESCAPE", {}, window);
   },
 
   onPopupHidden: function() {
     is(BrowserUI.activePanel == null, true, "VK_ESCAPE should have dismissed the awesome panel");
     runNextTest();
   }
@@ -173,19 +208,19 @@ gTests.push({
         messageManager.removeMessageListener(aMessage.name, arguments.callee);
         gCurrentTest.onPageReady();
       }
     });
   },
 
   onPageReady: function() {
     window.addEventListener("NavigationPanelShown", function(aEvent) {
-      window.removeEventListener(aEvent.type, arguments.callee, true);
+      window.removeEventListener(aEvent.type, arguments.callee, false);
       gCurrentTest.onPopupReady();
-    }, true);
+    }, false);
 
     AllPagesList.doCommand();
   },
 
   onPopupReady: function() {
     let edit = BrowserUI._edit;
 
     Panels.forEach(function(aPanel) {
@@ -208,15 +243,13 @@ gTests.push({
       todo_is(edit.selectionStart == edit.textLenght && edit.selectionEnd == edit.textLength, true, "urlbar text should not be selected on a simple show");
       edit.click();
       is(edit.selectionStart == 0 && edit.selectionEnd == edit.textLength, true, "urlbar text should be selected on a click");
     });
     edit.clickSelectsAll = oldClickSelectsAll;
 
     BrowserUI.closeTab(this._currentTab);
 
-    Util.executeSoon(function() {
-      BrowserUI.activePanel = null;
-      runNextTest();
-    });
+    BrowserUI.activePanel = null;
+    runNextTest();
   }
 });
 
--- a/mobile/themes/core/browser.css
+++ b/mobile/themes/core/browser.css
@@ -243,17 +243,17 @@ toolbarbutton.urlbar-cap-button {
   margin: 0 !important;
   padding: 0 !important;
   border: none !important;
   border-top: 1px solid #262629 !important;
   border-bottom: 3px solid #262629 !important;
   -moz-border-radius: 0;
 }
 
-#urlbar-edit:not([readonly="true"]):not([open]):hover:active {
+#urlbar-edit:not([open]):hover:active {
   background-color: #8db8d8;
 }
 
 #urlbar-edit > hbox > .textbox-input-box {
   margin: 0;
 }
 
 #urlbar-edit > hbox > hbox > .textbox-input {