Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(823)

Side by Side Diff: Source/web/resources/listPicker.js

Issue 1149153003: New SELECT Popup: Very slow to open a popup with many items. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: More optimization Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/web/PopupMenuImpl.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 "use strict"; 1 "use strict";
2 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file. 4 // found in the LICENSE file.
5 5
6 var global = { 6 var global = {
7 argumentsReceived: false, 7 argumentsReceived: false,
8 params: null, 8 params: null,
9 picker: null 9 picker: null
10 }; 10 };
(...skipping 25 matching lines...) Expand all
36 36
37 /** 37 /**
38 * @constructor 38 * @constructor
39 * @param {!Element} element 39 * @param {!Element} element
40 * @param {!Object} config 40 * @param {!Object} config
41 */ 41 */
42 function ListPicker(element, config) { 42 function ListPicker(element, config) {
43 Picker.call(this, element, config); 43 Picker.call(this, element, config);
44 window.pagePopupController.selectFontsFromOwnerDocument(document); 44 window.pagePopupController.selectFontsFromOwnerDocument(document);
45 this._selectElement = createElement("select"); 45 this._selectElement = createElement("select");
46 this._selectElement.size = 20;
46 this._element.appendChild(this._selectElement); 47 this._element.appendChild(this._selectElement);
47 this._layout(); 48 this._layout();
48 this._selectElement.focus();
49 this._selectElement.addEventListener("mouseup", this._handleMouseUp.bind(thi s), false); 49 this._selectElement.addEventListener("mouseup", this._handleMouseUp.bind(thi s), false);
50 this._selectElement.addEventListener("touchstart", this._handleTouchStart.bi nd(this), false); 50 this._selectElement.addEventListener("touchstart", this._handleTouchStart.bi nd(this), false);
51 this._selectElement.addEventListener("keydown", this._handleKeyDown.bind(thi s), false); 51 this._selectElement.addEventListener("keydown", this._handleKeyDown.bind(thi s), false);
52 this._selectElement.addEventListener("change", this._handleChange.bind(this) , false); 52 this._selectElement.addEventListener("change", this._handleChange.bind(this) , false);
53 window.addEventListener("message", this._handleWindowMessage.bind(this), fal se); 53 window.addEventListener("message", this._handleWindowMessage.bind(this), fal se);
54 window.addEventListener("mousemove", this._handleWindowMouseMove.bind(this), false); 54 window.addEventListener("mousemove", this._handleWindowMouseMove.bind(this), false);
55 window.addEventListener("touchmove", this._handleWindowTouchMove.bind(this), false); 55 window.addEventListener("touchmove", this._handleWindowTouchMove.bind(this), false);
56 window.addEventListener("touchend", this._handleWindowTouchEnd.bind(this), f alse); 56 window.addEventListener("touchend", this._handleWindowTouchEnd.bind(this), f alse);
57 this.lastMousePositionX = Infinity; 57 this.lastMousePositionX = Infinity;
58 this.lastMousePositionY = Infinity; 58 this.lastMousePositionY = Infinity;
59 this._selectionSetByMouseHover = false; 59 this._selectionSetByMouseHover = false;
60 60
61 this._trackingTouchId = null; 61 this._trackingTouchId = null;
62 62
63 this._handleWindowDidHide(); 63 this._handleWindowDidHide();
64 this._selectElement.focus();
65 this._selectElement.value = this._config.selectedIndex;
64 } 66 }
65 ListPicker.prototype = Object.create(Picker.prototype); 67 ListPicker.prototype = Object.create(Picker.prototype);
66 68
67 ListPicker.prototype._handleWindowDidHide = function() { 69 ListPicker.prototype._handleWindowDidHide = function() {
68 this._fixWindowSize(); 70 this._fixWindowSize();
69 var selectedOption = this._selectElement.options[this._selectElement.selecte dIndex]; 71 var selectedOption = this._selectElement.options[this._selectElement.selecte dIndex];
70 if (selectedOption) 72 if (selectedOption)
71 selectedOption.scrollIntoView(false); 73 selectedOption.scrollIntoView(false);
72 window.removeEventListener("didHide", this._handleWindowDidHideBound, false) ; 74 window.removeEventListener("didHide", this._handleWindowDidHideBound, false) ;
73 }; 75 };
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // to the owner element. We can handle most cases with the change 171 // to the owner element. We can handle most cases with the change
170 // event. But we need to call setValue even when the selection hasn't 172 // event. But we need to call setValue even when the selection hasn't
171 // changed. So we call it here too. setValue will be called twice for 173 // changed. So we call it here too. setValue will be called twice for
172 // some key presses but it won't matter. 174 // some key presses but it won't matter.
173 window.pagePopupController.setValue(this._selectElement.value); 175 window.pagePopupController.setValue(this._selectElement.value);
174 } 176 }
175 }; 177 };
176 178
177 ListPicker.prototype._fixWindowSize = function() { 179 ListPicker.prototype._fixWindowSize = function() {
178 this._selectElement.style.height = ""; 180 this._selectElement.style.height = "";
179 this._selectElement.size = 20;
180 var maxHeight = this._selectElement.offsetHeight; 181 var maxHeight = this._selectElement.offsetHeight;
181 this._selectElement.style.height = "0"; 182 // heightOutsideOfContent should be matched to border widths of the listbox
182 var heightOutsideOfContent = this._selectElement.offsetHeight - this._select Element.clientHeight; 183 // SELECT. See listPicker.css and html.css.
184 var heightOutsideOfContent = 2;
183 var noScrollHeight = Math.round(this._calculateScrollHeight() + heightOutsid eOfContent); 185 var noScrollHeight = Math.round(this._calculateScrollHeight() + heightOutsid eOfContent);
184 var desiredWindowHeight = noScrollHeight; 186 var desiredWindowHeight = noScrollHeight;
185 var desiredWindowWidth = this._selectElement.offsetWidth; 187 var desiredWindowWidth = this._selectElement.offsetWidth;
186 var expectingScrollbar = false; 188 var expectingScrollbar = false;
187 if (desiredWindowHeight > maxHeight) { 189 if (desiredWindowHeight > maxHeight) {
188 desiredWindowHeight = maxHeight; 190 desiredWindowHeight = maxHeight;
189 // Setting overflow to auto does not increase width for the scrollbar 191 // Setting overflow to auto does not increase width for the scrollbar
190 // so we need to do it manually. 192 // so we need to do it manually.
191 desiredWindowWidth += getScrollbarWidth(); 193 desiredWindowWidth += getScrollbarWidth();
192 expectingScrollbar = true; 194 expectingScrollbar = true;
(...skipping 29 matching lines...) Expand all
222 224
223 ListPicker.prototype._listItemCount = function() { 225 ListPicker.prototype._listItemCount = function() {
224 return this._selectElement.querySelectorAll("option,optgroup,hr").length; 226 return this._selectElement.querySelectorAll("option,optgroup,hr").length;
225 }; 227 };
226 228
227 ListPicker.prototype._layout = function() { 229 ListPicker.prototype._layout = function() {
228 if (this._config.isRTL) 230 if (this._config.isRTL)
229 this._element.classList.add("rtl"); 231 this._element.classList.add("rtl");
230 this._selectElement.style.backgroundColor = this._config.backgroundColor; 232 this._selectElement.style.backgroundColor = this._config.backgroundColor;
231 this._updateChildren(this._selectElement, this._config); 233 this._updateChildren(this._selectElement, this._config);
232 this._selectElement.value = this._config.selectedIndex;
233 }; 234 };
234 235
235 ListPicker.prototype._update = function() { 236 ListPicker.prototype._update = function() {
236 var scrollPosition = this._selectElement.scrollTop; 237 var scrollPosition = this._selectElement.scrollTop;
237 var oldValue = this._selectElement.value; 238 var oldValue = this._selectElement.value;
238 this._layout(); 239 this._layout();
240 this._selectElement.value = this._config.selectedIndex;
239 this._selectElement.scrollTop = scrollPosition; 241 this._selectElement.scrollTop = scrollPosition;
240 var optionUnderMouse = null; 242 var optionUnderMouse = null;
241 if (this._selectionSetByMouseHover) { 243 if (this._selectionSetByMouseHover) {
242 var elementUnderMouse = document.elementFromPoint(this.lastMousePosition X, this.lastMousePositionY); 244 var elementUnderMouse = document.elementFromPoint(this.lastMousePosition X, this.lastMousePositionY);
243 optionUnderMouse = elementUnderMouse && elementUnderMouse.closest("optio n"); 245 optionUnderMouse = elementUnderMouse && elementUnderMouse.closest("optio n");
244 } 246 }
245 if (optionUnderMouse) 247 if (optionUnderMouse)
246 optionUnderMouse.selected = true; 248 optionUnderMouse.selected = true;
247 else 249 else
248 this._selectElement.value = oldValue; 250 this._selectElement.value = oldValue;
249 this._selectElement.scrollTop = scrollPosition; 251 this._selectElement.scrollTop = scrollPosition;
250 this.dispatchEvent("didUpdate"); 252 this.dispatchEvent("didUpdate");
251 }; 253 };
252 254
253 /** 255 /**
254 * @param {!Element} parent Select element or optgroup element. 256 * @param {!Element} parent Select element or optgroup element.
255 * @param {!Object} config 257 * @param {!Object} config
256 */ 258 */
257 ListPicker.prototype._updateChildren = function(parent, config) { 259 ListPicker.prototype._updateChildren = function(parent, config) {
258 var outOfDateIndex = 0; 260 var outOfDateIndex = 0;
261 var fragment = null;
262 var inGroup = parent.tagName === "OPTGROUP";
259 for (var i = 0; i < config.children.length; ++i) { 263 for (var i = 0; i < config.children.length; ++i) {
260 var childConfig = config.children[i]; 264 var childConfig = config.children[i];
261 var item = this._findReusableItem(parent, childConfig, outOfDateIndex) | | this._createItemElement(childConfig); 265 var item = this._findReusableItem(parent, childConfig, outOfDateIndex) | | this._createItemElement(childConfig);
262 this._configureItem(item, childConfig, parent.tagName === "OPTGROUP"); 266 this._configureItem(item, childConfig, inGroup);
263 if (outOfDateIndex < parent.children.length) 267 if (outOfDateIndex < parent.children.length) {
264 parent.insertBefore(item, parent.children[outOfDateIndex]); 268 parent.insertBefore(item, parent.children[outOfDateIndex]);
265 else 269 } else {
266 parent.appendChild(item); 270 if (!fragment)
271 fragment = document.createDocumentFragment();
272 fragment.appendChild(item);
273 }
267 outOfDateIndex++; 274 outOfDateIndex++;
268 } 275 }
276 if (fragment) {
277 parent.appendChild(fragment);
278 return;
keishi 2015/05/26 06:41:25 When you change from <select><optgroup></optgroup>
279 }
269 var unused = parent.children.length - outOfDateIndex; 280 var unused = parent.children.length - outOfDateIndex;
270 for (var i = 0; i < unused; i++) { 281 for (var i = 0; i < unused; i++) {
271 parent.removeChild(parent.lastElementChild); 282 parent.removeChild(parent.lastElementChild);
272 } 283 }
273 }; 284 };
274 285
275 ListPicker.prototype._findReusableItem = function(parent, config, startIndex) { 286 ListPicker.prototype._findReusableItem = function(parent, config, startIndex) {
276 if (startIndex >= parent.children.length) 287 if (startIndex >= parent.children.length)
277 return null; 288 return null;
278 var tagName = "OPTION"; 289 var tagName = "OPTION";
(...skipping 15 matching lines...) Expand all
294 if (config.type === "option") 305 if (config.type === "option")
295 element = createElement("option"); 306 element = createElement("option");
296 else if (config.type === "optgroup") 307 else if (config.type === "optgroup")
297 element = createElement("optgroup"); 308 element = createElement("optgroup");
298 else if (config.type === "separator") 309 else if (config.type === "separator")
299 element = createElement("hr"); 310 element = createElement("hr");
300 return element; 311 return element;
301 }; 312 };
302 313
303 ListPicker.prototype._applyItemStyle = function(element, styleConfig) { 314 ListPicker.prototype._applyItemStyle = function(element, styleConfig) {
304 element.style.color = styleConfig.color; 315 if (!styleConfig)
305 element.style.backgroundColor = styleConfig.backgroundColor; 316 return;
306 element.style.fontSize = styleConfig.fontSize + "px"; 317 var style = element.style;
307 element.style.fontWeight = styleConfig.fontWeight; 318 style.visibility = styleConfig.visibility;
308 element.style.fontFamily = styleConfig.fontFamily.join(","); 319 style.display = styleConfig.display;
309 element.style.fontStyle = styleConfig.fontStyle; 320 style.direction = styleConfig.direction;
310 element.style.fontVariant = styleConfig.fontVariant; 321 style.unicodeBidi = styleConfig.unicodeBidi;
311 element.style.visibility = styleConfig.visibility; 322 if (!styleConfig.color)
312 element.style.display = styleConfig.display; 323 return;
313 element.style.direction = styleConfig.direction; 324 style.color = styleConfig.color;
314 element.style.unicodeBidi = styleConfig.unicodeBidi; 325 style.backgroundColor = styleConfig.backgroundColor;
326 style.fontSize = styleConfig.fontSize + "px";
327 style.fontWeight = styleConfig.fontWeight;
328 style.fontFamily = styleConfig.fontFamily.join(",");
329 style.fontStyle = styleConfig.fontStyle;
330 style.fontVariant = styleConfig.fontVariant;
315 }; 331 };
316 332
317 ListPicker.prototype._configureItem = function(element, config, inGroup) { 333 ListPicker.prototype._configureItem = function(element, config, inGroup) {
318 if (config.type === "option") { 334 if (config.type === "option") {
319 element.label = config.label; 335 element.label = config.label;
320 element.value = config.value; 336 element.value = config.value;
321 element.title = config.title; 337 element.title = config.title;
322 element.disabled = config.disabled; 338 element.disabled = config.disabled;
323 element.setAttribute("aria-label", config.ariaLabel); 339 element.setAttribute("aria-label", config.ariaLabel);
324 element.style.webkitPaddingStart = this._config.paddingStart + "px"; 340 element.style.webkitPaddingStart = this._config.paddingStart + "px";
(...skipping 21 matching lines...) Expand all
346 } 362 }
347 this._applyItemStyle(element, config.style); 363 this._applyItemStyle(element, config.style);
348 }; 364 };
349 365
350 if (window.dialogArguments) { 366 if (window.dialogArguments) {
351 initialize(dialogArguments); 367 initialize(dialogArguments);
352 } else { 368 } else {
353 window.addEventListener("message", handleMessage, false); 369 window.addEventListener("message", handleMessage, false);
354 window.setTimeout(handleArgumentsTimeout, 1000); 370 window.setTimeout(handleArgumentsTimeout, 1000);
355 } 371 }
OLDNEW
« no previous file with comments | « Source/web/PopupMenuImpl.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698