OLD | NEW |
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._highlig
htItem(null)); |
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; |
52 } | 60 } |
53 | 61 |
54 /** | 62 /** |
55 * @param {string} query | 63 * @param {string} query |
56 * @return {!RegExp} | 64 * @return {!RegExp} |
57 */ | 65 */ |
58 static filterRegex(query) { | 66 static filterRegex(query) { |
59 const toEscape = String.regexSpecialCharacters(); | 67 const toEscape = String.regexSpecialCharacters(); |
60 var regexString = ''; | 68 var regexString = ''; |
61 for (var i = 0; i < query.length; ++i) { | 69 for (var i = 0; i < query.length; ++i) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 return false; | 118 return false; |
111 } | 119 } |
112 | 120 |
113 /** | 121 /** |
114 * @param {string} placeholder | 122 * @param {string} placeholder |
115 */ | 123 */ |
116 setPlaceholder(placeholder) { | 124 setPlaceholder(placeholder) { |
117 this._prompt.setPlaceholder(placeholder); | 125 this._prompt.setPlaceholder(placeholder); |
118 } | 126 } |
119 | 127 |
120 showAsDialog() { | 128 /** |
| 129 * @param {!AnchorBox=} anchorBox |
| 130 * @param {!UI.GlassPane.AnchorBehavior=} anchorBehavior |
| 131 */ |
| 132 showAsDialog(anchorBox, anchorBehavior) { |
121 this._dialog = new UI.Dialog(); | 133 this._dialog = new UI.Dialog(); |
| 134 if (anchorBox) |
| 135 this._dialog.setContentAnchorBox(anchorBox); |
| 136 else |
| 137 this._dialog.setContentPosition(null, 22); |
122 this._dialog.setMaxContentSize(new UI.Size(504, 340)); | 138 this._dialog.setMaxContentSize(new UI.Size(504, 340)); |
123 this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeigh
t); | 139 this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeigh
t); |
124 this._dialog.setContentPosition(null, 22); | 140 if (anchorBehavior) |
| 141 this._dialog.setAnchorBehavior(anchorBehavior); |
125 this.show(this._dialog.contentElement); | 142 this.show(this._dialog.contentElement); |
126 this._dialog.show(); | 143 this._dialog.show(); |
127 } | 144 } |
128 | 145 |
129 /** | 146 /** |
130 * @param {string} prefix | 147 * @param {string} prefix |
131 */ | 148 */ |
132 setPrefix(prefix) { | 149 setPrefix(prefix) { |
133 this._prefix = prefix; | 150 this._prefix = prefix; |
134 } | 151 } |
135 | 152 |
136 /** | 153 /** |
137 * @param {?QuickOpen.FilteredListWidget.Provider} provider | 154 * @param {?QuickOpen.FilteredListWidget.Provider} provider |
138 */ | 155 */ |
139 setProvider(provider) { | 156 setProvider(provider) { |
140 if (provider === this._provider) | 157 if (provider === this._provider) |
141 return; | 158 return; |
142 | 159 |
143 if (this._provider) | 160 if (this._provider) |
144 this._provider.detach(); | 161 this._provider.detach(); |
145 this._clearTimers(); | 162 this._clearTimers(); |
146 | 163 |
147 this._provider = provider; | 164 this._provider = provider; |
148 if (this.isShowing()) | 165 if (this.isShowing()) |
149 this._attachProvider(); | 166 this._attachProvider(); |
150 } | 167 } |
151 | 168 |
| 169 /** |
| 170 * @param {?string} icon |
| 171 */ |
| 172 setInputIcon(icon) { |
| 173 this._iconContainer.removeChildren(); |
| 174 if (icon) |
| 175 this._iconContainer.appendChild(UI.Icon.create(icon, 'filtered-list-input-
icon')); |
| 176 } |
| 177 |
152 _attachProvider() { | 178 _attachProvider() { |
153 this._list.replaceAllItems([]); | 179 this._list.replaceAllItems([]); |
154 this._list.invalidateItemHeight(); | 180 this._list.invalidateItemHeight(); |
155 if (this._provider) { | 181 if (this._provider) { |
156 this._provider.setRefreshCallback(this._itemsLoaded.bind(this, this._provi
der)); | 182 this._provider.setRefreshCallback(this._itemsLoaded.bind(this, this._provi
der)); |
157 this._provider.attach(); | 183 this._provider.attach(); |
158 } | 184 } |
159 this._itemsLoaded(this._provider); | 185 this._itemsLoaded(this._provider); |
160 } | 186 } |
161 | 187 |
162 /** | 188 /** |
163 * @return {string} | 189 * @return {string} |
164 */ | 190 */ |
165 _value() { | 191 _value() { |
166 return this._prompt.text().trim(); | 192 return this._prompt.text().trim(); |
167 } | 193 } |
168 | 194 |
169 _cleanValue() { | 195 _cleanValue() { |
170 return this._value().substring(this._prefix.length); | 196 return this._value().substring(this._prefix.length); |
171 } | 197 } |
172 | 198 |
173 /** | 199 /** |
| 200 * @param {!Event} event |
| 201 */ |
| 202 _updateHover(event) { |
| 203 var item = this._list.itemForNode(/** @type {?Node} */ (event.target)); |
| 204 this._highlightItem(item); |
| 205 } |
| 206 |
| 207 /** |
174 * @override | 208 * @override |
175 */ | 209 */ |
176 wasShown() { | 210 wasShown() { |
177 this._attachProvider(); | 211 this._attachProvider(); |
178 } | 212 } |
179 | 213 |
180 /** | 214 /** |
181 * @override | 215 * @override |
182 */ | 216 */ |
183 willHide() { | 217 willHide() { |
| 218 this._highlightItem(null); |
184 if (this._provider) | 219 if (this._provider) |
185 this._provider.detach(); | 220 this._provider.detach(); |
186 this._clearTimers(); | 221 this._clearTimers(); |
187 } | 222 } |
188 | 223 |
189 _clearTimers() { | 224 _clearTimers() { |
190 clearTimeout(this._filterTimer); | 225 clearTimeout(this._filterTimer); |
191 clearTimeout(this._scoringTimer); | 226 clearTimeout(this._scoringTimer); |
192 clearTimeout(this._loadTimeout); | 227 clearTimeout(this._loadTimeout); |
193 delete this._filterTimer; | 228 delete this._filterTimer; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 * @param {?number} from | 298 * @param {?number} from |
264 * @param {?number} to | 299 * @param {?number} to |
265 * @param {?Element} fromElement | 300 * @param {?Element} fromElement |
266 * @param {?Element} toElement | 301 * @param {?Element} toElement |
267 */ | 302 */ |
268 selectedItemChanged(from, to, fromElement, toElement) { | 303 selectedItemChanged(from, to, fromElement, toElement) { |
269 if (fromElement) | 304 if (fromElement) |
270 fromElement.classList.remove('selected'); | 305 fromElement.classList.remove('selected'); |
271 if (toElement) | 306 if (toElement) |
272 toElement.classList.add('selected'); | 307 toElement.classList.add('selected'); |
| 308 this._highlightItem(to); |
273 } | 309 } |
274 | 310 |
275 /** | 311 /** |
| 312 * @param {number} item |
| 313 */ |
| 314 setInitialSelection(item) { |
| 315 if (this._list.length() > 0) |
| 316 this._list.selectItem(item, true); |
| 317 else |
| 318 this._initialSelectedItem = item; |
| 319 } |
| 320 |
| 321 /** |
276 * @param {!Event} event | 322 * @param {!Event} event |
277 */ | 323 */ |
278 _onClick(event) { | 324 _onClick(event) { |
279 var item = this._list.itemForNode(/** @type {?Node} */ (event.target)); | 325 var item = this._list.itemForNode(/** @type {?Node} */ (event.target)); |
280 if (item === null) | 326 if (item === null) |
281 return; | 327 return; |
282 | 328 |
283 event.consume(true); | 329 event.consume(true); |
284 this._selectItem(item); | 330 this._selectItem(item); |
285 if (this._dialog) | 331 if (this._dialog) |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 * @param {!Array<number>} bestItems | 473 * @param {!Array<number>} bestItems |
428 * @param {!Array<number>} overflowItems | 474 * @param {!Array<number>} overflowItems |
429 * @param {!Array<number>} filteredItems | 475 * @param {!Array<number>} filteredItems |
430 */ | 476 */ |
431 _refreshList(bestItems, overflowItems, filteredItems) { | 477 _refreshList(bestItems, overflowItems, filteredItems) { |
432 delete this._refreshListWithCurrentResult; | 478 delete this._refreshListWithCurrentResult; |
433 filteredItems = [].concat(bestItems, overflowItems, filteredItems); | 479 filteredItems = [].concat(bestItems, overflowItems, filteredItems); |
434 this._updateNotFoundMessage(!!filteredItems.length); | 480 this._updateNotFoundMessage(!!filteredItems.length); |
435 var oldHeight = this._list.element.offsetHeight; | 481 var oldHeight = this._list.element.offsetHeight; |
436 this._list.replaceAllItems(filteredItems); | 482 this._list.replaceAllItems(filteredItems); |
437 if (filteredItems.length) | 483 if (filteredItems.length) { |
438 this._list.selectItem(filteredItems[0]); | 484 var selection = filteredItems[0]; |
| 485 if (this._initialSelectedItem !== null && filteredItems.includes(this._ini
tialSelectedItem)) |
| 486 selection = this._initialSelectedItem; |
| 487 this._initialSelectedItem = null; |
| 488 this._list.selectItem(selection, true); |
| 489 } |
439 if (this._list.element.offsetHeight !== oldHeight) | 490 if (this._list.element.offsetHeight !== oldHeight) |
440 this._list.viewportResized(); | 491 this._list.viewportResized(); |
441 this._itemsFilteredForTest(); | 492 this._itemsFilteredForTest(); |
442 } | 493 } |
443 | 494 |
444 /** | 495 /** |
445 * @param {boolean} hasItems | 496 * @param {boolean} hasItems |
446 */ | 497 */ |
447 _updateNotFoundMessage(hasItems) { | 498 _updateNotFoundMessage(hasItems) { |
448 this._list.element.classList.toggle('hidden', !hasItems); | 499 this._list.element.classList.toggle('hidden', !hasItems); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 | 551 |
501 /** | 552 /** |
502 * @param {?number} itemIndex | 553 * @param {?number} itemIndex |
503 */ | 554 */ |
504 _selectItem(itemIndex) { | 555 _selectItem(itemIndex) { |
505 this._promptHistory.push(this._value()); | 556 this._promptHistory.push(this._value()); |
506 if (this._promptHistory.length > 100) | 557 if (this._promptHistory.length > 100) |
507 this._promptHistory.shift(); | 558 this._promptHistory.shift(); |
508 this._provider.selectItem(itemIndex, this._cleanValue()); | 559 this._provider.selectItem(itemIndex, this._cleanValue()); |
509 } | 560 } |
| 561 |
| 562 /** |
| 563 * @param {?number} item |
| 564 */ |
| 565 _highlightItem(item) { |
| 566 if (this._provider) |
| 567 this._provider.highlightItem(item); |
| 568 } |
510 }; | 569 }; |
511 | 570 |
512 | 571 |
513 /** | 572 /** |
514 * @unrestricted | 573 * @unrestricted |
515 */ | 574 */ |
516 QuickOpen.FilteredListWidget.Provider = class { | 575 QuickOpen.FilteredListWidget.Provider = class { |
517 /** | 576 /** |
518 * @param {function():void} refreshCallback | 577 * @param {function():void} refreshCallback |
519 */ | 578 */ |
(...skipping 22 matching lines...) Expand all Loading... |
542 /** | 601 /** |
543 * @param {number} itemIndex | 602 * @param {number} itemIndex |
544 * @param {string} query | 603 * @param {string} query |
545 * @return {number} | 604 * @return {number} |
546 */ | 605 */ |
547 itemScoreAt(itemIndex, query) { | 606 itemScoreAt(itemIndex, query) { |
548 return 1; | 607 return 1; |
549 } | 608 } |
550 | 609 |
551 /** | 610 /** |
| 611 * @param {?number} itemIndex |
| 612 */ |
| 613 highlightItem(itemIndex) { |
| 614 } |
| 615 |
| 616 /** |
552 * @param {number} itemIndex | 617 * @param {number} itemIndex |
553 * @param {string} query | 618 * @param {string} query |
554 * @param {!Element} titleElement | 619 * @param {!Element} titleElement |
555 * @param {!Element} subtitleElement | 620 * @param {!Element} subtitleElement |
556 */ | 621 */ |
557 renderItem(itemIndex, query, titleElement, subtitleElement) { | 622 renderItem(itemIndex, query, titleElement, subtitleElement) { |
558 } | 623 } |
559 | 624 |
560 /** | 625 /** |
561 * @return {boolean} | 626 * @return {boolean} |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 * @param {string} query | 658 * @param {string} query |
594 * @return {string} | 659 * @return {string} |
595 */ | 660 */ |
596 notFoundText(query) { | 661 notFoundText(query) { |
597 return Common.UIString('No results found'); | 662 return Common.UIString('No results found'); |
598 } | 663 } |
599 | 664 |
600 detach() { | 665 detach() { |
601 } | 666 } |
602 }; | 667 }; |
OLD | NEW |