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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/quick_open/FilteredListWidget.js

Issue 2773583002: [DevTools] Introduce a sidebar with a drop-down
Patch Set: [DevTools] Introduce a sidebar with a drop-down Created 3 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
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 * Copyright (c) 2012 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 /** 6 /**
7 * @unrestricted 7 * @unrestricted
8 * @implements {UI.ListDelegate} 8 * @implements {UI.ListDelegate}
9 */ 9 */
10 QuickOpen.FilteredListWidget = class extends UI.VBox { 10 QuickOpen.FilteredListWidget = class extends UI.VBox {
11 /** 11 /**
12 * @param {?QuickOpen.FilteredListWidget.Provider} provider 12 * @param {?QuickOpen.FilteredListWidget.Provider} provider
13 * @param {!Array<string>=} promptHistory 13 * @param {!Array<string>=} promptHistory
14 * @param {function(string)=} queryChangedCallback 14 * @param {function(string)=} queryChangedCallback
15 */ 15 */
16 constructor(provider, promptHistory, queryChangedCallback) { 16 constructor(provider, promptHistory, queryChangedCallback) {
17 super(true); 17 super(true);
18 this._promptHistory = promptHistory || []; 18 this._promptHistory = promptHistory || [];
19 19
20 this.contentElement.classList.add('filtered-list-widget'); 20 this.contentElement.classList.add('filtered-list-widget');
21 this.contentElement.addEventListener('keydown', this._onKeyDown.bind(this), true); 21 this.contentElement.addEventListener('keydown', this._onKeyDown.bind(this), true);
22 this.registerRequiredCSS('quick_open/filteredListWidget.css'); 22 this.registerRequiredCSS('quick_open/filteredListWidget.css');
23 23
24 this._promptElement = this.contentElement.createChild('div', 'filtered-list- widget-input'); 24 var promptContainer = this.contentElement.createChild('div', 'filtered-list- widget-input-container');
25 this._iconContainer = promptContainer.createChild('div');
26 var container = promptContainer.createChild('div', 'filtered-list-widget-inp ut');
27 this._promptElement = container.createChild('div');
25 this._promptElement.setAttribute('spellcheck', 'false'); 28 this._promptElement.setAttribute('spellcheck', 'false');
26 this._promptElement.setAttribute('contenteditable', 'plaintext-only'); 29 this._promptElement.setAttribute('contenteditable', 'plaintext-only');
27 this._prompt = new UI.TextPrompt(); 30 this._prompt = new UI.TextPrompt();
28 this._prompt.initialize(() => Promise.resolve([])); 31 this._prompt.initialize(() => Promise.resolve([]));
29 var promptProxy = this._prompt.attach(this._promptElement); 32 var promptProxy = this._prompt.attach(this._promptElement);
30 promptProxy.addEventListener('input', this._onInput.bind(this), false); 33 promptProxy.addEventListener('input', this._onInput.bind(this), false);
31 promptProxy.classList.add('filtered-list-widget-prompt-element'); 34 promptProxy.classList.add('filtered-list-widget-prompt-element');
32 35
33 this._bottomElementsContainer = this.contentElement.createChild('div', 'vbox '); 36 this._bottomElementsContainer = this.contentElement.createChild('div', 'vbox ');
34 this._progressElement = this._bottomElementsContainer.createChild('div', 'fi ltered-list-widget-progress'); 37 this._progressElement = this._bottomElementsContainer.createChild('div', 'fi ltered-list-widget-progress');
35 this._progressBarElement = this._progressElement.createChild('div', 'filtere d-list-widget-progress-bar'); 38 this._progressBarElement = this._progressElement.createChild('div', 'filtere d-list-widget-progress-bar');
36 39
37 /** @type {!UI.ListControl<number>} */ 40 /** @type {!UI.ListControl<number>} */
38 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems); 41 this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems);
39 this._itemElementsContainer = this._list.element; 42 this._itemElementsContainer = this._list.element;
43 this._itemElementsContainer.addEventListener('mousemove', event => this._upd ateHover(event));
44 this._itemElementsContainer.addEventListener('mouseout', () => this._hover(n ull));
40 this._itemElementsContainer.classList.add('container'); 45 this._itemElementsContainer.classList.add('container');
41 this._bottomElementsContainer.appendChild(this._itemElementsContainer); 46 this._bottomElementsContainer.appendChild(this._itemElementsContainer);
42 this._itemElementsContainer.addEventListener('click', this._onClick.bind(thi s), false); 47 this._itemElementsContainer.addEventListener('click', this._onClick.bind(thi s), false);
43 48
44 this._notFoundElement = this._bottomElementsContainer.createChild('div', 'no t-found-text'); 49 this._notFoundElement = this._bottomElementsContainer.createChild('div', 'no t-found-text');
45 this._notFoundElement.classList.add('hidden'); 50 this._notFoundElement.classList.add('hidden');
46 51
47 this.setDefaultFocusedElement(this._promptElement); 52 this.setDefaultFocusedElement(this._promptElement);
48 53
49 this._prefix = ''; 54 this._prefix = '';
50 this._provider = provider; 55 this._provider = provider;
51 this._queryChangedCallback = queryChangedCallback; 56 this._queryChangedCallback = queryChangedCallback;
57
58 /** @type {?number} */
59 this._initialSelectedItem = null;
60 /** @type {?Element} */
61 this._hoveredListElement = null;
52 } 62 }
53 63
54 /** 64 /**
55 * @param {string} query 65 * @param {string} query
56 * @return {!RegExp} 66 * @return {!RegExp}
57 */ 67 */
58 static filterRegex(query) { 68 static filterRegex(query) {
59 const toEscape = String.regexSpecialCharacters(); 69 const toEscape = String.regexSpecialCharacters();
60 var regexString = ''; 70 var regexString = '';
61 for (var i = 0; i < query.length; ++i) { 71 for (var i = 0; i < query.length; ++i) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 return false; 120 return false;
111 } 121 }
112 122
113 /** 123 /**
114 * @param {string} placeholder 124 * @param {string} placeholder
115 */ 125 */
116 setPlaceholder(placeholder) { 126 setPlaceholder(placeholder) {
117 this._prompt.setPlaceholder(placeholder); 127 this._prompt.setPlaceholder(placeholder);
118 } 128 }
119 129
120 showAsDialog() { 130 /**
131 * @param {!AnchorBox=} anchorBox
132 * @param {!UI.GlassPane.AnchorBehavior=} anchorBehavior
133 */
134 showAsDialog(anchorBox, anchorBehavior) {
121 this._dialog = new UI.Dialog(); 135 this._dialog = new UI.Dialog();
136 if (anchorBox)
137 this._dialog.setContentAnchorBox(anchorBox);
138 else
139 this._dialog.setContentPosition(null, 22);
122 this._dialog.setMaxContentSize(new UI.Size(504, 340)); 140 this._dialog.setMaxContentSize(new UI.Size(504, 340));
123 this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeigh t); 141 this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeigh t);
124 this._dialog.setContentPosition(null, 22); 142 if (anchorBehavior)
143 this._dialog.setAnchorBehavior(anchorBehavior);
125 this.show(this._dialog.contentElement); 144 this.show(this._dialog.contentElement);
126 this._dialog.show(); 145 this._dialog.show();
127 } 146 }
128 147
129 /** 148 /**
130 * @param {string} prefix 149 * @param {string} prefix
131 */ 150 */
132 setPrefix(prefix) { 151 setPrefix(prefix) {
133 this._prefix = prefix; 152 this._prefix = prefix;
134 } 153 }
135 154
136 /** 155 /**
137 * @param {?QuickOpen.FilteredListWidget.Provider} provider 156 * @param {?QuickOpen.FilteredListWidget.Provider} provider
138 */ 157 */
139 setProvider(provider) { 158 setProvider(provider) {
140 if (provider === this._provider) 159 if (provider === this._provider)
141 return; 160 return;
142 161
143 if (this._provider) 162 if (this._provider)
144 this._provider.detach(); 163 this._provider.detach();
145 this._clearTimers(); 164 this._clearTimers();
146 165
147 this._provider = provider; 166 this._provider = provider;
148 if (this.isShowing()) 167 if (this.isShowing())
149 this._attachProvider(); 168 this._attachProvider();
150 } 169 }
151 170
171 /**
172 * @param {?string} icon
173 */
174 setInputIcon(icon) {
175 this._iconContainer.removeChildren();
176 if (icon)
177 this._iconContainer.appendChild(UI.Icon.create(icon, 'filtered-list-input- icon'));
178 }
179
152 _attachProvider() { 180 _attachProvider() {
153 this._list.replaceAllItems([]); 181 this._list.replaceAllItems([]);
154 this._list.invalidateItemHeight(); 182 this._list.invalidateItemHeight();
155 if (this._provider) { 183 if (this._provider) {
156 this._provider.setRefreshCallback(this._itemsLoaded.bind(this, this._provi der)); 184 this._provider.setRefreshCallback(this._itemsLoaded.bind(this, this._provi der));
157 this._provider.attach(); 185 this._provider.attach();
158 } 186 }
159 this._itemsLoaded(this._provider); 187 this._itemsLoaded(this._provider);
160 } 188 }
161 189
162 /** 190 /**
163 * @return {string} 191 * @return {string}
164 */ 192 */
165 _value() { 193 _value() {
166 return this._prompt.text().trim(); 194 return this._prompt.text().trim();
167 } 195 }
168 196
169 _cleanValue() { 197 _cleanValue() {
170 return this._value().substring(this._prefix.length); 198 return this._value().substring(this._prefix.length);
171 } 199 }
172 200
173 /** 201 /**
202 * @param {!Event} event
203 */
204 _updateHover(event) {
205 var item = this._list.itemForNode(/** @type {?Node} */ (event.target));
206 this._hover(item);
207 }
208
209 /**
174 * @override 210 * @override
175 */ 211 */
176 wasShown() { 212 wasShown() {
177 this._attachProvider(); 213 this._attachProvider();
178 } 214 }
179 215
180 /** 216 /**
181 * @override 217 * @override
182 */ 218 */
183 willHide() { 219 willHide() {
220 this._hover(null);
184 if (this._provider) 221 if (this._provider)
185 this._provider.detach(); 222 this._provider.detach();
186 this._clearTimers(); 223 this._clearTimers();
187 } 224 }
188 225
189 _clearTimers() { 226 _clearTimers() {
190 clearTimeout(this._filterTimer); 227 clearTimeout(this._filterTimer);
191 clearTimeout(this._scoringTimer); 228 clearTimeout(this._scoringTimer);
192 clearTimeout(this._loadTimeout); 229 clearTimeout(this._loadTimeout);
193 delete this._filterTimer; 230 delete this._filterTimer;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 * @param {?number} from 300 * @param {?number} from
264 * @param {?number} to 301 * @param {?number} to
265 * @param {?Element} fromElement 302 * @param {?Element} fromElement
266 * @param {?Element} toElement 303 * @param {?Element} toElement
267 */ 304 */
268 selectedItemChanged(from, to, fromElement, toElement) { 305 selectedItemChanged(from, to, fromElement, toElement) {
269 if (fromElement) 306 if (fromElement)
270 fromElement.classList.remove('selected'); 307 fromElement.classList.remove('selected');
271 if (toElement) 308 if (toElement)
272 toElement.classList.add('selected'); 309 toElement.classList.add('selected');
310 this._hover(to);
dgozman 2017/05/03 17:32:58 I don't think it's a good idea to mix up mouse acc
eostroukhov 2017/05/03 22:01:37 In the newer version it is now called "highlight"
273 } 311 }
274 312
275 /** 313 /**
314 * @param {number} item
315 */
316 setInitialSelection(item) {
317 if (this._list.length() > 0)
318 this._list.selectItem(item, true);
319 else
320 this._initialSelectedItem = item;
321 }
322
323 /**
276 * @param {!Event} event 324 * @param {!Event} event
277 */ 325 */
278 _onClick(event) { 326 _onClick(event) {
279 var item = this._list.itemForNode(/** @type {?Node} */ (event.target)); 327 var item = this._list.itemForNode(/** @type {?Node} */ (event.target));
280 if (item === null) 328 if (item === null)
281 return; 329 return;
282 330
283 event.consume(true); 331 event.consume(true);
284 this._selectItem(item); 332 this._selectItem(item);
285 if (this._dialog) 333 if (this._dialog)
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 * @param {!Array<number>} bestItems 475 * @param {!Array<number>} bestItems
428 * @param {!Array<number>} overflowItems 476 * @param {!Array<number>} overflowItems
429 * @param {!Array<number>} filteredItems 477 * @param {!Array<number>} filteredItems
430 */ 478 */
431 _refreshList(bestItems, overflowItems, filteredItems) { 479 _refreshList(bestItems, overflowItems, filteredItems) {
432 delete this._refreshListWithCurrentResult; 480 delete this._refreshListWithCurrentResult;
433 filteredItems = [].concat(bestItems, overflowItems, filteredItems); 481 filteredItems = [].concat(bestItems, overflowItems, filteredItems);
434 this._updateNotFoundMessage(!!filteredItems.length); 482 this._updateNotFoundMessage(!!filteredItems.length);
435 var oldHeight = this._list.element.offsetHeight; 483 var oldHeight = this._list.element.offsetHeight;
436 this._list.replaceAllItems(filteredItems); 484 this._list.replaceAllItems(filteredItems);
437 if (filteredItems.length) 485 if (filteredItems.length) {
438 this._list.selectItem(filteredItems[0]); 486 var selection = filteredItems[0];
487 if (this._initialSelectedItem !== null && filteredItems.includes(this._ini tialSelectedItem))
488 selection = this._initialSelectedItem;
489 this._initialSelectedItem = null;
490 this._list.selectItem(selection, true);
491 }
439 if (this._list.element.offsetHeight !== oldHeight) 492 if (this._list.element.offsetHeight !== oldHeight)
440 this._list.viewportResized(); 493 this._list.viewportResized();
441 this._itemsFilteredForTest(); 494 this._itemsFilteredForTest();
442 } 495 }
443 496
444 /** 497 /**
445 * @param {boolean} hasItems 498 * @param {boolean} hasItems
446 */ 499 */
447 _updateNotFoundMessage(hasItems) { 500 _updateNotFoundMessage(hasItems) {
448 this._list.element.classList.toggle('hidden', !hasItems); 501 this._list.element.classList.toggle('hidden', !hasItems);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 553
501 /** 554 /**
502 * @param {?number} itemIndex 555 * @param {?number} itemIndex
503 */ 556 */
504 _selectItem(itemIndex) { 557 _selectItem(itemIndex) {
505 this._promptHistory.push(this._value()); 558 this._promptHistory.push(this._value());
506 if (this._promptHistory.length > 100) 559 if (this._promptHistory.length > 100)
507 this._promptHistory.shift(); 560 this._promptHistory.shift();
508 this._provider.selectItem(itemIndex, this._cleanValue()); 561 this._provider.selectItem(itemIndex, this._cleanValue());
509 } 562 }
563
564 /**
565 * @param {?number} item
566 */
567 _hover(item) {
568 var element = item === null ? null : this._list.elementForItem(item);
569 if (element === this._hoveredListElement)
570 return;
571 if (this._hoveredListElement)
572 this._hoveredListElement.classList.remove('hovered');
dgozman 2017/05/03 17:32:58 Let's do this with :hover css class, and remove Li
eostroukhov 2017/05/03 22:01:38 I was not sure if it was ok to use pseudoclasses :
573 if (element)
574 element.classList.add('hovered');
575 this._hoveredListElement = element;
576 if (this._provider)
577 this._provider.hoverItem(item);
578 }
510 }; 579 };
511 580
512 581
513 /** 582 /**
514 * @unrestricted 583 * @unrestricted
515 */ 584 */
516 QuickOpen.FilteredListWidget.Provider = class { 585 QuickOpen.FilteredListWidget.Provider = class {
517 /** 586 /**
518 * @param {function():void} refreshCallback 587 * @param {function():void} refreshCallback
519 */ 588 */
(...skipping 22 matching lines...) Expand all
542 /** 611 /**
543 * @param {number} itemIndex 612 * @param {number} itemIndex
544 * @param {string} query 613 * @param {string} query
545 * @return {number} 614 * @return {number}
546 */ 615 */
547 itemScoreAt(itemIndex, query) { 616 itemScoreAt(itemIndex, query) {
548 return 1; 617 return 1;
549 } 618 }
550 619
551 /** 620 /**
621 * @param {?number} itemIndex
622 */
623 hoverItem(itemIndex) {
624 }
625
626 /**
552 * @param {number} itemIndex 627 * @param {number} itemIndex
553 * @param {string} query 628 * @param {string} query
554 * @param {!Element} titleElement 629 * @param {!Element} titleElement
555 * @param {!Element} subtitleElement 630 * @param {!Element} subtitleElement
556 */ 631 */
557 renderItem(itemIndex, query, titleElement, subtitleElement) { 632 renderItem(itemIndex, query, titleElement, subtitleElement) {
558 } 633 }
559 634
560 /** 635 /**
561 * @return {boolean} 636 * @return {boolean}
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 * @param {string} query 668 * @param {string} query
594 * @return {string} 669 * @return {string}
595 */ 670 */
596 notFoundText(query) { 671 notFoundText(query) {
597 return Common.UIString('No results found'); 672 return Common.UIString('No results found');
598 } 673 }
599 674
600 detach() { 675 detach() {
601 } 676 }
602 }; 677 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698