Bug 532677 - FormFill: Taskbar pops up to middle of the screen with no-associated protocol error [r=mfinkle]
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -1302,37 +1302,17 @@
</handler>
<handler event="click" button="0">
<![CDATA[
if (this.disabled || this.itemCount == 0)
return;
this.focus();
-
- let choices = [];
- let children = this.menupopup.children;
- for (let i = 0; i < children.length; i++) {
- let child = children[i];
- choices.push({ text: child.label, selected: child.selected, optionIndex: i });
- }
-
- let self = this;
- let wrapper = {
- multiple: false,
- choices: choices,
- changeCallback: function() {
- let evt = document.createEvent("XULCommandEvent");
- evt.initCommandEvent("command", true, true, window, 0, false, false, false, false, null);
- self.dispatchEvent(evt);
- },
- selectCallback: function(aIndex) { self.selectedIndex = aIndex; }
- };
-
- SelectHelperUI.show(wrapper);
+ MenuListHelperUI.show(this);
]]>
</handler>
</handlers>
</binding>
<binding id="chrome-select-option">
<content orient="horizontal" flex="1">
<xul:image class="chrome-select-option-image" anonid="check"/>
--- a/mobile/chrome/content/bindings/browser.js
+++ b/mobile/chrome/content/bindings/browser.js
@@ -247,16 +247,17 @@ WebNavigation.init();
let DOMEvents = {
init: function() {
addEventListener("DOMContentLoaded", this, false);
addEventListener("DOMTitleChanged", this, false);
addEventListener("DOMLinkAdded", this, false);
addEventListener("DOMWillOpenModalDialog", this, false);
+ addEventListener("DOMModalDialogClosed", this, true);
addEventListener("DOMWindowClose", this, false);
addEventListener("DOMPopupBlocked", this, false);
addEventListener("pageshow", this, false);
addEventListener("pagehide", this, false);
},
handleEvent: function(aEvent) {
let document = content.document;
@@ -316,16 +317,17 @@ let DOMEvents = {
rel: target.rel,
type: target.type
};
sendAsyncMessage("DOMLinkAdded", json);
break;
case "DOMWillOpenModalDialog":
+ case "DOMModalDialogClosed":
case "DOMWindowClose":
let retvals = sendSyncMessage(aEvent.type, { });
for (rv in retvals) {
if (rv.preventDefault) {
aEvent.preventDefault();
break;
}
}
@@ -384,34 +386,43 @@ PromptRemoter.prototype = {
}
function bringTabToFront() {
let event = window.document.createEvent("Events");
event.initEvent("DOMWillOpenModalDialog", true, false);
window.dispatchEvent(event);
}
+ function informClosedFrontTab() {
+ let event = window.document.createEvent("Events");
+ event.initEvent("DOMModalDialogClosed", true, false);
+ window.dispatchEvent(event);
+ }
+
window.wrappedJSObject.alert = function(aMessage) {
bringTabToFront();
- sendAsyncMessage("Prompt:Alert", {
+ sendSyncMessage("Prompt:Alert", {
message: aMessage
});
+ informClosedFrontTab();
}
window.wrappedJSObject.confirm = function(aMessage) {
bringTabToFront();
return sendSyncMessage("Prompt:Confirm", {
message: aMessage
});
+ informClosedFrontTab();
}
window.wrappedJSObject.prompt = function(aText, aValue) {
bringTabToFront();
return sendSyncMessage("Prompt:Prompt", {
text: aText,
value: aValue
});
+ informClosedFrontTab();
}
},
};
new PromptRemoter();
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -1571,16 +1571,20 @@ var FormHelperUI = {
messageManager.addMessageListener("FormAssist:Show", this);
messageManager.addMessageListener("FormAssist:Hide", this);
messageManager.addMessageListener("FormAssist:Update", this);
messageManager.addMessageListener("FormAssist:AutoComplete", this);
// Listen for events where form assistant should be closed
document.getElementById("tabs").addEventListener("TabSelect", this, true);
document.getElementById("browsers").addEventListener("URLChanged", this, true);
+
+ // Listen for modal dialog to show/hide the UI
+ messageManager.addMessageListener("DOMWillOpenModalDialog", this);
+ messageManager.addMessageListener("DOMModalDialogClosed", this);
},
show: function formHelperShow(aElement, aHasPrevious, aHasNext) {
this._open = true;
// Update the next/previous commands
this._cmdPrevious.setAttribute("disabled", !aHasPrevious);
this._cmdNext.setAttribute("disabled", !aHasNext);
@@ -1616,36 +1620,46 @@ var FormHelperUI = {
receiveMessage: function formHelperReceiveMessage(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "FormAssist:Show":
// if the user has manually disabled the Form Assistant UI we still
// want to show a UI for <select /> element but not managed by
// FormHelperUI
let enabled = Services.prefs.getBoolPref("formhelper.enabled");
- if (enabled) {
- this.show(json.current, json.hasPrevious, json.hasNext);
- }
- else {
- SelectHelperUI.show(json.current.list);
- }
+ enabled ? this.show(json.current, json.hasPrevious, json.hasNext)
+ : SelectHelperUI.show(json.current.choices);
break;
case "FormAssist:Hide":
this.hide();
break;
case "FormAssist:AutoComplete":
this._updateAutocompleteFor(json.current);
this._container.contentHasChanged();
break;
case "FormAssist:Update":
this._zoom(null, Rect.fromRect(json.caretRect));
break;
+
+ case "DOMWillOpenModalDialog":
+ if (this._open && aMessage.target == Browser.selectedBrowser) {
+ this._container.style.display = "none";
+ this._container._spacer.hidden = true;
+ }
+ break;
+
+ case "DOMModalDialogClosed":
+ if (this._open && aMessage.target == Browser.selectedBrowser) {
+ this._container.style.display = "-moz-box";
+ this._container._spacer.hidden = false;
+ }
+ break;
}
},
goToPrevious: function formHelperGoToPrevious() {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Previous", { });
},
goToNext: function formHelperGoToNext() {
@@ -2017,18 +2031,17 @@ var SelectHelperUI = {
break;
}
}
}
if (isIdentical)
return;
- this._list.changeCallback ? this._list.changeCallback()
- : Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceChange", { });
+ Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceChange", { });
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "click":
let item = aEvent.target;
if (item && item.hasOwnProperty("optionIndex")) {
if (this._list.multiple) {
@@ -2036,38 +2049,89 @@ var SelectHelperUI = {
item.selected = !item.selected;
}
else {
this.unselectAll();
// Select the new one and update the control
item.selected = true;
}
-
this.onSelect(item.optionIndex, item.selected, !this._list.multiple);
}
break;
}
},
onSelect: function(aIndex, aSelected, aClearAll) {
- if (this._list.selectCallback) {
- this._list.selectCallback(aIndex);
- return;
- }
-
let json = {
index: aIndex,
selected: aSelected,
clearAll: aClearAll
};
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceSelect", json);
}
};
+var MenuListHelperUI = {
+ get _container() {
+ delete this._container;
+ return this._container = document.getElementById("menulist-container");
+ },
+
+ get _popup() {
+ delete this._popup;
+ return this._popup = document.getElementById("menulist-popup");
+ },
+
+ _currentList: null,
+ show: function mn_show(aMenulist) {
+ this._currentList = aMenulist;
+
+ let container = this._container;
+ let listbox = this._popup.firstChild;
+ while (listbox.firstChild)
+ listbox.removeChild(listbox.firstChild);
+
+ let children = this._currentList.menupopup.children;
+ for (let i = 0; i < children.length; i++) {
+ let child = children[i];
+ let item = document.createElement("richlistitem");
+ if (child.selected)
+ item.setAttribute("selected", child.selected);
+ item.setAttribute("class", "menulist-command");
+
+ let label = document.createElement("label");
+ label.setAttribute("value", child.label);
+ item.appendChild(label);
+
+ listbox.appendChild(item);
+ }
+
+ container.hidden = false;
+ BrowserUI.pushPopup(this, [this._popup]);
+ },
+
+ hide: function mn_hide() {
+ this._currentList = null;
+ this._container.hidden = true;
+ BrowserUI.popPopup();
+ },
+
+ selectByIndex: function mn_selectByIndex(aIndex) {
+ this._currentList.selectedIndex = aIndex;
+
+ // Dispatch a xul command event to the attached menulist
+ let evt = document.createEvent("XULCommandEvent");
+ evt.initCommandEvent("command", true, true, window, 0, false, false, false, false, null);
+ this._currentList.dispatchEvent(evt);
+
+ this.hide();
+ }
+}
+
var ContextHelper = {
popupState: null,
get _panel() {
delete this._panel;
return this._panel = document.getElementById("context-container");
},
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -2166,31 +2166,32 @@ function importDialog(aParent, aSrc, aAr
if (!trimmed.length)
currentNode.parentNode.removeChild(currentNode);
}
let doc = xhr.responseXML.documentElement;
var dialog = null;
- // we need to insert before select-container if we want it to show correctly
- let selectContainer = document.getElementById("select-container");
- let parentNode = selectContainer.parentNode;
+ // we need to insert before menulist-container if we want it to show correctly
+ // for prompt.select for instance
+ let menulistContainer = document.getElementById("menulist-container");
+ let parentNode = menulistContainer.parentNode;
// emit DOMWillOpenModalDialog event
let event = document.createEvent("Events");
event.initEvent("DOMWillOpenModalDialog", true, false);
let dispatcher = aParent || getBrowser();
dispatcher.dispatchEvent(event);
// create a full-screen semi-opaque box as a background
let back = document.createElement("box");
back.setAttribute("class", "modal-block");
dialog = back.appendChild(document.importNode(doc, true));
- parentNode.insertBefore(back, selectContainer);
+ parentNode.insertBefore(back, menulistContainer);
dialog.arguments = aArguments;
dialog.parent = aParent;
return dialog;
}
function showDownloadManager(aWindowContext, aID, aReason) {
BrowserUI.showPanel("downloads-container");
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -534,16 +534,22 @@
<scrollbox id="select-list" flex="1" orient="vertical"/>
<hbox id="select-buttons" pack="center">
<button id="select-buttons-done" class="button-dark" label="&selectHelper.done;" oncommand="SelectHelperUI.hide();"/>
</hbox>
</vbox>
<spacer flex="1000"/>
</vbox>
+ <hbox id="menulist-container" class="window-width window-height context-block" top="0" left="0" hidden="true" flex="1">
+ <vbox id="menulist-popup" class="dialog-dark">
+ <richlistbox id="menulist-commands" onselect="MenuListHelperUI.selectByIndex(this.selectedIndex)"/>
+ </vbox>
+ </hbox>
+
<hbox id="context-container" class="window-width window-height context-block" top="0" left="0" hidden="true">
<vbox id="context-popup" class="dialog-dark">
<hbox id="context-header">
<label id="context-hint" crop="center" flex="1"/>
</hbox>
<richlistbox id="context-commands" onclick="ContextHelper.hide();">
<richlistitem class="context-command" id="context-openinnewtab" type="link-saveable" onclick="ContextCommands.openInNewTab();">
<label value="&contextOpenInNewTab.label;"/>
--- a/mobile/chrome/content/forms.js
+++ b/mobile/chrome/content/forms.js
@@ -63,16 +63,18 @@ function FormAssistant() {
addMessageListener("FormAssist:ChoiceSelect", this);
addMessageListener("FormAssist:ChoiceChange", this);
addMessageListener("FormAssist:AutoComplete", this);
addEventListener("keyup", this, false);
};
FormAssistant.prototype = {
+ _selectWrapper: null,
+
get currentElement() {
return this._elements[this._currentIndex];
},
get currentIndex() {
return this._currentIndex;
},
@@ -128,39 +130,40 @@ FormAssistant.prototype = {
this._elements = [aElement];
this.currentIndex = 0;
}
return this._open = true;
},
receiveMessage: function receiveMessage(aMessage) {
- if (!this._enabled || !this.currentElement)
+ let currentElement = this.currentElement;
+ if ((!this._enabled && !getWrapperForElement(currentElement)) || !currentElement)
return;
- let currentElement = this.currentElement;
let json = aMessage.json;
switch (aMessage.name) {
case "FormAssist:Previous":
this.currentIndex--;
break;
case "FormAssist:Next":
this.currentIndex++;
break;
case "FormAssist:ChoiceSelect": {
- let wrapper = getWrapperForElement(currentElement);
- wrapper.select(json.index, json.selected, json.clearAll);
+ this._selectWrapper = getWrapperForElement(currentElement);
+ this._selectWrapper.select(json.index, json.selected, json.clearAll);
break;
}
case "FormAssist:ChoiceChange": {
- let wrapper = getWrapperForElement(currentElement);
- wrapper.fireOnChange();
+ // ChoiceChange happened once we have move to an other element so we
+ // should remenber the used wrapper
+ this._selectWrapper.fireOnChange();
break;
}
case "FormAssist:AutoComplete":
currentElement.value = json.value;
break;
}
},
--- a/mobile/themes/core/browser.css
+++ b/mobile/themes/core/browser.css
@@ -1502,16 +1502,57 @@ pageaction:hover:active > vbox > .pageac
.chrome-select-option-image {
min-width: 30px;
}
.chrome-select-option[selected="true"] {
list-style-image: url("chrome://browser/skin/images/check-30.png");
}
+/* menulist popup ---------------------------------------------------------- */
+#menulist-popup {
+ border: none;
+ padding: 1px;
+ -moz-border-radius: 8px;
+}
+
+#menulist-commands {
+ border: 1px solid rgb(207,207,207);
+ -moz-border-radius: 8px;
+}
+
+.menulist-command {
+ -moz-box-align: center;
+ background-color: rgb(245,245,245);
+ min-width: 200px; /* keep the command from being too narrow */
+}
+
+.menulist-command:first-child {
+ background: -moz-linear-gradient(top, rgb(255,255,255), rgb(245,245,245));
+ -moz-border-radius: 8px 8px 0 0;
+}
+
+.menulist-command:last-child {
+ background: -moz-linear-gradient(top, rgb(245,245,245), rgb(215,215,215));
+ -moz-border-radius: 0 0 8px 8px;
+}
+
+.menulist-command:first-child:last-child {
+ -moz-border-radius: 8px;
+}
+
+.menulist-command:hover:active {
+ background: #8db8d8;
+}
+
+.menulist-command[selected="true"] {
+ pointer-events: none;
+ background: #8db8d8;
+}
+
/* context popup ----------------------------------------------------------- */
#context-popup {
/* Remove some dialog-dark styles */
padding: 8px 0 0 0;
border: none;
}
#share-title,
@@ -1539,8 +1580,9 @@ pageaction:hover:active > vbox > .pageac
background: -moz-linear-gradient(top, rgb(245,245,245), rgb(215,215,215));
-moz-border-radius: 0 0 8px 8px;
}
/* Force any command tap to highlight */
.context-command:hover:active {
background: #8db8d8;
}
+