blob: 6cacb7f0aa9a3b324bc37f188b87e541e84badd9 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Matt Lilek ([email protected]).
4 * Copyright (C) 2009 Joseph Pecoraro
5 * Copyright (C) 2011 Google Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/**
33 * @unrestricted
34 */
35UI.SearchableView = class extends UI.VBox {
36 /**
37 * @param {!UI.Searchable} searchable
38 * @param {string=} settingName
39 */
40 constructor(searchable, settingName) {
41 super(true);
42 this.registerRequiredCSS('ui/searchableView.css');
43 this.element[UI.SearchableView._symbol] = this;
44
45 this._searchProvider = searchable;
46 this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null;
47 this._replaceable = false;
48
Joel Einbinder7fbe24c2019-01-24 05:19:0149 this.contentElement.createChild('slot');
Blink Reformat4c46d092018-04-07 15:32:3750 this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
51 this._footerElementContainer.style.order = 100;
52 this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
53
54 const replaceToggleToolbar = new UI.Toolbar('replace-toggle-toolbar', this._footerElement);
55 this._replaceToggleButton = new UI.ToolbarToggle(Common.UIString('Replace'), 'mediumicon-replace');
56 this._replaceToggleButton.addEventListener(UI.ToolbarButton.Events.Click, this._toggleReplace, this);
57 replaceToggleToolbar.appendToolbarItem(this._replaceToggleButton);
58
59 const searchInputElements = this._footerElement.createChild('div', 'toolbar-search-inputs');
60 const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
61
62 this._searchInputElement = UI.HistoryInput.create();
63 this._searchInputElement.classList.add('search-replace');
64 this._searchInputElement.id = 'search-input-field';
65 this._searchInputElement.placeholder = Common.UIString('Find');
66 searchControlElement.appendChild(this._searchInputElement);
67
68 this._matchesElement = searchControlElement.createChild('label', 'search-results-matches');
69 this._matchesElement.setAttribute('for', 'search-input-field');
70
71 const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
72
73 this._searchNavigationPrevElement =
74 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
75 this._searchNavigationPrevElement.addEventListener('click', this._onPrevButtonSearch.bind(this), false);
76 this._searchNavigationPrevElement.title = Common.UIString('Search previous');
77
78 this._searchNavigationNextElement =
79 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
80 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
81 this._searchNavigationNextElement.title = Common.UIString('Search next');
82
83 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
84 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
85
86 this._replaceInputElement =
87 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
88 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
89 this._replaceInputElement.placeholder = Common.UIString('Replace');
90
91 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
92 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
93
94 const toolbar = new UI.Toolbar('toolbar-search-options', firstRowButtons);
95
96 if (this._searchProvider.supportsCaseSensitiveSearch()) {
97 this._caseSensitiveButton = new UI.ToolbarToggle(Common.UIString('Match Case'));
98 this._caseSensitiveButton.setText('Aa');
99 this._caseSensitiveButton.addEventListener(UI.ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
100 toolbar.appendToolbarItem(this._caseSensitiveButton);
101 }
102
103 if (this._searchProvider.supportsRegexSearch()) {
104 this._regexButton = new UI.ToolbarToggle(Common.UIString('Use Regular Expression'));
105 this._regexButton.setText('.*');
106 this._regexButton.addEventListener(UI.ToolbarButton.Events.Click, this._toggleRegexSearch, this);
107 toolbar.appendToolbarItem(this._regexButton);
108 }
109
110 const cancelButtonElement =
111 UI.createTextButton(Common.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
112 firstRowButtons.appendChild(cancelButtonElement);
113
114 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
115
116 this._replaceButtonElement =
117 UI.createTextButton(Common.UIString('Replace'), this._replace.bind(this), 'search-action-button');
118 this._replaceButtonElement.disabled = true;
119 this._secondRowButtons.appendChild(this._replaceButtonElement);
120
121 this._replaceAllButtonElement =
122 UI.createTextButton(Common.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
123 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
124 this._replaceAllButtonElement.disabled = true;
125
126 this._minimalSearchQuerySize = 3;
127 this._loadSetting();
128 }
129
130 /**
131 * @param {?Element} element
132 * @return {?UI.SearchableView}
133 */
134 static fromElement(element) {
135 let view = null;
136 while (element && !view) {
137 view = element[UI.SearchableView._symbol];
138 element = element.parentElementOrShadowHost();
139 }
140 return view;
141 }
142
143 _toggleCaseSensitiveSearch() {
144 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
145 this._saveSetting();
146 this._performSearch(false, true);
147 }
148
149 _toggleRegexSearch() {
150 this._regexButton.setToggled(!this._regexButton.toggled());
151 this._saveSetting();
152 this._performSearch(false, true);
153 }
154
155 _toggleReplace() {
156 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
157 this._updateSecondRowVisibility();
158 }
159
160 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34161 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37162 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34163 }
Blink Reformat4c46d092018-04-07 15:32:37164 const settingValue = this._setting.get() || {};
165 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
166 settingValue.isRegex = this._regexButton.toggled();
167 this._setting.set(settingValue);
168 }
169
170 _loadSetting() {
171 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34172 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37173 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34174 }
175 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37176 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34177 }
Blink Reformat4c46d092018-04-07 15:32:37178 }
179
180 /**
181 * @param {number} minimalSearchQuerySize
182 */
183 setMinimalSearchQuerySize(minimalSearchQuerySize) {
184 this._minimalSearchQuerySize = minimalSearchQuerySize;
185 }
186
187 /**
188 * @param {string} placeholder
189 */
190 setPlaceholder(placeholder) {
191 this._searchInputElement.placeholder = placeholder;
192 }
193
194 /**
195 * @param {boolean} replaceable
196 */
197 setReplaceable(replaceable) {
198 this._replaceable = replaceable;
199 }
200
201 /**
202 * @param {number} matches
203 */
204 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34205 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37206 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34207 }
Blink Reformat4c46d092018-04-07 15:32:37208 this._searchProvider.currentSearchMatches = matches;
209 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
210 }
211
212 /**
213 * @param {number} currentMatchIndex
214 */
215 updateCurrentMatchIndex(currentMatchIndex) {
216 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
217 }
218
219 /**
220 * @return {boolean}
221 */
222 isSearchVisible() {
223 return this._searchIsVisible;
224 }
225
226 closeSearch() {
227 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34228 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37229 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34230 }
Blink Reformat4c46d092018-04-07 15:32:37231 }
232
233 _toggleSearchBar(toggled) {
234 this._footerElementContainer.classList.toggle('hidden', !toggled);
235 this.doResize();
236 }
237
238 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37240 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34241 }
Blink Reformat4c46d092018-04-07 15:32:37242 this.resetSearch();
243 delete this._searchIsVisible;
244 this._toggleSearchBar(false);
245 }
246
247 resetSearch() {
248 this._clearSearch();
249 this._updateReplaceVisibility();
250 this._matchesElement.textContent = '';
251 }
252
253 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34254 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37255 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34256 }
Blink Reformat4c46d092018-04-07 15:32:37257 this.resetSearch();
258 this._performSearch(false, false);
259 }
260
261 /**
262 * @return {boolean}
263 */
264 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34265 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37266 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34267 }
Blink Reformat4c46d092018-04-07 15:32:37268 this._searchProvider.jumpToNextSearchResult();
269 return true;
270 }
271
272 /**
273 * @return {boolean}
274 */
275 handleFindPreviousShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34276 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37277 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34278 }
Blink Reformat4c46d092018-04-07 15:32:37279 this._searchProvider.jumpToPreviousSearchResult();
280 return true;
281 }
282
283 /**
284 * @return {boolean}
285 */
286 handleFindShortcut() {
287 this.showSearchField();
288 return true;
289 }
290
291 /**
292 * @return {boolean}
293 */
294 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34295 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37296 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34297 }
Blink Reformat4c46d092018-04-07 15:32:37298 this.closeSearch();
299 return true;
300 }
301
302 /**
303 * @param {boolean} enabled
304 */
305 _updateSearchNavigationButtonState(enabled) {
306 this._replaceButtonElement.disabled = !enabled;
307 this._replaceAllButtonElement.disabled = !enabled;
308 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
309 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
310 }
311
312 /**
313 * @param {number} matches
314 * @param {number} currentMatchIndex
315 */
316 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34317 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37318 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34319 } else if (matches === 0 || currentMatchIndex >= 0) {
Blink Reformat4c46d092018-04-07 15:32:37320 this._matchesElement.textContent = Common.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34321 } else if (matches === 1) {
Blink Reformat4c46d092018-04-07 15:32:37322 this._matchesElement.textContent = Common.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34323 } else {
Blink Reformat4c46d092018-04-07 15:32:37324 this._matchesElement.textContent = Common.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34325 }
Blink Reformat4c46d092018-04-07 15:32:37326 this._updateSearchNavigationButtonState(matches > 0);
327 }
328
329 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34330 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37331 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 }
Blink Reformat4c46d092018-04-07 15:32:37333
334 let queryCandidate;
335 if (!this._searchInputElement.hasFocus()) {
336 const selection = UI.inspectorView.element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34337 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37338 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34339 }
Blink Reformat4c46d092018-04-07 15:32:37340 }
341
342 this._toggleSearchBar(true);
343 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37345 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 }
Blink Reformat4c46d092018-04-07 15:32:37347 this._performSearch(false, false);
348 this._searchInputElement.focus();
349 this._searchInputElement.select();
350 this._searchIsVisible = true;
351 }
352
353 _updateReplaceVisibility() {
354 this._replaceToggleButton.setVisible(this._replaceable);
355 if (!this._replaceable) {
356 this._replaceToggleButton.setToggled(false);
357 this._updateSecondRowVisibility();
358 }
359 }
360
361 /**
362 * @param {!Event} event
363 */
364 _onSearchKeyDown(event) {
365 if (isEscKey(event)) {
366 this.closeSearch();
367 event.consume(true);
368 return;
369 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34370 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37371 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34372 }
Blink Reformat4c46d092018-04-07 15:32:37373
Tim van der Lippe1d6e57a2019-09-30 11:55:34374 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37375 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34376 } else {
Blink Reformat4c46d092018-04-07 15:32:37377 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34378 }
Blink Reformat4c46d092018-04-07 15:32:37379 }
380
381 /**
382 * @param {!Event} event
383 */
384 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34385 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37386 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 }
Blink Reformat4c46d092018-04-07 15:32:37388 }
389
390 /**
391 * @param {boolean=} isBackwardSearch
392 */
393 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34394 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37395 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34396 }
Blink Reformat4c46d092018-04-07 15:32:37397
Tim van der Lippe1d6e57a2019-09-30 11:55:34398 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37399 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34400 } else {
Blink Reformat4c46d092018-04-07 15:32:37401 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34402 }
Blink Reformat4c46d092018-04-07 15:32:37403 }
404
405 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37407 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 }
Blink Reformat4c46d092018-04-07 15:32:37409 this._jumpToNextSearchResult();
410 this._searchInputElement.focus();
411 }
412
413 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34414 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37415 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34416 }
Blink Reformat4c46d092018-04-07 15:32:37417 this._jumpToNextSearchResult(true);
418 this._searchInputElement.focus();
419 }
420
421 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34422 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37423 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34424 } else {
Blink Reformat4c46d092018-04-07 15:32:37425 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34426 }
Blink Reformat4c46d092018-04-07 15:32:37427 this._searchInputElement.focus();
428 }
429
430 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34431 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37432 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34433 } else {
Blink Reformat4c46d092018-04-07 15:32:37434 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34435 }
Blink Reformat4c46d092018-04-07 15:32:37436 this._searchInputElement.focus();
437 }
438
439 _clearSearch() {
440 delete this._currentQuery;
441 if (!!this._searchProvider.currentQuery) {
442 delete this._searchProvider.currentQuery;
443 this._searchProvider.searchCanceled();
444 }
445 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
446 }
447
448 /**
449 * @param {boolean} forceSearch
450 * @param {boolean} shouldJump
451 * @param {boolean=} jumpBackwards
452 */
453 _performSearch(forceSearch, shouldJump, jumpBackwards) {
454 const query = this._searchInputElement.value;
455 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
456 this._clearSearch();
457 return;
458 }
459
460 this._currentQuery = query;
461 this._searchProvider.currentQuery = query;
462
463 const searchConfig = this._currentSearchConfig();
464 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
465 }
466
467 /**
468 * @return {!UI.SearchableView.SearchConfig}
469 */
470 _currentSearchConfig() {
471 const query = this._searchInputElement.value;
472 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
473 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
474 return new UI.SearchableView.SearchConfig(query, caseSensitive, isRegex);
475 }
476
477 _updateSecondRowVisibility() {
478 const secondRowVisible = this._replaceToggleButton.toggled();
479 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
480 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
481 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
482
Tim van der Lippe1d6e57a2019-09-30 11:55:34483 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37484 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34485 } else {
Blink Reformat4c46d092018-04-07 15:32:37486 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34487 }
Blink Reformat4c46d092018-04-07 15:32:37488 this.doResize();
489 }
490
491 _replace() {
492 const searchConfig = this._currentSearchConfig();
493 /** @type {!UI.Replaceable} */ (this._searchProvider)
494 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
495 delete this._currentQuery;
496 this._performSearch(true, true);
497 }
498
499 _replaceAll() {
500 const searchConfig = this._currentSearchConfig();
501 /** @type {!UI.Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
502 }
503
504 /**
505 * @param {!Event} event
506 */
507 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34508 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37509 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34510 }
Blink Reformat4c46d092018-04-07 15:32:37511 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
512 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
513 }
514
515 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34516 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37517 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34518 }
Blink Reformat4c46d092018-04-07 15:32:37519 delete this._valueChangedTimeoutId;
520 this._performSearch(false, true);
521 }
522};
523
524
525UI.SearchableView._symbol = Symbol('searchableView');
526
527
528/**
529 * @interface
530 */
531UI.Searchable = function() {};
532
533UI.Searchable.prototype = {
534 searchCanceled() {},
535
536 /**
537 * @param {!UI.SearchableView.SearchConfig} searchConfig
538 * @param {boolean} shouldJump
539 * @param {boolean=} jumpBackwards
540 */
541 performSearch(searchConfig, shouldJump, jumpBackwards) {},
542
543 jumpToNextSearchResult() {},
544
545 jumpToPreviousSearchResult() {},
546
547 /**
548 * @return {boolean}
549 */
550 supportsCaseSensitiveSearch() {},
551
552 /**
553 * @return {boolean}
554 */
555 supportsRegexSearch() {}
556};
557
558/**
559 * @interface
560 */
561UI.Replaceable = function() {};
562
563UI.Replaceable.prototype = {
564 /**
565 * @param {!UI.SearchableView.SearchConfig} searchConfig
566 * @param {string} replacement
567 */
568 replaceSelectionWith(searchConfig, replacement) {},
569
570 /**
571 * @param {!UI.SearchableView.SearchConfig} searchConfig
572 * @param {string} replacement
573 */
574 replaceAllWith(searchConfig, replacement) {}
575};
576
577/**
578 * @unrestricted
579 */
580UI.SearchableView.SearchConfig = class {
581 /**
582 * @param {string} query
583 * @param {boolean} caseSensitive
584 * @param {boolean} isRegex
585 */
586 constructor(query, caseSensitive, isRegex) {
587 this.query = query;
588 this.caseSensitive = caseSensitive;
589 this.isRegex = isRegex;
590 }
591
592 /**
593 * @param {boolean=} global
594 * @return {!RegExp}
595 */
596 toSearchRegex(global) {
597 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34598 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37599 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34600 }
Blink Reformat4c46d092018-04-07 15:32:37601 const query = this.isRegex ? '/' + this.query + '/' : this.query;
602
603 let regex;
604
605 // First try creating regex if user knows the / / hint.
606 try {
607 if (/^\/.+\/$/.test(query)) {
608 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
609 regex.__fromRegExpQuery = true;
610 }
611 } catch (e) {
612 // Silent catch.
613 }
614
615 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34616 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37617 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34618 }
Blink Reformat4c46d092018-04-07 15:32:37619
620 return regex;
621 }
622};