Chromium Code Reviews| 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 |