summaryrefslogtreecommitdiffstats
path: root/mobile/android/chrome/content/SelectHelper.js
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/chrome/content/SelectHelper.js')
-rw-r--r--mobile/android/chrome/content/SelectHelper.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/mobile/android/chrome/content/SelectHelper.js b/mobile/android/chrome/content/SelectHelper.js
new file mode 100644
index 000000000..41d0193d4
--- /dev/null
+++ b/mobile/android/chrome/content/SelectHelper.js
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var SelectHelper = {
+ _uiBusy: false,
+
+ handleEvent: function(event) {
+ this.handleClick(event.target);
+ },
+
+ handleClick: function(target) {
+ // if we're busy looking at a select we want to eat any clicks that
+ // come to us, but not to process them
+ if (this._uiBusy || !this._isMenu(target) || this._isDisabledElement(target)) {
+ return;
+ }
+
+ this._uiBusy = true;
+ this.show(target);
+ this._uiBusy = false;
+ },
+
+ // This is a callback function to be provided to prompt.show(callBack).
+ // It will update which Option elements in a Select have been selected
+ // or unselected and fire the onChange event.
+ _promptCallBack: function(data, element) {
+ let selected = data.list;
+
+ if (element instanceof Ci.nsIDOMXULMenuListElement) {
+ if (element.selectedIndex != selected[0]) {
+ element.selectedIndex = selected[0];
+ this.fireOnCommand(element);
+ }
+ } else if (element instanceof HTMLSelectElement) {
+ let changed = false;
+ let i = 0; // The index for the element from `data.list` that we are currently examining.
+ this.forVisibleOptions(element, function(node) {
+ if (node.selected && selected.indexOf(i) == -1) {
+ changed = true;
+ node.selected = false;
+ } else if (!node.selected && selected.indexOf(i) != -1) {
+ changed = true;
+ node.selected = true;
+ }
+ i++;
+ });
+
+ if (changed) {
+ this.fireOnChange(element);
+ }
+ }
+ },
+
+ show: function(element) {
+ let list = this.getListForElement(element);
+ let p = new Prompt({
+ window: element.ownerDocument.defaultView
+ });
+
+ if (element.multiple) {
+ p.addButton({
+ label: Strings.browser.GetStringFromName("selectHelper.closeMultipleSelectDialog")
+ }).setMultiChoiceItems(list);
+ } else {
+ p.setSingleChoiceItems(list);
+ }
+
+ p.show((data) => {
+ this._promptCallBack(data,element)
+ });
+ },
+
+ _isMenu: function(element) {
+ return (element instanceof HTMLSelectElement || element instanceof Ci.nsIDOMXULMenuListElement);
+ },
+
+ // Return a list of Option elements within a Select excluding
+ // any that were not visible.
+ getListForElement: function(element) {
+ let index = 0;
+ let items = [];
+ this.forVisibleOptions(element, function(node, options,parent) {
+ let item = {
+ label: node.text || node.label,
+ header: options.isGroup,
+ disabled: node.disabled,
+ id: index,
+ selected: node.selected,
+ };
+
+ if (parent) {
+ item.child = true;
+ item.disabled = item.disabled || parent.disabled;
+ }
+ items.push(item);
+ index++;
+ });
+ return items;
+ },
+
+ // Apply a function to all visible Option elements in a Select
+ forVisibleOptions: function(element, aFunction, parent = null) {
+ if (element instanceof Ci.nsIDOMXULMenuListElement) {
+ element = element.menupopup;
+ }
+ let children = element.children;
+ let numChildren = children.length;
+
+
+ // if there are no children in this select, we add a dummy row so that at least something appears
+ if (numChildren == 0) {
+ aFunction.call(this, {label: ""}, {isGroup: false}, parent);
+ }
+
+ for (let i = 0; i < numChildren; i++) {
+ let child = children[i];
+ let style = window.getComputedStyle(child, null);
+ if (style.display !== "none") {
+ if (child instanceof HTMLOptionElement ||
+ child instanceof Ci.nsIDOMXULSelectControlItemElement) {
+ aFunction.call(this, child, {isGroup: false}, parent);
+ } else if (child instanceof HTMLOptGroupElement) {
+ aFunction.call(this, child, {isGroup: true});
+ this.forVisibleOptions(child, aFunction, child);
+ }
+ }
+ }
+ },
+
+ fireOnChange: function(element) {
+ let event = element.ownerDocument.createEvent("Events");
+ event.initEvent("change", true, true, element.defaultView, 0,
+ false, false, false, false, null);
+ setTimeout(function() {
+ element.dispatchEvent(event);
+ }, 0);
+ },
+
+ fireOnCommand: function(element) {
+ let event = element.ownerDocument.createEvent("XULCommandEvent");
+ event.initCommandEvent("command", true, true, element.defaultView, 0,
+ false, false, false, false, null);
+ setTimeout(function() {
+ element.dispatchEvent(event);
+ }, 0);
+ },
+
+ _isDisabledElement : function(element) {
+ let currentElement = element;
+ while (currentElement) {
+ // Must test with === in case a form has a field named "disabled". See bug 1263589.
+ if (currentElement.disabled === true) {
+ return true;
+ }
+ currentElement = currentElement.parentElement;
+ }
+ return false;
+ }
+};