blob: 85df40947694fea7e0e50397a14906dd7f5680fa [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
Paul Lewis9950e182019-12-16 16:06:0732import {HistoryInput} from './HistoryInput.js';
33import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
34import {createTextButton} from './UIUtils.js';
35import {VBox} from './Widget.js';
36
Blink Reformat4c46d092018-04-07 15:32:3737/**
38 * @unrestricted
39 */
Paul Lewis9950e182019-12-16 16:06:0740export class SearchableView extends VBox {
Blink Reformat4c46d092018-04-07 15:32:3741 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0742 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3743 * @param {string=} settingName
44 */
45 constructor(searchable, settingName) {
46 super(true);
47 this.registerRequiredCSS('ui/searchableView.css');
Tim van der Lippe0830b3d2019-10-03 13:20:0748 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3749
50 this._searchProvider = searchable;
51 this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null;
52 this._replaceable = false;
53
Joel Einbinder7fbe24c2019-01-24 05:19:0154 this.contentElement.createChild('slot');
Blink Reformat4c46d092018-04-07 15:32:3755 this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
56 this._footerElementContainer.style.order = 100;
57 this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
58
Paul Lewis9950e182019-12-16 16:06:0759 const replaceToggleToolbar = new Toolbar('replace-toggle-toolbar', this._footerElement);
60 this._replaceToggleButton = new ToolbarToggle(Common.UIString('Replace'), 'mediumicon-replace');
61 this._replaceToggleButton.addEventListener(ToolbarButton.Events.Click, this._toggleReplace, this);
Blink Reformat4c46d092018-04-07 15:32:3762 replaceToggleToolbar.appendToolbarItem(this._replaceToggleButton);
63
64 const searchInputElements = this._footerElement.createChild('div', 'toolbar-search-inputs');
65 const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
66
Paul Lewis9950e182019-12-16 16:06:0767 this._searchInputElement = HistoryInput.create();
Blink Reformat4c46d092018-04-07 15:32:3768 this._searchInputElement.classList.add('search-replace');
69 this._searchInputElement.id = 'search-input-field';
70 this._searchInputElement.placeholder = Common.UIString('Find');
71 searchControlElement.appendChild(this._searchInputElement);
72
73 this._matchesElement = searchControlElement.createChild('label', 'search-results-matches');
74 this._matchesElement.setAttribute('for', 'search-input-field');
75
76 const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
77
78 this._searchNavigationPrevElement =
79 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
80 this._searchNavigationPrevElement.addEventListener('click', this._onPrevButtonSearch.bind(this), false);
81 this._searchNavigationPrevElement.title = Common.UIString('Search previous');
82
83 this._searchNavigationNextElement =
84 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
85 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
86 this._searchNavigationNextElement.title = Common.UIString('Search next');
87
88 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
89 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
90
91 this._replaceInputElement =
92 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
93 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
94 this._replaceInputElement.placeholder = Common.UIString('Replace');
95
96 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
97 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
98
Paul Lewis9950e182019-12-16 16:06:0799 const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
Blink Reformat4c46d092018-04-07 15:32:37100
101 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Paul Lewis9950e182019-12-16 16:06:07102 this._caseSensitiveButton = new ToolbarToggle(Common.UIString('Match Case'));
Blink Reformat4c46d092018-04-07 15:32:37103 this._caseSensitiveButton.setText('Aa');
Paul Lewis9950e182019-12-16 16:06:07104 this._caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37105 toolbar.appendToolbarItem(this._caseSensitiveButton);
106 }
107
108 if (this._searchProvider.supportsRegexSearch()) {
Paul Lewis9950e182019-12-16 16:06:07109 this._regexButton = new ToolbarToggle(Common.UIString('Use Regular Expression'));
Blink Reformat4c46d092018-04-07 15:32:37110 this._regexButton.setText('.*');
Paul Lewis9950e182019-12-16 16:06:07111 this._regexButton.addEventListener(ToolbarButton.Events.Click, this._toggleRegexSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37112 toolbar.appendToolbarItem(this._regexButton);
113 }
114
115 const cancelButtonElement =
Paul Lewis9950e182019-12-16 16:06:07116 createTextButton(Common.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37117 firstRowButtons.appendChild(cancelButtonElement);
118
119 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
120
121 this._replaceButtonElement =
Paul Lewis9950e182019-12-16 16:06:07122 createTextButton(Common.UIString('Replace'), this._replace.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37123 this._replaceButtonElement.disabled = true;
124 this._secondRowButtons.appendChild(this._replaceButtonElement);
125
126 this._replaceAllButtonElement =
Paul Lewis9950e182019-12-16 16:06:07127 createTextButton(Common.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37128 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
129 this._replaceAllButtonElement.disabled = true;
130
131 this._minimalSearchQuerySize = 3;
132 this._loadSetting();
133 }
134
135 /**
136 * @param {?Element} element
Tim van der Lippe0830b3d2019-10-03 13:20:07137 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37138 */
139 static fromElement(element) {
140 let view = null;
141 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07142 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37143 element = element.parentElementOrShadowHost();
144 }
145 return view;
146 }
147
148 _toggleCaseSensitiveSearch() {
149 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
150 this._saveSetting();
151 this._performSearch(false, true);
152 }
153
154 _toggleRegexSearch() {
155 this._regexButton.setToggled(!this._regexButton.toggled());
156 this._saveSetting();
157 this._performSearch(false, true);
158 }
159
160 _toggleReplace() {
161 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
162 this._updateSecondRowVisibility();
163 }
164
165 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34166 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37167 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 }
Blink Reformat4c46d092018-04-07 15:32:37169 const settingValue = this._setting.get() || {};
170 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
171 settingValue.isRegex = this._regexButton.toggled();
172 this._setting.set(settingValue);
173 }
174
175 _loadSetting() {
176 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34177 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37178 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34179 }
180 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37181 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34182 }
Blink Reformat4c46d092018-04-07 15:32:37183 }
184
185 /**
186 * @param {number} minimalSearchQuerySize
187 */
188 setMinimalSearchQuerySize(minimalSearchQuerySize) {
189 this._minimalSearchQuerySize = minimalSearchQuerySize;
190 }
191
192 /**
193 * @param {string} placeholder
194 */
195 setPlaceholder(placeholder) {
196 this._searchInputElement.placeholder = placeholder;
197 }
198
199 /**
200 * @param {boolean} replaceable
201 */
202 setReplaceable(replaceable) {
203 this._replaceable = replaceable;
204 }
205
206 /**
207 * @param {number} matches
Tim van der Lippe0830b3d2019-10-03 13:20:07208 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37209 */
210 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34211 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37212 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34213 }
Blink Reformat4c46d092018-04-07 15:32:37214 this._searchProvider.currentSearchMatches = matches;
215 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
216 }
217
218 /**
219 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07220 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37221 */
222 updateCurrentMatchIndex(currentMatchIndex) {
223 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
224 }
225
226 /**
227 * @return {boolean}
228 */
229 isSearchVisible() {
230 return this._searchIsVisible;
231 }
232
233 closeSearch() {
234 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34235 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37236 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34237 }
Blink Reformat4c46d092018-04-07 15:32:37238 }
239
240 _toggleSearchBar(toggled) {
241 this._footerElementContainer.classList.toggle('hidden', !toggled);
242 this.doResize();
243 }
244
245 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34246 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37247 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34248 }
Blink Reformat4c46d092018-04-07 15:32:37249 this.resetSearch();
250 delete this._searchIsVisible;
251 this._toggleSearchBar(false);
252 }
253
254 resetSearch() {
255 this._clearSearch();
256 this._updateReplaceVisibility();
257 this._matchesElement.textContent = '';
258 }
259
260 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37262 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34263 }
Blink Reformat4c46d092018-04-07 15:32:37264 this.resetSearch();
265 this._performSearch(false, false);
266 }
267
268 /**
269 * @return {boolean}
270 */
271 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34272 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37273 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34274 }
Blink Reformat4c46d092018-04-07 15:32:37275 this._searchProvider.jumpToNextSearchResult();
276 return true;
277 }
278
279 /**
280 * @return {boolean}
281 */
282 handleFindPreviousShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34283 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37284 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34285 }
Blink Reformat4c46d092018-04-07 15:32:37286 this._searchProvider.jumpToPreviousSearchResult();
287 return true;
288 }
289
290 /**
291 * @return {boolean}
292 */
293 handleFindShortcut() {
294 this.showSearchField();
295 return true;
296 }
297
298 /**
299 * @return {boolean}
300 */
301 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34302 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37303 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34304 }
Blink Reformat4c46d092018-04-07 15:32:37305 this.closeSearch();
306 return true;
307 }
308
309 /**
310 * @param {boolean} enabled
311 */
312 _updateSearchNavigationButtonState(enabled) {
313 this._replaceButtonElement.disabled = !enabled;
314 this._replaceAllButtonElement.disabled = !enabled;
315 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
316 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
317 }
318
319 /**
320 * @param {number} matches
321 * @param {number} currentMatchIndex
322 */
323 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34324 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37325 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34326 } else if (matches === 0 || currentMatchIndex >= 0) {
Blink Reformat4c46d092018-04-07 15:32:37327 this._matchesElement.textContent = Common.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34328 } else if (matches === 1) {
Blink Reformat4c46d092018-04-07 15:32:37329 this._matchesElement.textContent = Common.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34330 } else {
Blink Reformat4c46d092018-04-07 15:32:37331 this._matchesElement.textContent = Common.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 }
Blink Reformat4c46d092018-04-07 15:32:37333 this._updateSearchNavigationButtonState(matches > 0);
334 }
335
336 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34337 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37338 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34339 }
Blink Reformat4c46d092018-04-07 15:32:37340
341 let queryCandidate;
342 if (!this._searchInputElement.hasFocus()) {
343 const selection = UI.inspectorView.element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37345 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 }
Blink Reformat4c46d092018-04-07 15:32:37347 }
348
349 this._toggleSearchBar(true);
350 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34351 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37352 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 }
Blink Reformat4c46d092018-04-07 15:32:37354 this._performSearch(false, false);
355 this._searchInputElement.focus();
356 this._searchInputElement.select();
357 this._searchIsVisible = true;
358 }
359
360 _updateReplaceVisibility() {
361 this._replaceToggleButton.setVisible(this._replaceable);
362 if (!this._replaceable) {
363 this._replaceToggleButton.setToggled(false);
364 this._updateSecondRowVisibility();
365 }
366 }
367
368 /**
369 * @param {!Event} event
370 */
371 _onSearchKeyDown(event) {
372 if (isEscKey(event)) {
373 this.closeSearch();
374 event.consume(true);
375 return;
376 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34377 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37378 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34379 }
Blink Reformat4c46d092018-04-07 15:32:37380
Tim van der Lippe1d6e57a2019-09-30 11:55:34381 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37382 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34383 } else {
Blink Reformat4c46d092018-04-07 15:32:37384 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34385 }
Blink Reformat4c46d092018-04-07 15:32:37386 }
387
388 /**
389 * @param {!Event} event
390 */
391 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34392 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37393 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34394 }
Blink Reformat4c46d092018-04-07 15:32:37395 }
396
397 /**
398 * @param {boolean=} isBackwardSearch
399 */
400 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34401 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37402 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34403 }
Blink Reformat4c46d092018-04-07 15:32:37404
Tim van der Lippe1d6e57a2019-09-30 11:55:34405 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37406 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 } else {
Blink Reformat4c46d092018-04-07 15:32:37408 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 }
Blink Reformat4c46d092018-04-07 15:32:37410 }
411
412 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34413 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37414 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 }
Blink Reformat4c46d092018-04-07 15:32:37416 this._jumpToNextSearchResult();
417 this._searchInputElement.focus();
418 }
419
420 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34421 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37422 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34423 }
Blink Reformat4c46d092018-04-07 15:32:37424 this._jumpToNextSearchResult(true);
425 this._searchInputElement.focus();
426 }
427
428 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34429 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37430 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34431 } else {
Blink Reformat4c46d092018-04-07 15:32:37432 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34433 }
Blink Reformat4c46d092018-04-07 15:32:37434 this._searchInputElement.focus();
435 }
436
437 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34438 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37439 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34440 } else {
Blink Reformat4c46d092018-04-07 15:32:37441 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34442 }
Blink Reformat4c46d092018-04-07 15:32:37443 this._searchInputElement.focus();
444 }
445
Tim van der Lippe0830b3d2019-10-03 13:20:07446 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37447 _clearSearch() {
448 delete this._currentQuery;
449 if (!!this._searchProvider.currentQuery) {
450 delete this._searchProvider.currentQuery;
451 this._searchProvider.searchCanceled();
452 }
453 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
454 }
455
456 /**
457 * @param {boolean} forceSearch
458 * @param {boolean} shouldJump
459 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07460 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37461 */
462 _performSearch(forceSearch, shouldJump, jumpBackwards) {
463 const query = this._searchInputElement.value;
464 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
465 this._clearSearch();
466 return;
467 }
468
469 this._currentQuery = query;
470 this._searchProvider.currentQuery = query;
471
472 const searchConfig = this._currentSearchConfig();
473 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
474 }
475
476 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07477 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37478 */
479 _currentSearchConfig() {
480 const query = this._searchInputElement.value;
481 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
482 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07483 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37484 }
485
486 _updateSecondRowVisibility() {
487 const secondRowVisible = this._replaceToggleButton.toggled();
488 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
489 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
490 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
491
Tim van der Lippe1d6e57a2019-09-30 11:55:34492 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37493 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34494 } else {
Blink Reformat4c46d092018-04-07 15:32:37495 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34496 }
Blink Reformat4c46d092018-04-07 15:32:37497 this.doResize();
498 }
499
500 _replace() {
501 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07502 /** @type {!Replaceable} */ (this._searchProvider)
Blink Reformat4c46d092018-04-07 15:32:37503 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
504 delete this._currentQuery;
505 this._performSearch(true, true);
506 }
507
508 _replaceAll() {
509 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07510 /** @type {!Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
Blink Reformat4c46d092018-04-07 15:32:37511 }
512
513 /**
514 * @param {!Event} event
515 */
516 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34517 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37518 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34519 }
Blink Reformat4c46d092018-04-07 15:32:37520 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
521 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
522 }
523
524 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34525 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37526 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34527 }
Blink Reformat4c46d092018-04-07 15:32:37528 delete this._valueChangedTimeoutId;
529 this._performSearch(false, true);
530 }
Tim van der Lippe0830b3d2019-10-03 13:20:07531}
Blink Reformat4c46d092018-04-07 15:32:37532
Tim van der Lippe0830b3d2019-10-03 13:20:07533export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37534
535
536/**
537 * @interface
538 */
Tim van der Lippe0830b3d2019-10-03 13:20:07539export class Searchable {
540 searchCanceled() {
541 }
Blink Reformat4c46d092018-04-07 15:32:37542
543 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07544 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37545 * @param {boolean} shouldJump
546 * @param {boolean=} jumpBackwards
547 */
Tim van der Lippe0830b3d2019-10-03 13:20:07548 performSearch(searchConfig, shouldJump, jumpBackwards) {
549 }
Blink Reformat4c46d092018-04-07 15:32:37550
Tim van der Lippe0830b3d2019-10-03 13:20:07551 jumpToNextSearchResult() {
552 }
Blink Reformat4c46d092018-04-07 15:32:37553
Tim van der Lippe0830b3d2019-10-03 13:20:07554 jumpToPreviousSearchResult() {
555 }
Blink Reformat4c46d092018-04-07 15:32:37556
557 /**
558 * @return {boolean}
559 */
Tim van der Lippe0830b3d2019-10-03 13:20:07560 supportsCaseSensitiveSearch() {
561 }
Blink Reformat4c46d092018-04-07 15:32:37562
563 /**
564 * @return {boolean}
565 */
566 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07567}
Blink Reformat4c46d092018-04-07 15:32:37568
569/**
570 * @interface
571 */
Tim van der Lippe0830b3d2019-10-03 13:20:07572export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37573 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07574 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37575 * @param {string} replacement
576 */
Tim van der Lippe0830b3d2019-10-03 13:20:07577 replaceSelectionWith(searchConfig, replacement) {
578 }
Blink Reformat4c46d092018-04-07 15:32:37579
580 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07581 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37582 * @param {string} replacement
583 */
584 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07585}
Blink Reformat4c46d092018-04-07 15:32:37586
587/**
588 * @unrestricted
589 */
Tim van der Lippe0830b3d2019-10-03 13:20:07590export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37591 /**
592 * @param {string} query
593 * @param {boolean} caseSensitive
594 * @param {boolean} isRegex
595 */
596 constructor(query, caseSensitive, isRegex) {
597 this.query = query;
598 this.caseSensitive = caseSensitive;
599 this.isRegex = isRegex;
600 }
601
602 /**
603 * @param {boolean=} global
604 * @return {!RegExp}
605 */
606 toSearchRegex(global) {
607 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34608 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37609 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34610 }
Blink Reformat4c46d092018-04-07 15:32:37611 const query = this.isRegex ? '/' + this.query + '/' : this.query;
612
613 let regex;
614
615 // First try creating regex if user knows the / / hint.
616 try {
617 if (/^\/.+\/$/.test(query)) {
618 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
619 regex.__fromRegExpQuery = true;
620 }
621 } catch (e) {
622 // Silent catch.
623 }
624
625 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34626 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37627 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34628 }
Blink Reformat4c46d092018-04-07 15:32:37629
630 return regex;
631 }
Tim van der Lippe0830b3d2019-10-03 13:20:07632}