blob: 44cc0522650153b928478b21e22895525418d233 [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 Lewis17e384e2020-01-08 15:46:5132import * as Common from '../common/common.js';
Paul Lewis9950e182019-12-16 16:06:0733import {HistoryInput} from './HistoryInput.js';
34import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
35import {createTextButton} from './UIUtils.js';
36import {VBox} from './Widget.js';
37
Blink Reformat4c46d092018-04-07 15:32:3738/**
39 * @unrestricted
40 */
Paul Lewis9950e182019-12-16 16:06:0741export class SearchableView extends VBox {
Blink Reformat4c46d092018-04-07 15:32:3742 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0743 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3744 * @param {string=} settingName
45 */
46 constructor(searchable, settingName) {
47 super(true);
48 this.registerRequiredCSS('ui/searchableView.css');
Tim van der Lippe0830b3d2019-10-03 13:20:0749 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3750
51 this._searchProvider = searchable;
Paul Lewis17e384e2020-01-08 15:46:5152 // Note: go via self.Common for globally-namespaced singletons.
53 this._setting = settingName ? self.Common.settings.createSetting(settingName, {}) : null;
Blink Reformat4c46d092018-04-07 15:32:3754 this._replaceable = false;
55
Joel Einbinder7fbe24c2019-01-24 05:19:0156 this.contentElement.createChild('slot');
Blink Reformat4c46d092018-04-07 15:32:3757 this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
58 this._footerElementContainer.style.order = 100;
59 this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
60
Paul Lewis9950e182019-12-16 16:06:0761 const replaceToggleToolbar = new Toolbar('replace-toggle-toolbar', this._footerElement);
Paul Lewis17e384e2020-01-08 15:46:5162 this._replaceToggleButton = new ToolbarToggle(Common.UIString.UIString('Replace'), 'mediumicon-replace');
Paul Lewis9950e182019-12-16 16:06:0763 this._replaceToggleButton.addEventListener(ToolbarButton.Events.Click, this._toggleReplace, this);
Blink Reformat4c46d092018-04-07 15:32:3764 replaceToggleToolbar.appendToolbarItem(this._replaceToggleButton);
65
66 const searchInputElements = this._footerElement.createChild('div', 'toolbar-search-inputs');
67 const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
68
Paul Lewis9950e182019-12-16 16:06:0769 this._searchInputElement = HistoryInput.create();
Blink Reformat4c46d092018-04-07 15:32:3770 this._searchInputElement.classList.add('search-replace');
71 this._searchInputElement.id = 'search-input-field';
Paul Lewis17e384e2020-01-08 15:46:5172 this._searchInputElement.placeholder = Common.UIString.UIString('Find');
Blink Reformat4c46d092018-04-07 15:32:3773 searchControlElement.appendChild(this._searchInputElement);
74
75 this._matchesElement = searchControlElement.createChild('label', 'search-results-matches');
76 this._matchesElement.setAttribute('for', 'search-input-field');
77
78 const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
79
80 this._searchNavigationPrevElement =
81 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
82 this._searchNavigationPrevElement.addEventListener('click', this._onPrevButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5183 this._searchNavigationPrevElement.title = Common.UIString.UIString('Search previous');
Blink Reformat4c46d092018-04-07 15:32:3784
85 this._searchNavigationNextElement =
86 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
87 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5188 this._searchNavigationNextElement.title = Common.UIString.UIString('Search next');
Blink Reformat4c46d092018-04-07 15:32:3789
90 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
91 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
92
93 this._replaceInputElement =
94 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
95 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
Paul Lewis17e384e2020-01-08 15:46:5196 this._replaceInputElement.placeholder = Common.UIString.UIString('Replace');
Blink Reformat4c46d092018-04-07 15:32:3797
98 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
99 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
100
Paul Lewis9950e182019-12-16 16:06:07101 const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
Blink Reformat4c46d092018-04-07 15:32:37102
103 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51104 this._caseSensitiveButton = new ToolbarToggle(Common.UIString.UIString('Match Case'));
Blink Reformat4c46d092018-04-07 15:32:37105 this._caseSensitiveButton.setText('Aa');
Paul Lewis9950e182019-12-16 16:06:07106 this._caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37107 toolbar.appendToolbarItem(this._caseSensitiveButton);
108 }
109
110 if (this._searchProvider.supportsRegexSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51111 this._regexButton = new ToolbarToggle(Common.UIString.UIString('Use Regular Expression'));
Blink Reformat4c46d092018-04-07 15:32:37112 this._regexButton.setText('.*');
Paul Lewis9950e182019-12-16 16:06:07113 this._regexButton.addEventListener(ToolbarButton.Events.Click, this._toggleRegexSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37114 toolbar.appendToolbarItem(this._regexButton);
115 }
116
117 const cancelButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51118 createTextButton(Common.UIString.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37119 firstRowButtons.appendChild(cancelButtonElement);
120
121 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
122
123 this._replaceButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51124 createTextButton(Common.UIString.UIString('Replace'), this._replace.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37125 this._replaceButtonElement.disabled = true;
126 this._secondRowButtons.appendChild(this._replaceButtonElement);
127
128 this._replaceAllButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51129 createTextButton(Common.UIString.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37130 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
131 this._replaceAllButtonElement.disabled = true;
132
133 this._minimalSearchQuerySize = 3;
134 this._loadSetting();
135 }
136
137 /**
138 * @param {?Element} element
Tim van der Lippe0830b3d2019-10-03 13:20:07139 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37140 */
141 static fromElement(element) {
142 let view = null;
143 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07144 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37145 element = element.parentElementOrShadowHost();
146 }
147 return view;
148 }
149
150 _toggleCaseSensitiveSearch() {
151 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
152 this._saveSetting();
153 this._performSearch(false, true);
154 }
155
156 _toggleRegexSearch() {
157 this._regexButton.setToggled(!this._regexButton.toggled());
158 this._saveSetting();
159 this._performSearch(false, true);
160 }
161
162 _toggleReplace() {
163 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
164 this._updateSecondRowVisibility();
165 }
166
167 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37169 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34170 }
Blink Reformat4c46d092018-04-07 15:32:37171 const settingValue = this._setting.get() || {};
172 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
173 settingValue.isRegex = this._regexButton.toggled();
174 this._setting.set(settingValue);
175 }
176
177 _loadSetting() {
178 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34179 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37180 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34181 }
182 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37183 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34184 }
Blink Reformat4c46d092018-04-07 15:32:37185 }
186
187 /**
188 * @param {number} minimalSearchQuerySize
189 */
190 setMinimalSearchQuerySize(minimalSearchQuerySize) {
191 this._minimalSearchQuerySize = minimalSearchQuerySize;
192 }
193
194 /**
195 * @param {string} placeholder
196 */
197 setPlaceholder(placeholder) {
198 this._searchInputElement.placeholder = placeholder;
199 }
200
201 /**
202 * @param {boolean} replaceable
203 */
204 setReplaceable(replaceable) {
205 this._replaceable = replaceable;
206 }
207
208 /**
209 * @param {number} matches
Tim van der Lippe0830b3d2019-10-03 13:20:07210 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37211 */
212 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34213 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37214 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34215 }
Blink Reformat4c46d092018-04-07 15:32:37216 this._searchProvider.currentSearchMatches = matches;
217 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
218 }
219
220 /**
221 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07222 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37223 */
224 updateCurrentMatchIndex(currentMatchIndex) {
225 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
226 }
227
228 /**
229 * @return {boolean}
230 */
231 isSearchVisible() {
232 return this._searchIsVisible;
233 }
234
235 closeSearch() {
236 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34237 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37238 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 }
Blink Reformat4c46d092018-04-07 15:32:37240 }
241
242 _toggleSearchBar(toggled) {
243 this._footerElementContainer.classList.toggle('hidden', !toggled);
244 this.doResize();
245 }
246
247 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34248 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37249 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34250 }
Blink Reformat4c46d092018-04-07 15:32:37251 this.resetSearch();
252 delete this._searchIsVisible;
253 this._toggleSearchBar(false);
254 }
255
256 resetSearch() {
257 this._clearSearch();
258 this._updateReplaceVisibility();
259 this._matchesElement.textContent = '';
260 }
261
262 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34263 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37264 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34265 }
Blink Reformat4c46d092018-04-07 15:32:37266 this.resetSearch();
267 this._performSearch(false, false);
268 }
269
270 /**
271 * @return {boolean}
272 */
273 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34274 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37275 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34276 }
Blink Reformat4c46d092018-04-07 15:32:37277 this._searchProvider.jumpToNextSearchResult();
278 return true;
279 }
280
281 /**
282 * @return {boolean}
283 */
284 handleFindPreviousShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34285 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37286 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34287 }
Blink Reformat4c46d092018-04-07 15:32:37288 this._searchProvider.jumpToPreviousSearchResult();
289 return true;
290 }
291
292 /**
293 * @return {boolean}
294 */
295 handleFindShortcut() {
296 this.showSearchField();
297 return true;
298 }
299
300 /**
301 * @return {boolean}
302 */
303 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34304 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37305 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34306 }
Blink Reformat4c46d092018-04-07 15:32:37307 this.closeSearch();
308 return true;
309 }
310
311 /**
312 * @param {boolean} enabled
313 */
314 _updateSearchNavigationButtonState(enabled) {
315 this._replaceButtonElement.disabled = !enabled;
316 this._replaceAllButtonElement.disabled = !enabled;
317 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
318 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
319 }
320
321 /**
322 * @param {number} matches
323 * @param {number} currentMatchIndex
324 */
325 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34326 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37327 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34328 } else if (matches === 0 || currentMatchIndex >= 0) {
Paul Lewis17e384e2020-01-08 15:46:51329 this._matchesElement.textContent = Common.UIString.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34330 } else if (matches === 1) {
Paul Lewis17e384e2020-01-08 15:46:51331 this._matchesElement.textContent = Common.UIString.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 } else {
Paul Lewis17e384e2020-01-08 15:46:51333 this._matchesElement.textContent = Common.UIString.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34334 }
Blink Reformat4c46d092018-04-07 15:32:37335 this._updateSearchNavigationButtonState(matches > 0);
336 }
337
338 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34339 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37340 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34341 }
Blink Reformat4c46d092018-04-07 15:32:37342
343 let queryCandidate;
344 if (!this._searchInputElement.hasFocus()) {
345 const selection = UI.inspectorView.element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37347 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34348 }
Blink Reformat4c46d092018-04-07 15:32:37349 }
350
351 this._toggleSearchBar(true);
352 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37354 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34355 }
Blink Reformat4c46d092018-04-07 15:32:37356 this._performSearch(false, false);
357 this._searchInputElement.focus();
358 this._searchInputElement.select();
359 this._searchIsVisible = true;
360 }
361
362 _updateReplaceVisibility() {
363 this._replaceToggleButton.setVisible(this._replaceable);
364 if (!this._replaceable) {
365 this._replaceToggleButton.setToggled(false);
366 this._updateSecondRowVisibility();
367 }
368 }
369
370 /**
371 * @param {!Event} event
372 */
373 _onSearchKeyDown(event) {
374 if (isEscKey(event)) {
375 this.closeSearch();
376 event.consume(true);
377 return;
378 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34379 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37380 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34381 }
Blink Reformat4c46d092018-04-07 15:32:37382
Tim van der Lippe1d6e57a2019-09-30 11:55:34383 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37384 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34385 } else {
Blink Reformat4c46d092018-04-07 15:32:37386 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 }
Blink Reformat4c46d092018-04-07 15:32:37388 }
389
390 /**
391 * @param {!Event} event
392 */
393 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34394 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37395 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34396 }
Blink Reformat4c46d092018-04-07 15:32:37397 }
398
399 /**
400 * @param {boolean=} isBackwardSearch
401 */
402 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34403 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37404 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34405 }
Blink Reformat4c46d092018-04-07 15:32:37406
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37408 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 } else {
Blink Reformat4c46d092018-04-07 15:32:37410 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34411 }
Blink Reformat4c46d092018-04-07 15:32:37412 }
413
414 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37416 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34417 }
Blink Reformat4c46d092018-04-07 15:32:37418 this._jumpToNextSearchResult();
419 this._searchInputElement.focus();
420 }
421
422 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34423 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37424 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34425 }
Blink Reformat4c46d092018-04-07 15:32:37426 this._jumpToNextSearchResult(true);
427 this._searchInputElement.focus();
428 }
429
430 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34431 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37432 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34433 } else {
Blink Reformat4c46d092018-04-07 15:32:37434 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34435 }
Blink Reformat4c46d092018-04-07 15:32:37436 this._searchInputElement.focus();
437 }
438
439 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34440 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37441 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34442 } else {
Blink Reformat4c46d092018-04-07 15:32:37443 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34444 }
Blink Reformat4c46d092018-04-07 15:32:37445 this._searchInputElement.focus();
446 }
447
Tim van der Lippe0830b3d2019-10-03 13:20:07448 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37449 _clearSearch() {
450 delete this._currentQuery;
451 if (!!this._searchProvider.currentQuery) {
452 delete this._searchProvider.currentQuery;
453 this._searchProvider.searchCanceled();
454 }
455 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
456 }
457
458 /**
459 * @param {boolean} forceSearch
460 * @param {boolean} shouldJump
461 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07462 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37463 */
464 _performSearch(forceSearch, shouldJump, jumpBackwards) {
465 const query = this._searchInputElement.value;
466 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
467 this._clearSearch();
468 return;
469 }
470
471 this._currentQuery = query;
472 this._searchProvider.currentQuery = query;
473
474 const searchConfig = this._currentSearchConfig();
475 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
476 }
477
478 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07479 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37480 */
481 _currentSearchConfig() {
482 const query = this._searchInputElement.value;
483 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
484 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07485 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37486 }
487
488 _updateSecondRowVisibility() {
489 const secondRowVisible = this._replaceToggleButton.toggled();
490 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
491 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
492 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
493
Tim van der Lippe1d6e57a2019-09-30 11:55:34494 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37495 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34496 } else {
Blink Reformat4c46d092018-04-07 15:32:37497 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34498 }
Blink Reformat4c46d092018-04-07 15:32:37499 this.doResize();
500 }
501
502 _replace() {
503 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07504 /** @type {!Replaceable} */ (this._searchProvider)
Blink Reformat4c46d092018-04-07 15:32:37505 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
506 delete this._currentQuery;
507 this._performSearch(true, true);
508 }
509
510 _replaceAll() {
511 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07512 /** @type {!Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
Blink Reformat4c46d092018-04-07 15:32:37513 }
514
515 /**
516 * @param {!Event} event
517 */
518 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34519 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37520 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34521 }
Blink Reformat4c46d092018-04-07 15:32:37522 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
523 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
524 }
525
526 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34527 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37528 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34529 }
Blink Reformat4c46d092018-04-07 15:32:37530 delete this._valueChangedTimeoutId;
531 this._performSearch(false, true);
532 }
Tim van der Lippe0830b3d2019-10-03 13:20:07533}
Blink Reformat4c46d092018-04-07 15:32:37534
Tim van der Lippe0830b3d2019-10-03 13:20:07535export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37536
537
538/**
539 * @interface
540 */
Tim van der Lippe0830b3d2019-10-03 13:20:07541export class Searchable {
542 searchCanceled() {
543 }
Blink Reformat4c46d092018-04-07 15:32:37544
545 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07546 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37547 * @param {boolean} shouldJump
548 * @param {boolean=} jumpBackwards
549 */
Tim van der Lippe0830b3d2019-10-03 13:20:07550 performSearch(searchConfig, shouldJump, jumpBackwards) {
551 }
Blink Reformat4c46d092018-04-07 15:32:37552
Tim van der Lippe0830b3d2019-10-03 13:20:07553 jumpToNextSearchResult() {
554 }
Blink Reformat4c46d092018-04-07 15:32:37555
Tim van der Lippe0830b3d2019-10-03 13:20:07556 jumpToPreviousSearchResult() {
557 }
Blink Reformat4c46d092018-04-07 15:32:37558
559 /**
560 * @return {boolean}
561 */
Tim van der Lippe0830b3d2019-10-03 13:20:07562 supportsCaseSensitiveSearch() {
563 }
Blink Reformat4c46d092018-04-07 15:32:37564
565 /**
566 * @return {boolean}
567 */
568 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07569}
Blink Reformat4c46d092018-04-07 15:32:37570
571/**
572 * @interface
573 */
Tim van der Lippe0830b3d2019-10-03 13:20:07574export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37575 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07576 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37577 * @param {string} replacement
578 */
Tim van der Lippe0830b3d2019-10-03 13:20:07579 replaceSelectionWith(searchConfig, replacement) {
580 }
Blink Reformat4c46d092018-04-07 15:32:37581
582 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07583 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37584 * @param {string} replacement
585 */
586 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07587}
Blink Reformat4c46d092018-04-07 15:32:37588
589/**
590 * @unrestricted
591 */
Tim van der Lippe0830b3d2019-10-03 13:20:07592export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37593 /**
594 * @param {string} query
595 * @param {boolean} caseSensitive
596 * @param {boolean} isRegex
597 */
598 constructor(query, caseSensitive, isRegex) {
599 this.query = query;
600 this.caseSensitive = caseSensitive;
601 this.isRegex = isRegex;
602 }
603
604 /**
605 * @param {boolean=} global
606 * @return {!RegExp}
607 */
608 toSearchRegex(global) {
609 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34610 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37611 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34612 }
Blink Reformat4c46d092018-04-07 15:32:37613 const query = this.isRegex ? '/' + this.query + '/' : this.query;
614
615 let regex;
616
617 // First try creating regex if user knows the / / hint.
618 try {
619 if (/^\/.+\/$/.test(query)) {
620 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
621 regex.__fromRegExpQuery = true;
622 }
623 } catch (e) {
624 // Silent catch.
625 }
626
627 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34628 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37629 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34630 }
Blink Reformat4c46d092018-04-07 15:32:37631
632 return regex;
633 }
Tim van der Lippe0830b3d2019-10-03 13:20:07634}