OLD | NEW |
---|---|
(Empty) | |
1 "use strict"; | |
2 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
3 // Use of this source code is governed by a BSD-style license that can be | |
4 // found in the LICENSE file. | |
5 | |
6 var global = { | |
7 argumentsReceived: false, | |
8 params: null, | |
9 picker: null | |
10 }; | |
11 | |
12 /** | |
13 * @param {Event} event | |
14 */ | |
15 function handleMessage(event) { | |
16 window.removeEventListener("message", handleMessage, false); | |
17 initialize(JSON.parse(event.data)); | |
18 global.argumentsReceived = true; | |
19 } | |
20 | |
21 /** | |
22 * @param {!Object} args | |
23 */ | |
24 function initialize(args) { | |
25 global.params = args; | |
26 var main = $("main"); | |
27 main.innerHTML = ""; | |
28 global.picker = new ListPicker(main, args); | |
29 } | |
30 | |
31 function handleArgumentsTimeout() { | |
32 if (global.argumentsReceived) | |
33 return; | |
34 var args = { | |
35 }; | |
36 initialize(args); | |
tkent
2014/12/16 05:42:39
initialize({});
keishi
2014/12/16 12:21:03
Done.
| |
37 } | |
38 | |
39 /** | |
40 * @constructor | |
41 * @param {!Element} element | |
42 * @param {!Object} config | |
43 */ | |
44 function ListPicker(element, config) { | |
45 Picker.call(this, element, config); | |
46 this._selectElement = createElement("select"); | |
47 this._element.appendChild(this._selectElement); | |
48 this._layout(); | |
49 this._selectElement.focus(); | |
50 this._selectElement.addEventListener("mouseover", this._handleMouseOver.bind (this), false); | |
51 this._selectElement.addEventListener("mouseup", this._handleMouseUp.bind(thi s), false); | |
52 this._selectElement.addEventListener("keydown", this._handleKeyDown.bind(thi s), false); | |
53 this._selectElement.addEventListener("input", this._handleInput.bind(this), false); | |
54 window.addEventListener("message", this._handleWindowMessage.bind(this), fal se); | |
55 window.addEventListener("mousemove", this._handleWindowMouseMove.bind(this), false); | |
56 window.addEventListener("mousemove", this._handleWindowMouseMove.bind(this), false); | |
57 this.lastMousePositionX = Infinity; | |
58 this.lastMousePositionY = Infinity; | |
59 | |
60 // Not sure why but we need to delay this call so that offsetHeight is | |
61 // accurate. We wait for the window to resize to work around an issue | |
62 // of immediate resize requests getting mixed up. | |
63 this._handleWindowDidHideBound = this._handleWindowDidHide.bind(this); | |
64 window.addEventListener("didHide", this._handleWindowDidHideBound, false); | |
65 hideWindow(); | |
66 } | |
67 ListPicker.prototype = Object.create(Picker.prototype); | |
68 | |
69 ListPicker.prototype._handleWindowDidHide = function() { | |
70 this._fixWindowSize(); | |
71 var selectedOption = this._selectElement.options[this._selectElement.selecte dIndex]; | |
72 selectedOption.scrollIntoView(false); | |
73 window.removeEventListener("didHide", this._handleWindowDidHideBound, false) ; | |
74 }; | |
75 | |
76 ListPicker.prototype._handleWindowMessage = function(event) { | |
77 eval(event.data); | |
78 if (window.updateData.type === "update") | |
79 this._update(window.updateData); | |
80 delete window.updateData; | |
81 }; | |
82 | |
83 ListPicker.prototype._handleWindowMouseMove = function (event) { | |
84 this.lastMousePositionX = event.clientX; | |
85 this.lastMousePositionY = event.clientY; | |
86 }; | |
87 | |
88 ListPicker.prototype._handleMouseOver = function(event) { | |
89 if (event.toElement.tagName !== "OPTION") | |
90 return; | |
91 var savedScrollTop = this._selectElement.scrollTop; | |
92 event.toElement.selected = true; | |
93 this._selectElement.scrollTop = savedScrollTop; | |
94 }; | |
95 | |
96 ListPicker.prototype._handleMouseUp = function(event) { | |
97 if (event.target.tagName !== "OPTION") | |
98 return; | |
99 window.pagePopupController.setValueAndClosePopup(0, this._selectElement.valu e); | |
100 }; | |
101 | |
102 ListPicker.prototype._handleInput = function(event) { | |
103 window.pagePopupController.setValue(this._selectElement.value); | |
104 }; | |
105 | |
106 ListPicker.prototype._handleKeyDown = function(event) { | |
107 var key = event.keyIdentifier; | |
108 if (key === "U+001B") { // ESC | |
109 window.pagePopupController.closePopup(); | |
110 event.preventDefault(); | |
111 } else if (key === "Enter") { | |
112 window.pagePopupController.setValueAndClosePopup(0, this._selectElement. value); | |
113 event.preventDefault(); | |
114 } else if (event.altKey && (key === "Down" || key === "Up")) { | |
115 // FIXME: We need to add a delay here because, if we do it immediately | |
tkent
2014/12/16 05:42:39
Is it possible to fix this FIXME? If not, let's r
keishi
2014/12/16 12:21:03
No. Removed.
| |
116 // the key press event will be handled by HTMLSelectElement and this | |
117 // popup will be reopened. | |
118 setTimeout(function () { | |
119 window.pagePopupController.closePopup(); | |
120 }, 0); | |
121 event.preventDefault(); | |
122 } | |
123 }; | |
124 | |
125 ListPicker.prototype._fixWindowSize = function() { | |
126 this._selectElement.style.height = ""; | |
127 this._selectElement.size = 20; | |
128 var maxHeight = this._selectElement.offsetHeight; | |
129 this._selectElement.style.height = "0"; | |
130 var heightOutsideOfContent = this._selectElement.offsetHeight - this._select Element.clientHeight; | |
131 var desiredWindowHeight = this._selectElement.scrollHeight + heightOutsideOf Content; | |
132 this._selectElement.style.height = desiredWindowHeight + "px"; | |
133 // FIXME: scrollHeight returns floored value so we needed this check. | |
tkent
2014/12/16 05:42:39
Ditto.
keishi
2014/12/16 12:21:03
Removed.
| |
134 if (this._hasVerticalScrollbar()) | |
135 desiredWindowHeight += 1; | |
136 if (desiredWindowHeight > maxHeight) | |
137 desiredWindowHeight = maxHeight; | |
138 var desiredWindowWidth = Math.max(this._config.anchorRectInScreen.width, thi s._selectElement.offsetWidth); | |
139 var windowRect = adjustWindowRect(desiredWindowWidth, desiredWindowHeight, t his._selectElement.offsetWidth, 0); | |
140 this._selectElement.style.width = windowRect.width + "px"; | |
141 this._selectElement.style.height = windowRect.height + "px"; | |
142 this._element.style.height = windowRect.height + "px"; | |
143 setWindowRect(windowRect); | |
144 }; | |
145 | |
146 ListPicker.prototype._hasVerticalScrollbar = function() { | |
147 return this._selectElement.scrollWidth > this._selectElement.clientWidth; | |
148 }; | |
149 | |
150 ListPicker.prototype._listItemCount = function() { | |
151 return this._selectElement.querySelectorAll("option,optgroup,hr").length; | |
152 }; | |
153 | |
154 ListPicker.prototype._layout = function() { | |
155 for (var i = 0; i < this._config.children.length; ++i) { | |
156 this._selectElement.appendChild(this._createItemElement(this._config.chi ldren[i])); | |
157 } | |
158 this._selectElement.value = this._config.selectedIndex; | |
159 }; | |
160 | |
161 ListPicker.prototype._update = function(data) { | |
162 this._config.children = data.children; | |
163 var oldValue = this._selectElement.value; | |
164 while (this._selectElement.firstChild) { | |
165 this._selectElement.removeChild(this._selectElement.firstChild); | |
166 } | |
167 for (var i = 0; i < this._config.children.length; ++i) { | |
168 this._selectElement.appendChild(this._createItemElement(this._config.chi ldren[i])); | |
169 } | |
170 this._selectElement.value = this._config.selectedIndex; | |
171 var elementUnderMouse = document.elementFromPoint(this.lastMousePositionX, t his.lastMousePositionY); | |
172 var optionUnderMouse = elementUnderMouse && elementUnderMouse.closest("optio n"); | |
173 if (optionUnderMouse) | |
174 optionUnderMouse.selected = true; | |
175 else | |
176 this._selectElement.value = oldValue; | |
177 this._fixWindowSize(); | |
178 }; | |
179 | |
180 ListPicker.prototype._createItemElement = function(config) { | |
181 if (config.type === "option") { | |
182 var option = createElement("option"); | |
183 option.appendChild(document.createTextNode(config.label)); | |
184 option.value = config.value; | |
185 option.title = config.title; | |
186 option.disabled = config.disabled; | |
187 option.setAttribute("aria-label", config.ariaLabel); | |
188 this._applyItemStyle(option, config.style); | |
189 this._selectElement.appendChild(option); | |
190 return option; | |
191 } else if (config.type === "optgroup") { | |
192 var optgroup = createElement("optgroup"); | |
193 optgroup.label = config.label; | |
194 optgroup.title = config.title; | |
195 optgroup.disabled = config.disabled; | |
196 optgroup.setAttribute("aria-label", config.ariaLabel); | |
197 this._applyItemStyle(optgroup, config.style); | |
198 for (var i = 0; i < config.children.length; ++i) { | |
199 optgroup.appendChild(this._createItemElement(config.children[i])); | |
200 } | |
201 this._selectElement.appendChild(optgroup); | |
202 return optgroup; | |
203 } else if (config.type === "separator") { | |
204 var hr = createElement("hr"); | |
205 hr.title = config.title; | |
206 hr.disabled = config.disabled; | |
207 hr.setAttribute("aria-label", config.ariaLabel); | |
208 this._applyItemStyle(hr, config.style); | |
209 return hr; | |
210 } | |
211 }; | |
212 | |
213 ListPicker.prototype._applyItemStyle = function(element, styleConfig) { | |
214 element.style.color = styleConfig.color; | |
215 element.style.backgroundColor = styleConfig.backgroundColor; | |
216 element.style.fontSize = styleConfig.fontSize + "px"; | |
217 element.style.fontWeight = styleConfig.fontWeight; | |
218 element.style.fontFamily = styleConfig.fontFamily.join(","); | |
219 element.style.visibility = styleConfig.visibility; | |
220 element.style.display = styleConfig.display; | |
221 element.style.direction = styleConfig.direction; | |
222 element.style.unicodeBidi = styleConfig.unicodeBidi; | |
223 }; | |
224 | |
225 if (window.dialogArguments) { | |
226 initialize(dialogArguments); | |
227 } else { | |
228 window.addEventListener("message", handleMessage, false); | |
229 window.setTimeout(handleArgumentsTimeout, 1000); | |
230 } | |
OLD | NEW |