michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: "use strict"; michael@0: michael@0: var SelectHelper = { michael@0: _uiBusy: false, michael@0: michael@0: handleEvent: function(aEvent) { michael@0: this.handleClick(aEvent.target); michael@0: }, michael@0: michael@0: handleClick: function(aTarget) { michael@0: // if we're busy looking at a select we want to eat any clicks that michael@0: // come to us, but not to process them michael@0: if (this._uiBusy || !this._isMenu(aTarget) || aTarget.disabled) michael@0: return; michael@0: michael@0: this._uiBusy = true; michael@0: this.show(aTarget); michael@0: this._uiBusy = false; michael@0: }, michael@0: michael@0: show: function(aElement) { michael@0: let list = this.getListForElement(aElement); michael@0: michael@0: let p = new Prompt({ michael@0: window: aElement.contentDocument michael@0: }); michael@0: michael@0: if (aElement.multiple) { michael@0: p.addButton({ michael@0: label: Strings.browser.GetStringFromName("selectHelper.closeMultipleSelectDialog") michael@0: }).setMultiChoiceItems(list); michael@0: } else { michael@0: p.setSingleChoiceItems(list); michael@0: } michael@0: michael@0: p.show((function(data) { michael@0: let selected = data.list; michael@0: michael@0: if (aElement instanceof Ci.nsIDOMXULMenuListElement) { michael@0: if (aElement.selectedIndex != selected[0]) { michael@0: aElement.selectedIndex = selected[0]; michael@0: this.fireOnCommand(aElement); michael@0: } michael@0: } else if (aElement instanceof HTMLSelectElement) { michael@0: let changed = false; michael@0: let i = 0; michael@0: this.forOptions(aElement, function(aNode) { michael@0: if (aNode.selected && selected.indexOf(i) == -1) { michael@0: changed = true; michael@0: aNode.selected = false; michael@0: } else if (!aNode.selected && selected.indexOf(i) != -1) { michael@0: changed = true; michael@0: aNode.selected = true; michael@0: } michael@0: i++; michael@0: }); michael@0: michael@0: if (changed) michael@0: this.fireOnChange(aElement); michael@0: } michael@0: }).bind(this)); michael@0: }, michael@0: michael@0: _isMenu: function(aElement) { michael@0: return (aElement instanceof HTMLSelectElement || michael@0: aElement instanceof Ci.nsIDOMXULMenuListElement); michael@0: }, michael@0: michael@0: getListForElement: function(aElement) { michael@0: let index = 0; michael@0: let items = []; michael@0: this.forOptions(aElement, function(aNode, aOptions, aParent) { michael@0: let item = { michael@0: label: aNode.text || aNode.label, michael@0: header: aOptions.isGroup, michael@0: disabled: aNode.disabled, michael@0: id: index, michael@0: selected: aNode.selected michael@0: } michael@0: michael@0: if (aParent) { michael@0: item.child = true; michael@0: item.disabled = item.disabled || aParent.disabled; michael@0: } michael@0: items.push(item); michael@0: michael@0: index++; michael@0: }); michael@0: return items; michael@0: }, michael@0: michael@0: forOptions: function(aElement, aFunction, aParent = null) { michael@0: let element = aElement; michael@0: if (aElement instanceof Ci.nsIDOMXULMenuListElement) michael@0: element = aElement.menupopup; michael@0: let children = element.children; michael@0: let numChildren = children.length; michael@0: michael@0: // if there are no children in this select, we add a dummy row so that at least something appears michael@0: if (numChildren == 0) michael@0: aFunction.call(this, { label: "" }, { isGroup: false }, aParent); michael@0: michael@0: for (let i = 0; i < numChildren; i++) { michael@0: let child = children[i]; michael@0: if (child instanceof HTMLOptionElement || michael@0: child instanceof Ci.nsIDOMXULSelectControlItemElement) { michael@0: aFunction.call(this, child, { isGroup: false }, aParent); michael@0: } else if (child instanceof HTMLOptGroupElement) { michael@0: aFunction.call(this, child, { isGroup: true }); michael@0: this.forOptions(child, aFunction, child); michael@0: michael@0: } michael@0: } michael@0: }, michael@0: michael@0: fireOnChange: function(aElement) { michael@0: let evt = aElement.ownerDocument.createEvent("Events"); michael@0: evt.initEvent("change", true, true, aElement.defaultView, 0, michael@0: false, false, michael@0: false, false, null); michael@0: setTimeout(function() { michael@0: aElement.dispatchEvent(evt); michael@0: }, 0); michael@0: }, michael@0: michael@0: fireOnCommand: function(aElement) { michael@0: let evt = aElement.ownerDocument.createEvent("XULCommandEvent"); michael@0: evt.initCommandEvent("command", true, true, aElement.defaultView, 0, michael@0: false, false, michael@0: false, false, null); michael@0: setTimeout(function() { michael@0: aElement.dispatchEvent(evt); michael@0: }, 0); michael@0: } michael@0: };