Bug 573560 - Simplify the Form Assistant code in browser-ui.js [r=mfinkle]

This commit is contained in:
Vivien Nicolas 2010-07-13 12:19:22 -04:00
parent 6a3f7f106d
commit 4490f52cd9
4 changed files with 276 additions and 352 deletions

View File

@ -1092,13 +1092,27 @@
return;
this.focus();
try {
SelectHelper.show(new BasicWrapper(this));
}
catch(e) {
Services.scriptloader.loadSubScript("chrome://browser/content/forms.js", this);
SelectHelper.show(new BasicWrapper(this));
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);
]]>
</handler>
</handlers>

View File

@ -398,7 +398,7 @@ var BrowserUI = {
WeaveGlue.init();
});
FormMessageReceiver.start();
FormHelperUI.init();
},
uninit : function() {
@ -1408,57 +1408,160 @@ var BookmarkList = {
};
/**
* Responsible for handling the interface for navigating forms and filling in information.
* - Navigating forms is handled by next and previous buttons.
* Responsible for navigating forms and filling in information.
* - Navigating forms is handled by next and previous commands.
* - When an element is focused, the browser view zooms in to the control.
* - The caret positionning and the view are sync to keep the type
* in text into view for input fields (text/textarea).
* - Provides autocomplete box for input fields.
*/
var FormHelper = {
_open: false,
_navigator: null,
var FormHelperUI = {
init: function formHelperInit() {
this._container = document.getElementById("form-helper-container");
this._cmdPrevious = document.getElementById("cmd_formPrevious");
this._cmdNext = document.getElementById("cmd_formNext");
this._helperSpacer = document.getElementById("form-helper-spacer");
this._autofillContainer = document.getElementById("form-helper-autofill");
get _container() {
delete this._container;
return this._container = document.getElementById("form-helper-container");
// Listen for form assistant messages from content
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);
},
get _helperSpacer() {
delete this._helperSpacer;
return this._helperSpacer = document.getElementById("form-helper-spacer");
show: function formHelperShow(aElement, aHasPrevious, aHasNext) {
this._open = true;
// Update the next/previous commands
this._cmdPrevious.setAttribute("disabled", !aHasPrevious);
this._cmdNext.setAttribute("disabled", !aHasNext);
let lastElement = this._currentElement || null;
this._currentElement = {
name: aElement.name,
value: aElement.value,
maxLength: aElement.maxLength,
list: aElement.choices
}
this._updateContainer(lastElement, this._currentElement);
this._zoom(Rect.fromRect(aElement.rect), Rect.fromRect(aElement.caretRect));
},
get _autofillContainer() {
delete this._autofillContainer;
return this._autofillContainer = document.getElementById("form-helper-autofill");
hide: function formHelperHide() {
if (!this._open)
return;
this._updateContainerForSelect(this._currentElement, null);
this._open = false;
},
doAutoFill: function formHelperDoAutoFill(aElement) {
// Suggestions are only in <label>s. Ignore the rest.
if (aElement instanceof Ci.nsIDOMXULLabelElement)
this._navigator.getCurrent().autocomplete(aElement.value);
handleEvent: function(aEvent) {
if (aEvent.type == "TabSelect" || aEvent.type == "URLChanged")
this.hide();
},
goToPrevious: function formHelperGoToPrevious() {
this._navigator.goToPrevious();
},
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);
}
break;
goToNext: function formHelperGoToNext() {
this._navigator.goToNext();
},
case "FormAssist:AutoComplete":
this._updateAutocompleteFor(json.current);
this._updateHelperSize();
break;
updateAutocompleteFor: function updateAutocompleteFor(aElement) {
let suggestions = this.getAutocompleteSuggestions(aElement);
this._setSuggestions(suggestions);
if (suggestions.length == 0) {
let height = Math.floor(this._container.getBoundingClientRect().height);
this._container.top = window.innerHeight - height;
let containerHeight = this._container.getBoundingClientRect().height;
this._helperSpacer.setAttribute("height", containerHeight);
case "FormAssist:Update":
this._zoom(null, Rect.fromRect(json.caretRect));
break;
}
},
getAutocompleteSuggestions: function(aElement) {
goToPrevious: function formHelperGoToPrevious() {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Previous", { });
},
goToNext: function formHelperGoToNext() {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Next", { });
},
doAutoComplete: function formHelperDoAutoComplete(aElement) {
// Suggestions are only in <label>s. Ignore the rest.
if (aElement instanceof Ci.nsIDOMXULLabelElement)
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:AutoComplete", { value: aElement.value });
},
get _open() {
return !this._container.hidden;
},
set _open(aVal) {
if (aVal == this._open)
return;
let bv = Browser._browserView;
bv.ignorePageScroll(aVal);
this._container.hidden = !aVal;
this._helperSpacer.hidden = !aVal;
if (aVal) {
this._zoomStart();
} else {
this._currentElement = null;
this._zoomFinish();
// give the form spacer area back to the content
// XXX this should probably be removed with layers
let bv = Browser._browserView;
Browser.forceChromeReflow();
Browser.contentScrollboxScroller.scrollBy(0, 0);
bv.onAfterVisibleMove();
}
let evt = document.createEvent("UIEvents");
evt.initUIEvent("FormUI", true, true, window, aVal);
this._container.dispatchEvent(evt);
},
_updateAutocompleteFor: function _formHelperUpdateAutocompleteFor(aElement) {
let suggestions = this._getAutocompleteSuggestions(aElement);
this._displaySuggestions(suggestions);
},
_displaySuggestions: function _formHelperDisplaySuggestions(aSuggestions) {
let autofill = this._autofillContainer;
while (autofill.hasChildNodes())
autofill.removeChild(autofill.lastChild);
let fragment = document.createDocumentFragment();
for (let i = 0; i < aSuggestions.length; i++) {
let value = aSuggestions[i];
let button = document.createElement("label");
button.setAttribute("value", value);
fragment.appendChild(button);
}
autofill.appendChild(fragment);
autofill.collapsed = !aSuggestions.length;
},
/** Retrieve the autocomplete list from the autocomplete service for an element */
_getAutocompleteSuggestions: function _formHelperGetAutocompleteSuggestions(aElement) {
if (!aElement.canAutocomplete)
return [];
@ -1474,206 +1577,91 @@ var FormHelper = {
return suggestions;
},
/**
* Shows form helper. If helper is already shown, then it selects the new element.
*/
open: function formHelperOpen(navigator) {
let bv = Browser._browserView;
if (!this._open) {
this._open = true;
bv.ignorePageScroll(true);
this._container.hidden = false;
this._helperSpacer.hidden = false;
}
let lastWrapper = this._navigator ? this._navigator.getCurrent() : null;
this._navigator = navigator;
this._currentElementChange(lastWrapper, navigator.getCurrent());
let evt = document.createEvent("UIEvents");
evt.initUIEvent("FormUI", true, true, window, this._open);
this._container.dispatchEvent(evt);
},
close: function formHelperHide() {
if (!this._open)
return;
this._updateContainerForSelect(this._navigator.getCurrent(), null);
this._helperSpacer.hidden = true;
this._zoomFinish();
// give the form spacer area back to the content
let bv = Browser._browserView;
Browser.forceChromeReflow();
Browser.contentScrollboxScroller.scrollBy(0, 0);
bv.onAfterVisibleMove();
bv.ignorePageScroll(false);
this._container.hidden = true;
this._open = false;
if (this._navigator) {
this._navigator.endSession();
this._navigator = null;
}
let evt = document.createEvent("UIEvents");
evt.initUIEvent("FormUI", true, true, window, this._open);
this._container.dispatchEvent(evt);
},
/** The currently selected element has changed. */
_currentElementChange: function(lastWrapper, currentWrapper) {
this._updateContainer(lastWrapper, currentWrapper);
this._zoom(currentWrapper.getRect());
},
/** Update the form helper container to reflect new element user is editing. */
_updateContainer: function(aLastWrapper, aCurrentWrapper) {
this._updateContainerForSelect(aLastWrapper, aCurrentWrapper);
_updateContainer: function _formHelperUpdateContainer(aLastElement, aCurrentElement) {
this._updateContainerForSelect(aLastElement, aCurrentElement);
// Setup autofill UI
this.updateAutocompleteFor(this._navigator.getCurrent().element);
this._updateAutocompleteFor(aCurrentElement);
this._updateHelperSize();
},
_updateHelperSize: function _formHelperUpdateHelperSize() {
let height = Math.floor(this._container.getBoundingClientRect().height);
this._container.top = window.innerHeight - height;
let navigator = this._navigator;
document.getElementById("form-helper-previous").disabled = !navigator.hasPrevious();
document.getElementById("form-helper-next").disabled = !navigator.hasNext();
let containerHeight = this._container.getBoundingClientRect().height;
this._helperSpacer.setAttribute("height", containerHeight);
},
/** Helper for _updateContainer that handles the case where the new element is a select. */
_updateContainerForSelect: function(aLastWrapper, aCurrentWrapper) {
let lastHasChoices = aLastWrapper && aLastWrapper.hasChoices();
let currentHasChoices = aCurrentWrapper && aCurrentWrapper.hasChoices();
_updateContainerForSelect: function _formHelperUpdateContainerForSelect(aLastElement, aCurrentElement) {
let lastHasChoices = aLastElement && (aLastElement.list != null);
let currentHasChoices = aCurrentElement && (aCurrentElement.list != null);
if (!lastHasChoices && currentHasChoices) {
SelectHelper.dock(this._container);
SelectHelper.show(aCurrentWrapper);
}
else if (lastHasChoices && currentHasChoices) {
SelectHelper.reset();
SelectHelper.show(aCurrentWrapper);
}
else if (lastHasChoices && !currentHasChoices) {
SelectHelper.hide();
SelectHelperUI.dock(this._container);
SelectHelperUI.show(aCurrentElement.list);
} else if (lastHasChoices && currentHasChoices) {
SelectHelperUI.reset();
SelectHelperUI.show(aCurrentElement.list);
} else if (lastHasChoices && !currentHasChoices) {
SelectHelperUI.hide();
}
},
/** Zoom and move viewport so that element is legible and touchable. */
_zoom: function formHelperZoom(elRect) {
_zoom: function formHelperZoom(aElementRect, aCaretRect) {
let bv = Browser._browserView;
if (!bv.allowZoom)
return;
let zoomLevel = Browser._getZoomLevelForRect(bv.browserToViewportRect(elRect.clone()));
if (Services.prefs.getBoolPref("formhelper.autozoom")) {
this._restore = {
zoom: bv.getZoomLevel(),
contentScrollOffset: Browser.getScrollboxPosition(Browser.contentScrollboxScroller),
pageScrollOffset: Browser.getScrollboxPosition(Browser.pageScrollboxScroller)
};
let zoomRect = bv.getVisibleRect();
// Zoom to a specified Rect
if (aElementRect && bv.allowZoom && Services.prefs.getBoolPref("formhelper.autozoom")) {
// Zoom to an element by keeping the caret into view
let zoomLevel = Browser._getZoomLevelForRect(bv.browserToViewportRect(aElementRect.clone()));
zoomLevel = Math.min(Math.max(kBrowserFormZoomLevelMin, zoomLevel), kBrowserFormZoomLevelMax);
let zoomRect = Browser._getZoomRectForPoint(elRect.center().x, elRect.y, zoomLevel);
let caretRect = Rect.fromRect(this._navigator.getCurrent().element.caretRect);
if (caretRect) {
caretRect = Browser._browserView.browserToViewportRect(caretRect);
if (!zoomRect.contains(caretRect)) {
let [deltaX, deltaY] = this._getOffsetForCaret(caretRect, zoomRect);
zoomRect.translate(deltaX, deltaY);
}
zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, zoomLevel);
Browser.animatedZoomTo(zoomRect);
}
// Move the view to show the caret if needed
if (aCaretRect) {
let caretRect = bv.browserToViewportRect(aCaretRect);
if (zoomRect.contains(caretRect))
return;
let [deltaX, deltaY] = this._getOffsetForCaret(caretRect, zoomRect);
if (deltaX != 0 || deltaY != 0) {
Browser.contentScrollboxScroller.scrollBy(deltaX, deltaY);
bv.onAfterVisibleMove();
}
Browser.animatedZoomTo(zoomRect);
}
},
/* Store the current zoom level, and scroll positions to restore them if needed */
_zoomStart: function _formHelperZoomStart() {
if (!Services.prefs.getBoolPref("formhelper.restore"))
return;
this._restore = {
zoom: Browser._browserView.getZoomLevel(),
contentScrollOffset: Browser.getScrollboxPosition(Browser.contentScrollboxScroller),
pageScrollOffset: Browser.getScrollboxPosition(Browser.pageScrollboxScroller)
};
},
/** Element is no longer selected. Restore zoom level if setting is enabled. */
_zoomFinish: function _zoomFinish() {
_zoomFinish: function _formHelperZoomFinish() {
if(!gPrefService.getBoolPref("formhelper.restore"))
return;
let restore = this._restore;
if (restore && Services.prefs.getBoolPref("formhelper.restore")) {
bv.setZoomLevel(restore.zoom);
Browser.contentScrollboxScroller.scrollTo(restore.contentScrollOffset.x,
restore.contentScrollOffset.y);
Browser.pageScrollboxScroller.scrollTo(restore.pageScrollOffset.x,
restore.pageScrollOffset.y);
}
},
/** Populate autofill container with list of strings for suggestions */
_setSuggestions: function(aSuggestions) {
let autofill = this._autofillContainer;
while (autofill.hasChildNodes())
autofill.removeChild(autofill.lastChild);
let fragment = document.createDocumentFragment();
for (let i = 0; i < aSuggestions.length; i++) {
let value = aSuggestions[i];
let button = document.createElement("label");
button.setAttribute("value", value);
fragment.appendChild(button);
}
autofill.appendChild(fragment);
autofill.collapsed = !aSuggestions.length;
}
};
var FormMessageReceiver = {
start: function() {
messageManager.addMessageListener("FormAssist:Show", this);
messageManager.addMessageListener("FormAssist:Hide", this);
messageManager.addMessageListener("FormAssist:Update", this);
messageManager.addMessageListener("FormAssist:AutoComplete", this);
document.getElementById("tabs").addEventListener("TabSelect", this, true);
document.getElementById("browsers").addEventListener("URLChanged", this, true);
},
receiveMessage: function(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "FormAssist:Update":
let bv = Browser._browserView;
let visible = bv.getVisibleRect();
let caretRect = bv.browserToViewportRect(Rect.fromRect(json.caretRect));
let [deltaX, deltaY] = this._getOffsetForCaret(caretRect, visible);
if (deltaX != 0 || deltaY != 0) {
Browser.contentScrollboxScroller.scrollBy(deltaX, deltaY);
bv.onAfterVisibleMove();
}
break;
case "FormAssist:Show":
json.showNavigation ? FormHelper.open(new FormNavigator(json))
: SelectHelper.show(new FormWrapper(json.current));
break;
case "FormAssist:AutoComplete":
let current = json.current;
if (current.canAutocomplete) {
FormHelper.updateAutocompleteFor(current);
}
break;
}
},
handleEvent: function(aEvent) {
if (aEvent.type == "TabSelect" || aEvent.type == "URLChanged")
FormHelper.close();
Browser._browserView.setZoomLevel(restore.zoom);
Browser.contentScrollboxScroller.scrollTo(restore.contentScrollOffset.x, restore.contentScrollOffset.y);
Browser.pageScrollboxScroller.scrollTo(restore.pageScrollOffset.x, restore.pageScrollOffset.y);
},
_getOffsetForCaret: function formHelper_getOffsetForCaret(aCaretRect, aRect) {
@ -1695,120 +1683,36 @@ var FormMessageReceiver = {
}
};
function FormNavigator(navObject) {
this._navObject = navObject;
this._current = new FormWrapper(navObject.current);
}
FormNavigator.prototype = {
hasPrevious: function() {
return this._navObject.hasPrevious;
},
hasNext: function() {
return this._navObject.hasNext;
},
getCurrent: function() {
return this._current;
},
endSession: function endSession() {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Close", { });
},
goToPrevious: function goToPrevious() {
try {
let fl = getBrowser().QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
fl.activateRemoteFrame();
}
catch(e) {}
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Previous", { });
},
goToNext: function goToNext() {
try {
let fl = getBrowser().QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
fl.activateRemoteFrame();
}
catch(e) {}
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:Next", { });
}
};
function FormWrapper(aElementObject) {
this.element = aElementObject;
this._rect = Rect.fromRect(aElementObject.rect);
}
FormWrapper.prototype = {
hasChoices: function() {
return this.element.choiceData != null;
},
choiceSelect: function(aIndex, aSelected, aClearAll) {
let json = {
index: aIndex,
selected: aSelected,
clearAll: aClearAll
};
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceSelect", json);
},
choiceChange: function() {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceChange", { });
},
getChoiceData: function() {
return this.element.choiceData;
},
canAutocomplete: function() {
return this.element.canAutocomplete;
},
autocomplete: function(aValue) {
Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:AutoComplete", { value: aValue });
},
getRect: function() {
return this._rect;
}
};
/**
* SelectHelper: Provides an interface for making a choice in a list.
* SelectHelperUI: Provides an interface for making a choice in a list.
* Supports simultaneous selection of choices and group headers.
* Needs a BasicWrapper for handling selected element.
*/
var SelectHelper = {
var SelectHelperUI = {
_list: null,
_selectedIndexes: null,
_navigator: null,
get _panel() {
delete this._panel;
return this._panel = document.getElementById("select-container");
},
show: function(wrapper) {
let choiceData = wrapper.getChoiceData();
this._wrapper = wrapper;
this._choiceData = choiceData;
show: function(aList) {
this._list = aList;
this._selectedIndexes = this._getSelectedIndexes(choiceData);
this._list = document.getElementById("select-list");
this._list.setAttribute("multiple", choiceData.multiple ? "true" : "false");
this._container = document.getElementById("select-list");
this._container.setAttribute("multiple", aList.multiple ? "true" : "false");
this._selectedIndexes = this._getSelectedIndexes();
let firstSelected = null;
let choices = choiceData.choices;
let choices = aList.choices;
for (let i = 0; i < choices.length; i++) {
let choice = choices[i];
if (choice.group) {
let group = document.createElement("option");
group.setAttribute("label", choice.text);
this._list.appendChild(group);
this._container.appendChild(group);
group.className = "optgroup";
} else {
let item = document.createElement("option");
@ -1817,7 +1721,7 @@ var SelectHelper = {
item.choiceIndex = i;
if (choice.inGroup)
item.className = "in-optgroup";
this._list.appendChild(item);
this._container.appendChild(item);
if (choice.selected) {
item.setAttribute("selected", "true");
firstSelected = firstSelected || item;
@ -1832,7 +1736,7 @@ var SelectHelper = {
this._scrollElementIntoView(firstSelected);
this._list.addEventListener("click", this, false);
this._container.addEventListener("click", this, false);
},
dock: function dock(aContainer) {
@ -1850,16 +1754,15 @@ var SelectHelper = {
reset: function() {
this._updateControl();
let empty = this._list.cloneNode(false);
this._list.parentNode.replaceChild(empty, this._list);
this._list = empty;
this._wrapper = null;
this._choiceData = null;
let empty = this._container.cloneNode(false);
this._container.parentNode.replaceChild(empty, this._container);
this._container = empty;
this._list = null;
this._selectedIndexes = null;
},
hide: function() {
this._list.removeEventListener("click", this, false);
this._container.removeEventListener("click", this, false);
this._panel.hidden = true;
if (this._docked)
@ -1871,7 +1774,7 @@ var SelectHelper = {
},
unselectAll: function() {
let choices = this._choiceData.choices;
let choices = this._list.choices;
this._forEachOption(function(aItem, aIndex) {
aItem.selected = false;
choices[aIndex].selected = false;
@ -1879,9 +1782,9 @@ var SelectHelper = {
},
selectByIndex: function(aIndex) {
let choices = this._choiceData.choices;
for (let i = 0; i < this._list.childNodes.length; i++) {
let option = this._list.childNodes[i];
let choices = this._list.choices;
for (let i = 0; i < this._container.childNodes.length; i++) {
let option = this._container.childNodes[i];
if (option.optionIndex == aIndex) {
option.selected = true;
this._choices[i].selected = true;
@ -1891,9 +1794,9 @@ var SelectHelper = {
}
},
_getSelectedIndexes: function(choiceData) {
_getSelectedIndexes: function() {
let indexes = [];
let choices = choiceData.choices;
let choices = this._list.choices;
let choiceLength = choices.length;
for (let i = 0; i < choiceLength; i++) {
let choice = choices[i];
@ -1918,9 +1821,9 @@ var SelectHelper = {
if (index == -1)
return;
let scrollBoxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
let scrollBoxObject = this._container.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
let itemHeight = aElement.getBoundingClientRect().height;
let visibleItemsCount = this._list.boxObject.height / itemHeight;
let visibleItemsCount = this._container.boxObject.height / itemHeight;
if ((index + 1) > visibleItemsCount) {
let delta = Math.ceil(visibleItemsCount / 2);
scrollBoxObject.scrollTo(0, ((index + 1) - delta) * itemHeight);
@ -1931,7 +1834,7 @@ var SelectHelper = {
},
_forEachOption: function(aCallback) {
let children = this._list.children;
let children = this._container.children;
for (let i = 0; i < children.length; i++) {
let item = children[i];
if (!item.hasOwnProperty("optionIndex"))
@ -1941,7 +1844,7 @@ var SelectHelper = {
},
_updateControl: function() {
let currentSelectedIndexes = this._getSelectedIndexes(this._choiceData);
let currentSelectedIndexes = this._getSelectedIndexes();
let isIdentical = currentSelectedIndexes.length == this._selectedIndexes.length;
if (isIdentical) {
@ -1953,8 +1856,11 @@ var SelectHelper = {
}
}
if (!isIdentical)
this._wrapper.choiceChange();
if (isIdentical)
return;
this._list.changeCallback ? this._list.changeCallback()
: Browser.selectedBrowser.messageManager.sendAsyncMessage("FormAssist:ChoiceChange", { });
},
handleEvent: function(aEvent) {
@ -1962,23 +1868,35 @@ var SelectHelper = {
case "click":
let item = aEvent.target;
if (item && item.hasOwnProperty("optionIndex")) {
if (this._choiceData.multiple) {
if (this._list.multiple) {
// Toggle the item state
item.selected = !item.selected;
this._choiceData.choices[item.choiceIndex].selected = item.selected;
this._wrapper.choiceSelect(item.optionIndex, item.selected, false);
}
else {
this.unselectAll();
// Select the new one and update the control
item.selected = true;
this._choiceData.choices[item.choiceIndex].selected = true;
this._wrapper.choiceSelect(item.optionIndex, 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);
}
};

View File

@ -147,9 +147,9 @@
<command id="cmd_selectAll" label="&selectAll.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- forms navigation -->
<command id="cmd_formPrevious" oncommand="FormHelper.goToPrevious();"/>
<command id="cmd_formNext" oncommand="FormHelper.goToNext();"/>
<command id="cmd_formClose" oncommand="FormHelper.close();"/>
<command id="cmd_formPrevious" oncommand="FormHelperUI.goToPrevious();"/>
<command id="cmd_formNext" oncommand="FormHelperUI.goToNext();"/>
<command id="cmd_formClose" oncommand="FormHelperUI.hide();"/>
</commandset>
<keyset id="mainKeyset">
@ -270,7 +270,7 @@
<!-- popup for form helper -->
<vbox id="form-helper-container" hidden="true" class="window-width" top="0" pack="end">
<arrowscrollbox id="form-helper-autofill" collapsed="true" align="center" flex="1" orient="horizontal"
onclick="FormHelper.doAutoFill(event.target);"/>
onclick="FormHelperUI.doAutoComplete(event.target);"/>
<hbox id="form-buttons" class="panel-dark" pack="center">
<button id="form-helper-previous" class="button-dark" label="&formHelper.previous;" command="cmd_formPrevious"/>
<button id="form-helper-next" class="button-dark" label="&formHelper.next;" command="cmd_formNext"/>
@ -486,7 +486,7 @@
<vbox id="select-container-inner" class="dialog-dark" flex="1">
<scrollbox id="select-list" flex="1" orient="vertical"/>
<hbox id="select-buttons" pack="center">
<button id="select-buttons-done" class="button-dark" label="&formHelper.done;" oncommand="SelectHelper.hide();"/>
<button id="select-buttons-done" class="button-dark" label="&formHelper.done;" oncommand="SelectHelperUI.hide();"/>
</hbox>
</vbox>
<spacer flex="1000"/>

View File

@ -62,11 +62,11 @@ function FormAssistant() {
addMessageListener("FormAssist:ChoiceSelect", this);
addMessageListener("FormAssist:ChoiceChange", this);
addMessageListener("FormAssist:AutoComplete", this);
addEventListener("keyup", this, false);
};
FormAssistant.prototype = {
_enabled: false,
open: function(aElement) {
if (!aElement)
return false;
@ -92,24 +92,14 @@ FormAssistant.prototype = {
if (!this.getCurrent())
return false;
addEventListener("keyup", this, false);
sendAsyncMessage("FormAssist:Show", this.getJSON());
sendSyncMessage("FormAssist:Show", this.getJSON());
return true;
},
close: function() {
removeEventListener("keyup", this, false);
sendAsyncMessage("FormAssist:Hide", { });
},
receiveMessage: function receiveMessage(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "FormAssist:Close":
this.close();
break;
case "FormAssist:Previous":
this.goToPrevious();
sendAsyncMessage("FormAssist:Show", this.getJSON());
@ -163,6 +153,9 @@ FormAssistant.prototype = {
},
handleEvent: function formHelperHandleEvent(aEvent) {
if (!this._enabled)
return;
let currentWrapper = this.getCurrent();
let currentElement = currentWrapper.element;
@ -265,10 +258,9 @@ FormAssistant.prototype = {
getJSON: function() {
return {
hasNext: !!this.getNext(),
hasPrevious: !!this.getPrevious(),
current: this.getCurrent().getJSON(),
showNavigation: this._enabled
hasPrevious: !!this.getPrevious(),
hasNext: !!this.getNext()
};
},
@ -465,7 +457,7 @@ BasicWrapper.prototype = {
// Build up a flat JSON array of the choices. In HTML, it's possible for select element choices
// to be under a group header (but not recursively). We distinguish between headers and entries
// using the boolean "choiceData.group".
// using the boolean "choices.group".
// XXX If possible, this would be a great candidate for tracing.
let children = wrapper.getChildren();
for (let i = 0; i < children.length; i++) {
@ -507,7 +499,7 @@ BasicWrapper.prototype = {
value: this.element.value,
maxLength: this.element.maxLength,
canAutocomplete: this.canAutocomplete(),
choiceData: this.getChoiceData(),
choices: this.getChoiceData(),
navigable: this.canNavigateTo(),
assistable: this.canAssist(),
rect: this.getRect(),