blob: 132375c6ec68dcbf1abb92860bc99cfce06885fb [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 */
Tim van der Lippe0830b3d2019-10-03 13:20:0735export default class SearchableView extends UI.VBox {
Blink Reformat4c46d092018-04-07 15:32:3736 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0737 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3738 * @param {string=} settingName
39 */
40 constructor(searchable, settingName) {
41 super(true);
42 this.registerRequiredCSS('ui/searchableView.css');
Tim van der Lippe0830b3d2019-10-03 13:20:0743 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3744
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
Tim van der Lippe0830b3d2019-10-03 13:20:07132 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37133 */
134 static fromElement(element) {
135 let view = null;
136 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07137 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37138 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
Tim van der Lippe0830b3d2019-10-03 13:20:07203 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37204 */
205 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34206 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37207 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34208 }
Blink Reformat4c46d092018-04-07 15:32:37209 this._searchProvider.currentSearchMatches = matches;
210 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
211 }
212
213 /**
214 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07215 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37216 */
217 updateCurrentMatchIndex(currentMatchIndex) {
218 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
219 }
220
221 /**
222 * @return {boolean}
223 */
224 isSearchVisible() {
225 return this._searchIsVisible;
226 }
227
228 closeSearch() {
229 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34230 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37231 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34232 }
Blink Reformat4c46d092018-04-07 15:32:37233 }
234
235 _toggleSearchBar(toggled) {
236 this._footerElementContainer.classList.toggle('hidden', !toggled);
237 this.doResize();
238 }
239
240 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34241 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37242 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34243 }
Blink Reformat4c46d092018-04-07 15:32:37244 this.resetSearch();
245 delete this._searchIsVisible;
246 this._toggleSearchBar(false);
247 }
248
249 resetSearch() {
250 this._clearSearch();
251 this._updateReplaceVisibility();
252 this._matchesElement.textContent = '';
253 }
254
255 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34256 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37257 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34258 }
Blink Reformat4c46d092018-04-07 15:32:37259 this.resetSearch();
260 this._performSearch(false, false);
261 }
262
263 /**
264 * @return {boolean}
265 */
266 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34267 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37268 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34269 }
Blink Reformat4c46d092018-04-07 15:32:37270 this._searchProvider.jumpToNextSearchResult();
271 return true;
272 }
273
274 /**
275 * @return {boolean}
276 */
277 handleFindPreviousShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34278 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37279 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34280 }
Blink Reformat4c46d092018-04-07 15:32:37281 this._searchProvider.jumpToPreviousSearchResult();
282 return true;
283 }
284
285 /**
286 * @return {boolean}
287 */
288 handleFindShortcut() {
289 this.showSearchField();
290 return true;
291 }
292
293 /**
294 * @return {boolean}
295 */
296 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34297 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37298 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34299 }
Blink Reformat4c46d092018-04-07 15:32:37300 this.closeSearch();
301 return true;
302 }
303
304 /**
305 * @param {boolean} enabled
306 */
307 _updateSearchNavigationButtonState(enabled) {
308 this._replaceButtonElement.disabled = !enabled;
309 this._replaceAllButtonElement.disabled = !enabled;
310 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
311 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
312 }
313
314 /**
315 * @param {number} matches
316 * @param {number} currentMatchIndex
317 */
318 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34319 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37320 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34321 } else if (matches === 0 || currentMatchIndex >= 0) {
Blink Reformat4c46d092018-04-07 15:32:37322 this._matchesElement.textContent = Common.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34323 } else if (matches === 1) {
Blink Reformat4c46d092018-04-07 15:32:37324 this._matchesElement.textContent = Common.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34325 } else {
Blink Reformat4c46d092018-04-07 15:32:37326 this._matchesElement.textContent = Common.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34327 }
Blink Reformat4c46d092018-04-07 15:32:37328 this._updateSearchNavigationButtonState(matches > 0);
329 }
330
331 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37333 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34334 }
Blink Reformat4c46d092018-04-07 15:32:37335
336 let queryCandidate;
337 if (!this._searchInputElement.hasFocus()) {
338 const selection = UI.inspectorView.element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34339 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37340 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34341 }
Blink Reformat4c46d092018-04-07 15:32:37342 }
343
344 this._toggleSearchBar(true);
345 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37347 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34348 }
Blink Reformat4c46d092018-04-07 15:32:37349 this._performSearch(false, false);
350 this._searchInputElement.focus();
351 this._searchInputElement.select();
352 this._searchIsVisible = true;
353 }
354
355 _updateReplaceVisibility() {
356 this._replaceToggleButton.setVisible(this._replaceable);
357 if (!this._replaceable) {
358 this._replaceToggleButton.setToggled(false);
359 this._updateSecondRowVisibility();
360 }
361 }
362
363 /**
364 * @param {!Event} event
365 */
366 _onSearchKeyDown(event) {
367 if (isEscKey(event)) {
368 this.closeSearch();
369 event.consume(true);
370 return;
371 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34372 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37373 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34374 }
Blink Reformat4c46d092018-04-07 15:32:37375
Tim van der Lippe1d6e57a2019-09-30 11:55:34376 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37377 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34378 } else {
Blink Reformat4c46d092018-04-07 15:32:37379 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34380 }
Blink Reformat4c46d092018-04-07 15:32:37381 }
382
383 /**
384 * @param {!Event} event
385 */
386 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37388 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34389 }
Blink Reformat4c46d092018-04-07 15:32:37390 }
391
392 /**
393 * @param {boolean=} isBackwardSearch
394 */
395 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34396 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37397 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34398 }
Blink Reformat4c46d092018-04-07 15:32:37399
Tim van der Lippe1d6e57a2019-09-30 11:55:34400 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37401 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34402 } else {
Blink Reformat4c46d092018-04-07 15:32:37403 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34404 }
Blink Reformat4c46d092018-04-07 15:32:37405 }
406
407 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37409 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34410 }
Blink Reformat4c46d092018-04-07 15:32:37411 this._jumpToNextSearchResult();
412 this._searchInputElement.focus();
413 }
414
415 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34416 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37417 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34418 }
Blink Reformat4c46d092018-04-07 15:32:37419 this._jumpToNextSearchResult(true);
420 this._searchInputElement.focus();
421 }
422
423 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34424 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37425 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34426 } else {
Blink Reformat4c46d092018-04-07 15:32:37427 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34428 }
Blink Reformat4c46d092018-04-07 15:32:37429 this._searchInputElement.focus();
430 }
431
432 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34433 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37434 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34435 } else {
Blink Reformat4c46d092018-04-07 15:32:37436 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34437 }
Blink Reformat4c46d092018-04-07 15:32:37438 this._searchInputElement.focus();
439 }
440
Tim van der Lippe0830b3d2019-10-03 13:20:07441 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37442 _clearSearch() {
443 delete this._currentQuery;
444 if (!!this._searchProvider.currentQuery) {
445 delete this._searchProvider.currentQuery;
446 this._searchProvider.searchCanceled();
447 }
448 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
449 }
450
451 /**
452 * @param {boolean} forceSearch
453 * @param {boolean} shouldJump
454 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07455 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37456 */
457 _performSearch(forceSearch, shouldJump, jumpBackwards) {
458 const query = this._searchInputElement.value;
459 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
460 this._clearSearch();
461 return;
462 }
463
464 this._currentQuery = query;
465 this._searchProvider.currentQuery = query;
466
467 const searchConfig = this._currentSearchConfig();
468 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
469 }
470
471 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07472 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37473 */
474 _currentSearchConfig() {
475 const query = this._searchInputElement.value;
476 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
477 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07478 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37479 }
480
481 _updateSecondRowVisibility() {
482 const secondRowVisible = this._replaceToggleButton.toggled();
483 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
484 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
485 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
486
Tim van der Lippe1d6e57a2019-09-30 11:55:34487 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37488 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34489 } else {
Blink Reformat4c46d092018-04-07 15:32:37490 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34491 }
Blink Reformat4c46d092018-04-07 15:32:37492 this.doResize();
493 }
494
495 _replace() {
496 const searchConfig = this._currentSearchConfig();
497 /** @type {!UI.Replaceable} */ (this._searchProvider)
498 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
499 delete this._currentQuery;
500 this._performSearch(true, true);
501 }
502
503 _replaceAll() {
504 const searchConfig = this._currentSearchConfig();
505 /** @type {!UI.Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
506 }
507
508 /**
509 * @param {!Event} event
510 */
511 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34512 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37513 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34514 }
Blink Reformat4c46d092018-04-07 15:32:37515 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
516 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
517 }
518
519 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34520 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37521 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34522 }
Blink Reformat4c46d092018-04-07 15:32:37523 delete this._valueChangedTimeoutId;
524 this._performSearch(false, true);
525 }
Tim van der Lippe0830b3d2019-10-03 13:20:07526}
Blink Reformat4c46d092018-04-07 15:32:37527
Tim van der Lippe0830b3d2019-10-03 13:20:07528export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37529
530
531/**
532 * @interface
533 */
Tim van der Lippe0830b3d2019-10-03 13:20:07534export class Searchable {
535 searchCanceled() {
536 }
Blink Reformat4c46d092018-04-07 15:32:37537
538 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07539 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37540 * @param {boolean} shouldJump
541 * @param {boolean=} jumpBackwards
542 */
Tim van der Lippe0830b3d2019-10-03 13:20:07543 performSearch(searchConfig, shouldJump, jumpBackwards) {
544 }
Blink Reformat4c46d092018-04-07 15:32:37545
Tim van der Lippe0830b3d2019-10-03 13:20:07546 jumpToNextSearchResult() {
547 }
Blink Reformat4c46d092018-04-07 15:32:37548
Tim van der Lippe0830b3d2019-10-03 13:20:07549 jumpToPreviousSearchResult() {
550 }
Blink Reformat4c46d092018-04-07 15:32:37551
552 /**
553 * @return {boolean}
554 */
Tim van der Lippe0830b3d2019-10-03 13:20:07555 supportsCaseSensitiveSearch() {
556 }
Blink Reformat4c46d092018-04-07 15:32:37557
558 /**
559 * @return {boolean}
560 */
561 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07562}
Blink Reformat4c46d092018-04-07 15:32:37563
564/**
565 * @interface
566 */
Tim van der Lippe0830b3d2019-10-03 13:20:07567export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37568 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07569 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37570 * @param {string} replacement
571 */
Tim van der Lippe0830b3d2019-10-03 13:20:07572 replaceSelectionWith(searchConfig, replacement) {
573 }
Blink Reformat4c46d092018-04-07 15:32:37574
575 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07576 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37577 * @param {string} replacement
578 */
579 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07580}
Blink Reformat4c46d092018-04-07 15:32:37581
582/**
583 * @unrestricted
584 */
Tim van der Lippe0830b3d2019-10-03 13:20:07585export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37586 /**
587 * @param {string} query
588 * @param {boolean} caseSensitive
589 * @param {boolean} isRegex
590 */
591 constructor(query, caseSensitive, isRegex) {
592 this.query = query;
593 this.caseSensitive = caseSensitive;
594 this.isRegex = isRegex;
595 }
596
597 /**
598 * @param {boolean=} global
599 * @return {!RegExp}
600 */
601 toSearchRegex(global) {
602 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34603 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37604 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34605 }
Blink Reformat4c46d092018-04-07 15:32:37606 const query = this.isRegex ? '/' + this.query + '/' : this.query;
607
608 let regex;
609
610 // First try creating regex if user knows the / / hint.
611 try {
612 if (/^\/.+\/$/.test(query)) {
613 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
614 regex.__fromRegExpQuery = true;
615 }
616 } catch (e) {
617 // Silent catch.
618 }
619
620 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34621 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37622 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34623 }
Blink Reformat4c46d092018-04-07 15:32:37624
625 return regex;
626 }
Tim van der Lippe0830b3d2019-10-03 13:20:07627}
628
629/* Legacy exported object*/
630self.UI = self.UI || {};
631
632/* Legacy exported object*/
633UI = UI || {};
634
635/** @constructor */
636UI.SearchableView = SearchableView;
637
638/**
639 * @constructor
640 */
641UI.SearchableView.SearchConfig = SearchConfig;
642
643/** @interface */
644UI.Searchable = Searchable;
645
646/** @interface */
647UI.Replaceable = Replaceable;