|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict"; |
|
5 |
|
6 var SelectHelper = { |
|
7 _uiBusy: false, |
|
8 |
|
9 handleEvent: function(aEvent) { |
|
10 this.handleClick(aEvent.target); |
|
11 }, |
|
12 |
|
13 handleClick: function(aTarget) { |
|
14 // if we're busy looking at a select we want to eat any clicks that |
|
15 // come to us, but not to process them |
|
16 if (this._uiBusy || !this._isMenu(aTarget) || aTarget.disabled) |
|
17 return; |
|
18 |
|
19 this._uiBusy = true; |
|
20 this.show(aTarget); |
|
21 this._uiBusy = false; |
|
22 }, |
|
23 |
|
24 show: function(aElement) { |
|
25 let list = this.getListForElement(aElement); |
|
26 |
|
27 let p = new Prompt({ |
|
28 window: aElement.contentDocument |
|
29 }); |
|
30 |
|
31 if (aElement.multiple) { |
|
32 p.addButton({ |
|
33 label: Strings.browser.GetStringFromName("selectHelper.closeMultipleSelectDialog") |
|
34 }).setMultiChoiceItems(list); |
|
35 } else { |
|
36 p.setSingleChoiceItems(list); |
|
37 } |
|
38 |
|
39 p.show((function(data) { |
|
40 let selected = data.list; |
|
41 |
|
42 if (aElement instanceof Ci.nsIDOMXULMenuListElement) { |
|
43 if (aElement.selectedIndex != selected[0]) { |
|
44 aElement.selectedIndex = selected[0]; |
|
45 this.fireOnCommand(aElement); |
|
46 } |
|
47 } else if (aElement instanceof HTMLSelectElement) { |
|
48 let changed = false; |
|
49 let i = 0; |
|
50 this.forOptions(aElement, function(aNode) { |
|
51 if (aNode.selected && selected.indexOf(i) == -1) { |
|
52 changed = true; |
|
53 aNode.selected = false; |
|
54 } else if (!aNode.selected && selected.indexOf(i) != -1) { |
|
55 changed = true; |
|
56 aNode.selected = true; |
|
57 } |
|
58 i++; |
|
59 }); |
|
60 |
|
61 if (changed) |
|
62 this.fireOnChange(aElement); |
|
63 } |
|
64 }).bind(this)); |
|
65 }, |
|
66 |
|
67 _isMenu: function(aElement) { |
|
68 return (aElement instanceof HTMLSelectElement || |
|
69 aElement instanceof Ci.nsIDOMXULMenuListElement); |
|
70 }, |
|
71 |
|
72 getListForElement: function(aElement) { |
|
73 let index = 0; |
|
74 let items = []; |
|
75 this.forOptions(aElement, function(aNode, aOptions, aParent) { |
|
76 let item = { |
|
77 label: aNode.text || aNode.label, |
|
78 header: aOptions.isGroup, |
|
79 disabled: aNode.disabled, |
|
80 id: index, |
|
81 selected: aNode.selected |
|
82 } |
|
83 |
|
84 if (aParent) { |
|
85 item.child = true; |
|
86 item.disabled = item.disabled || aParent.disabled; |
|
87 } |
|
88 items.push(item); |
|
89 |
|
90 index++; |
|
91 }); |
|
92 return items; |
|
93 }, |
|
94 |
|
95 forOptions: function(aElement, aFunction, aParent = null) { |
|
96 let element = aElement; |
|
97 if (aElement instanceof Ci.nsIDOMXULMenuListElement) |
|
98 element = aElement.menupopup; |
|
99 let children = element.children; |
|
100 let numChildren = children.length; |
|
101 |
|
102 // if there are no children in this select, we add a dummy row so that at least something appears |
|
103 if (numChildren == 0) |
|
104 aFunction.call(this, { label: "" }, { isGroup: false }, aParent); |
|
105 |
|
106 for (let i = 0; i < numChildren; i++) { |
|
107 let child = children[i]; |
|
108 if (child instanceof HTMLOptionElement || |
|
109 child instanceof Ci.nsIDOMXULSelectControlItemElement) { |
|
110 aFunction.call(this, child, { isGroup: false }, aParent); |
|
111 } else if (child instanceof HTMLOptGroupElement) { |
|
112 aFunction.call(this, child, { isGroup: true }); |
|
113 this.forOptions(child, aFunction, child); |
|
114 |
|
115 } |
|
116 } |
|
117 }, |
|
118 |
|
119 fireOnChange: function(aElement) { |
|
120 let evt = aElement.ownerDocument.createEvent("Events"); |
|
121 evt.initEvent("change", true, true, aElement.defaultView, 0, |
|
122 false, false, |
|
123 false, false, null); |
|
124 setTimeout(function() { |
|
125 aElement.dispatchEvent(evt); |
|
126 }, 0); |
|
127 }, |
|
128 |
|
129 fireOnCommand: function(aElement) { |
|
130 let evt = aElement.ownerDocument.createEvent("XULCommandEvent"); |
|
131 evt.initCommandEvent("command", true, true, aElement.defaultView, 0, |
|
132 false, false, |
|
133 false, false, null); |
|
134 setTimeout(function() { |
|
135 aElement.dispatchEvent(evt); |
|
136 }, 0); |
|
137 } |
|
138 }; |