Bug 596614 - focusing the URL field on the awesomescreen should not visibly change categories [r=mfinkle]
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -9,46 +9,72 @@
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>
<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[
+ this._ignoreController = true;
+ 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();
+
+ this._ignoreController = false;
+ return val;
+ ]]></setter>
+ </property>
+
+ <method name="attachController">
+ <body><![CDATA[
+ if (!this._ignoreController && this.mController.input != this)
+ this.mController.input = this;
+ ]]></body>
+ </method>
+
<method name="openPopup">
<body><![CDATA[
this.popup.openAutocompletePopup(this, null);
]]></body>
</method>
+
<method name="closePopup">
<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>
</implementation>
<handlers>
- <handler event="keypress" phase="capturing">
- <![CDATA[
- if (event.keyCode == event.DOM_VK_RETURN)
- setTimeout(function() { BrowserUI.activePanel = null }, 0);
- else if (this.readOnly)
- this.readOnly = false;
- ]]>
- </handler>
<handler event="text" phase="bubbling">
<![CDATA[
if (this.mController.input == this)
this.mController.handleText();
]]>
</handler>
+
+ <handler event="focus" phase="bubbling">
+ <![CDATA[
+ if (this.clickSelectsAll)
+ this.select();
+ ]]>
+ </handler>
+
<handler event="blur" phase="capturing">
<![CDATA[
// Bug 583341 - suppress disconnect of autocomplete controller
this._dontBlur = true;
]]>
</handler>
</handlers>
</binding>
@@ -183,17 +209,16 @@
<parameter name="aInput"/>
<parameter name="aElement"/>
<body><![CDATA[
if (this._popupOpen)
return;
this._selectedItem = null;
this._input = aInput;
- this._input.select();
this._popupOpen = true;
this.invalidate();
let event = document.createEvent("Events");
event.initEvent("popupshown", true, false);
this.dispatchEvent(event);
]]></body>
@@ -220,17 +245,16 @@
this._scrollBoxObject.scrollTo(0, 0);
]]></body>
</method>
<!-- Helper used by active dialog system -->
<method name="close">
<body><![CDATA[
this.input.reset();
- this.input.blur();
this.closePopup();
]]></body>
</method>
<field name="_XULNS">("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")</field>
<method name="invalidate">
<body><![CDATA[
@@ -461,21 +485,21 @@
]]></body>
</method>
</implementation>
<handlers>
<handler event="click" button="0">
<![CDATA[
let target = event.originalTarget;
- if (target.localName == "autocompleteresult" && !target._empty) {
- this._selectedIndex = target._index;
- this.input.controller.handleEnter(true);
- BrowserUI.activePanel = null;
- }
+ if (target._empty)
+ return;
+
+ this._selectedIndex = target._index;
+ this.input.controller.handleEnter(true);
]]>
</handler>
</handlers>
</binding>
<binding id="place-base">
<content/>
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -108,22 +108,22 @@ var BrowserUI = {
if (Browser._tabs[i].browser == aBrowser) {
Browser.selectedTab = Browser.tabs[i];
break;
}
}
},
_titleChanged: function(aBrowser) {
- var browser = Browser.selectedBrowser;
+ let browser = Browser.selectedBrowser;
if (browser && aBrowser != browser)
return;
- var url = this.getDisplayURI(browser);
- var caption = browser.contentTitle || url;
+ let url = this.getDisplayURI(browser);
+ let caption = browser.contentTitle || url;
if (Util.isURLEmpty(url))
caption = "";
this._setURI(caption);
},
/*
@@ -193,17 +193,17 @@ var BrowserUI = {
return;
this._toolbarLocked--;
if (!this._toolbarLocked)
document.getElementById("toolbar-moveable-container").top = "";
},
_setURI: function _setURI(aCaption) {
- if (this.isAutoCompleteOpen())
+ if (this._edit.hasAttribute("open"))
this._edit.defaultValue = aCaption;
else
this._edit.value = aCaption;
},
_editURI: function _editURI(aEdit) {
if (aEdit) {
// If the urlbar is not opened yet, inform the broadcaster and then
@@ -215,35 +215,41 @@ var BrowserUI = {
this._edit.defaultValue = this._edit.value;
// Now, replace the web page title by the url of the page
let urlString = this.getDisplayURI(Browser.selectedBrowser);
if (Util.isURLEmpty(urlString))
urlString = "";
this._edit.value = urlString;
}
-
- // If the urlbar readOnly state is set to false or if the window is in
- // portrait then we refresh the IME state to display the VKB if any
- if (!this._edit.readOnly || Util.isPortrait()) {
- // This is a workaround needed to cycle focus for the IME state
- // to be set properly (bug 488420)
- this._edit.blur();
- gFocusManager.setFocus(this._edit, Ci.nsIFocusManager.FLAG_NOSCROLL);
- }
-
- this._edit.readOnly = false;
}
else if (!aEdit) {
this._updateToolbar();
}
},
- updateAwesomeHeader: function updateAwesomeHeader(aVisible) {
- document.getElementById("awesome-header").hidden = aVisible;
+ updateAwesomeHeader: function updateAwesomeHeader(aString) {
+ // During an awesome search we always show the popup_autocomplete/AllPagesList
+ // panel since this looks in every places and the rationale behind typing
+ // is to find something, whereever it is.
+ if (this.activePanel != AllPagesList) {
+ let inputField = this._edit;
+ let oldClickSelectsAll = inputField.clickSelectsAll;
+ inputField.clickSelectsAll = false;
+
+ this.activePanel = AllPagesList;
+
+ // changing the searchString property call updateAwesomeHeader again
+ inputField.controller.searchString = aString;
+ inputField.readOnly = false;
+ inputField.clickSelectsAll = oldClickSelectsAll;
+ return;
+ }
+
+ document.getElementById("awesome-header").hidden = (aString != "");
},
_closeOrQuit: function _closeOrQuit() {
// Close active dialog, if we have one. If not then close the application.
if (this.activePanel) {
this.activePanel = null;
} else if (this.activeDialog) {
this.activeDialog.close();
@@ -264,21 +270,27 @@ var BrowserUI = {
return;
let container = document.getElementById("awesome-panels");
if (aPanel) {
container.hidden = false;
aPanel.open();
} else {
container.hidden = true;
- BrowserUI.showToolbar(false);
+ this.showToolbar(false);
+ document.getElementById("awesome-header").hidden = false;
}
+ this._edit.readOnly = !(aPanel == AllPagesList && Util.isPortrait());
+ if (this._edit.readOnly)
+ this._edit.blur();
+
if (this._activePanel)
this._activePanel.close();
+
this._activePanel = aPanel;
},
get activeDialog() {
// Return the topmost dialog
if (this._dialogs.length)
return this._dialogs[this._dialogs.length - 1];
return null;
@@ -418,16 +430,20 @@ var BrowserUI = {
messageManager.addMessageListener("DOMWindowClose", 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);
// Push the panel initialization out of the startup path
// (Using a message because we have no good way to delay-init [Bug 535366])
@@ -561,32 +577,28 @@ var BrowserUI = {
if (this.isAutoCompleteOpen())
return;
this._hidePopup();
this.activePanel = AllPagesList;
},
closeAutoComplete: function closeAutoComplete(aResetInput) {
- if (!this.isAutoCompleteOpen())
- return;
-
- if (aResetInput)
- this._edit.popup.close();
- else
- this._edit.popup.closePopup();
-
- // Because the controller is not detached during a blur event for Meego
- // compatibility with the VKB, we need to detach it manually
- this._edit.detachController();
+ if (this.isAutoCompleteOpen()) {
+ if (aResetInput)
+ this._edit.popup.close();
+ else
+ this._edit.popup.closePopup();
+ }
+
this.activePanel = null;
},
isAutoCompleteOpen: function isAutoCompleteOpen() {
- return this._edit.popup.popupOpen;
+ return this.activePanel == AllPagesList;
},
doOpenSearch: function doOpenSearch(aName) {
// save the current value of the urlbar
let searchValue = this._edit.value;
// Give the new page lots of room
Browser.hideSidebars();
@@ -782,16 +794,24 @@ var BrowserUI = {
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":
@@ -801,17 +821,21 @@ var BrowserUI = {
this.doCommand("cmd_openLocation");
break;
default:
break;
}
break;
// URL textbox events
case "click":
- this.doCommand("cmd_openLocation");
+ // if there is an already opened panel, keep it active (bug 596614).
+ if (this.activePanel && this._edit.readOnly)
+ this._edit.readOnly = false;
+ else if (!this.activePanel)
+ this.doCommand("cmd_openLocation");
break;
case "mousedown":
if (!this._isEventInsidePopup(aEvent))
this._hidePopup();
let selectAll = Services.prefs.getBoolPref("browser.urlbar.doubleClickSelectsAll");
if (aEvent.detail == 2 && aEvent.button == 0 && selectAll && aEvent.target == this._edit) {
this._edit.editor.selectAll();
@@ -823,17 +847,16 @@ var BrowserUI = {
this._favicon.src = "";
break;
// Awesome popup event
case "popupshown":
this._edit.setAttribute("open", "true");
break;
case "popuphidden":
this._edit.removeAttribute("open");
- this._edit.readOnly = true;
break;
}
},
receiveMessage: function receiveMessage(aMessage) {
let browser = aMessage.target;
let json = aMessage.json;
switch (aMessage.name) {
@@ -1432,17 +1455,19 @@ var NewTabPopup = {
};
var AwesomePanel = function(aElementId, aCommandId) {
let command = document.getElementById(aCommandId);
this.panel = document.getElementById(aElementId),
this.open = function aw_open() {
- BrowserUI.pushDialog(this);
+ if (!BrowserUI.activePanel)
+ BrowserUI.pushDialog(this);
+
command.setAttribute("checked", "true");
this.panel.hidden = false;
if (this.panel.hasAttribute("onshow")) {
let func = new Function("panel", this.panel.getAttribute("onshow"));
func.call(this.panel);
}
@@ -1454,29 +1479,27 @@ var AwesomePanel = function(aElementId,
if (this.panel.hasAttribute("onhide")) {
let func = new Function("panel", this.panel.getAttribute("onhide"));
func.call(this.panel);
}
if (this.panel.close)
this.panel.close();
- this.panel.blur();
this.panel.hidden = true;
command.removeAttribute("checked", "true");
- BrowserUI.popDialog();
+ if (!BrowserUI.activePanel)
+ BrowserUI.popDialog();
},
this.openLink = function aw_openLink(aEvent) {
let item = aEvent.originalTarget;
let uri = item.getAttribute("url") || item.getAttribute("uri");
- if (uri != "") {
+ if (uri != "")
BrowserUI.goToURI(uri);
- BrowserUI.activePanel = null;
- }
}
};
var BookmarkPopup = {
get box() {
delete this.box;
this.box = document.getElementById("bookmark-popup");
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -247,21 +247,21 @@
class="uri-element"
autocompletesearch="history"
autocompletepopup="popup_autocomplete"
enablehistory="false"
maxrows="6"
completeselectedindex="true"
minresultsforpopup="0"
oncontextmenu="event.preventDefault();"
- onsearchbegin="BrowserUI.updateAwesomeHeader(this.controller.searchString != '');"
+ onsearchbegin="BrowserUI.updateAwesomeHeader(this.controller.searchString);"
emptytext="&urlbar.emptytext;"
flex="1"
+ readonly="true"
ontextentered="BrowserUI.goToURI();"
- readonly="true"
clickSelectsAll="true"/>
<hbox id="urlbar-icons" observes="bcast_urlbarState">
<toolbarbutton id="tool-reload" class="urlbar-cap-button"
oncommand="CommandUpdater.doCommand(event.shiftKey ? 'cmd_forceReload' : 'cmd_reload');"/>
<toolbarbutton id="tool-stop" class="urlbar-cap-button" command="cmd_stop"/>
<toolbarbutton id="tool-search" class="urlbar-cap-button" command="cmd_opensearch"/>
</hbox>
</hbox>
@@ -508,17 +508,19 @@
<toolbarbutton type="radio" group="awesome-header" label="&desktopHeader.label;" command="cmd_remoteTabs" class="choice-remotetabs show-text"/>
#endif
</hbox>
<!-- titlebar autocomplete results -->
<vbox id="popup_autocomplete" class="panel-dark" flex="1" onshow="BrowserUI._edit.showHistoryPopup();" hidden="true"/>
<placelist id="bookmarks-items" type="bookmarks" onopen="BookmarkList.openLink(event);" onhide="BrowserUI.updateStar();" flex="1" hidden="true"/>
<historylist id="history-items" onopen="HistoryList.openLink(event);" flex="1" hidden="true"/>
+#ifdef MOZ_SERVICES_SYNC
<remotetabslist id="remotetabs-items" onopen="RemoteTabsList.openLink(event)" flex="1" hidden="true"/>
+#endif
</vbox>
<vbox id="newtab-popup" hidden="true" class="dialog-dark" onclick="NewTabPopup.selectTab()" align="center" left="21">
<label/>
</vbox>
<!-- options dialog for select form field -->
<vbox id="select-container" hidden="true" pack="center">
--- a/mobile/chrome/tests/browser_awesomescreen.js
+++ b/mobile/chrome/tests/browser_awesomescreen.js
@@ -44,13 +44,16 @@ gTests.push({
gCurrentTest.onPopupReady();
}, true);
BrowserUI.doCommand("cmd_openLocation");
},
onPopupReady: function() {
is(Elements.urlbarState.getAttribute("mode"), "edit", "bcast_urlbarState mode attribute should be equal to 'edit'");
- is(BrowserUI._edit.readOnly, false, "urlbar input textbox should not be readonly once it is open");
+ is(BrowserUI._edit.readOnly, true, "urlbar input textbox be readonly once it is open in landscape");
+
+ BrowserUI._edit.click();
+ is(BrowserUI._edit.readOnly, false, "urlbar input textbox should not be readonly once it is open in landscape and click again");
runNextTest();
}
});
--- a/mobile/chrome/tests/browser_navigation.js
+++ b/mobile/chrome/tests/browser_navigation.js
@@ -51,17 +51,17 @@ function runNextTest() {
//------------------------------------------------------------------------------
// Case: Loading a page into the URLBar with VK_RETURN
gTests.push({
desc: "Loading a page into the URLBar with VK_RETURN",
_currentTab: null,
run: function() {
- gCurrentTest._currentTab = Browser.addTab(testURL_01, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_01);
// Wait for the tab to load, then do the test
waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01));
},
onPageReady: function() {
// Test the mode
let urlIcons = document.getElementById("urlbar-icons");
@@ -104,17 +104,17 @@ gTests.push({
is(stopStyle.visibility, "collapse", "STOP is hidden");
let reload = document.getElementById("tool-reload");
let reloadStyle = window.getComputedStyle(reload, null);
is(reloadStyle.visibility, "collapse", "RELOAD is hidden");
// Send the string and press return
EventUtils.synthesizeString(testURL_02, window);
- EventUtils.synthesizeKey("VK_RETURN", {}, window)
+ EventUtils.synthesizeKey("VK_RETURN", {}, window);
// Wait for the tab to load, then do the test
waitFor(gCurrentTest.onPageFinish, pageLoaded(testURL_02));
},
onPageFinish: function() {
let urlIcons = document.getElementById("urlbar-icons");
is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'");
@@ -157,46 +157,46 @@ gTests.push({
//------------------------------------------------------------------------------
// Bug 570706 - --browser-chrome Mochitests on Fennec [post navigation]
// Check for text in the url bar for no title, with title and title change after pageload
gTests.push({
desc: "Check for text in the url bar for no title, with title and title change after pageload",
_currentTab: null,
run: function() {
- gCurrentTest._currentTab = Browser.addTab(testURL_03, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_03);
// Wait for the tab to load, then do the test
messageManager.addMessageListener("pageshow", function() {
if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_03) {
messageManager.removeMessageListener("pageshow", arguments.callee);
gCurrentTest.onPageReady();
}});
},
onPageReady: function() {
let urlbarEdit = document.getElementById("urlbar-edit");
is(urlbarEdit.value, "English Title Page", "The title must be displayed in urlbar");
Browser.closeTab(gCurrentTest._currentTab);
- gCurrentTest._currentTab = Browser.addTab(testURL_04, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_04);
messageManager.addMessageListener("pageshow", function() {
if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_04) {
messageManager.removeMessageListener("pageshow", arguments.callee);
gCurrentTest.onPageReady2();
}});
},
onPageReady2: function(){
let urlbarEdit = document.getElementById("urlbar-edit");
is(urlbarEdit.value, testURL_04, "The url for no title must be displayed in urlbar");
Browser.closeTab(gCurrentTest._currentTab);
// Check whether title appears after a pageload
- gCurrentTest._currentTab = Browser.addTab(testURL_01, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_01);
messageManager.addMessageListener("pageshow", function() {
if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_01) {
messageManager.removeMessageListener("pageshow", arguments.callee);
gCurrentTest.onPageReady3();
}});
},
onPageReady3: function(){
@@ -229,31 +229,31 @@ gTests.push({
});
// Case: Check for appearance of the favicon
gTests.push({
desc: "Check for appearance of the favicon",
_currentTab: null,
run: function() {
- gCurrentTest._currentTab = Browser.addTab(testURL_04, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_04);
messageManager.addMessageListener("pageshow", function() {
if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_04) {
messageManager.removeMessageListener("pageshow", arguments.callee);
gCurrentTest.onPageReady();
}});
},
onPageReady: function() {
let favicon = document.getElementById("urlbar-favicon");
is(favicon.src, "", "The default favicon must be loaded");
Browser.closeTab(gCurrentTest._currentTab);
- gCurrentTest._currentTab = Browser.addTab(testURL_03, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_03);
messageManager.addMessageListener("pageshow", function() {
if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_03) {
messageManager.removeMessageListener("pageshow", arguments.callee);
gCurrentTest.onPageFinish();
}});
},
onPageFinish: function(){
@@ -269,17 +269,17 @@ gTests.push({
// These tests use setTimeout instead of waitFor or addEventListener, because
// in-page navigation does not fire any loading events or progress
// notifications, and happens more or less instantly.
gTests.push({
desc: "Navigating within a page via URI fragments",
_currentTab: null,
run: function() {
- gCurrentTest._currentTab = Browser.addTab(testURL_01, true);
+ gCurrentTest._currentTab = BrowserUI.newTab(testURL_01);
waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01));
},
onPageReady: function() {
ok(back.disabled, "Can't go back");
ok(forward.disabled, "Can't go forward");
messageManager.addMessageListener("WebProgress:LocationChange", gCurrentTest.onFragmentLoaded);
--- 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([open]):hover:active {
+#urlbar-edit:not([readonly="true"]):not([open]):hover:active {
background-color: #8db8d8;
}
#urlbar-edit > hbox > .textbox-input-box {
margin: 0;
}
#urlbar-edit > hbox > hbox > .textbox-input {