blob: a7142dfac0e8156c7d03bd9f59cac59a0ab35596 [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
Tim van der Lippeee97fa32020-04-23 15:20:5632// @ts-nocheck
33// TODO(crbug.com/1011811): Enable TypeScript compiler checks
34
Paul Lewis17e384e2020-01-08 15:46:5135import * as Common from '../common/common.js';
Paul Lewis2d7d65c2020-03-16 17:26:3036
Paul Lewis9950e182019-12-16 16:06:0737import {HistoryInput} from './HistoryInput.js';
Tim van der Lippe80d82652020-08-27 13:53:4438import {InspectorView} from './InspectorView.js';
Paul Lewis9950e182019-12-16 16:06:0739import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
40import {createTextButton} from './UIUtils.js';
41import {VBox} from './Widget.js';
42
Blink Reformat4c46d092018-04-07 15:32:3743/**
44 * @unrestricted
45 */
Paul Lewis9950e182019-12-16 16:06:0746export class SearchableView extends VBox {
Blink Reformat4c46d092018-04-07 15:32:3747 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0748 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3749 * @param {string=} settingName
50 */
51 constructor(searchable, settingName) {
52 super(true);
53 this.registerRequiredCSS('ui/searchableView.css');
Tim van der Lippe0830b3d2019-10-03 13:20:0754 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3755
56 this._searchProvider = searchable;
Paul Lewis17e384e2020-01-08 15:46:5157 // Note: go via self.Common for globally-namespaced singletons.
Paul Lewis2d7d65c2020-03-16 17:26:3058 this._setting = settingName ? Common.Settings.Settings.instance().createSetting(settingName, {}) : null;
Blink Reformat4c46d092018-04-07 15:32:3759 this._replaceable = false;
60
Joel Einbinder7fbe24c2019-01-24 05:19:0161 this.contentElement.createChild('slot');
Blink Reformat4c46d092018-04-07 15:32:3762 this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
63 this._footerElementContainer.style.order = 100;
64 this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
65
Paul Lewis9950e182019-12-16 16:06:0766 const replaceToggleToolbar = new Toolbar('replace-toggle-toolbar', this._footerElement);
Paul Lewis17e384e2020-01-08 15:46:5167 this._replaceToggleButton = new ToolbarToggle(Common.UIString.UIString('Replace'), 'mediumicon-replace');
Paul Lewis9950e182019-12-16 16:06:0768 this._replaceToggleButton.addEventListener(ToolbarButton.Events.Click, this._toggleReplace, this);
Blink Reformat4c46d092018-04-07 15:32:3769 replaceToggleToolbar.appendToolbarItem(this._replaceToggleButton);
70
71 const searchInputElements = this._footerElement.createChild('div', 'toolbar-search-inputs');
72 const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
73
Paul Lewis9950e182019-12-16 16:06:0774 this._searchInputElement = HistoryInput.create();
Changhao Hanf9bf91d2020-06-25 22:24:0775 this._searchInputElement.type = 'search';
76 this._searchInputElement.classList.add('search-replace', 'custom-search-input');
Blink Reformat4c46d092018-04-07 15:32:3777 this._searchInputElement.id = 'search-input-field';
Paul Lewis17e384e2020-01-08 15:46:5178 this._searchInputElement.placeholder = Common.UIString.UIString('Find');
Blink Reformat4c46d092018-04-07 15:32:3779 searchControlElement.appendChild(this._searchInputElement);
80
81 this._matchesElement = searchControlElement.createChild('label', 'search-results-matches');
82 this._matchesElement.setAttribute('for', 'search-input-field');
83
84 const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
85
86 this._searchNavigationPrevElement =
87 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
88 this._searchNavigationPrevElement.addEventListener('click', this._onPrevButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5189 this._searchNavigationPrevElement.title = Common.UIString.UIString('Search previous');
Blink Reformat4c46d092018-04-07 15:32:3790
91 this._searchNavigationNextElement =
92 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
93 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5194 this._searchNavigationNextElement.title = Common.UIString.UIString('Search next');
Blink Reformat4c46d092018-04-07 15:32:3795
96 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
97 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
98
99 this._replaceInputElement =
100 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
101 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
Paul Lewis17e384e2020-01-08 15:46:51102 this._replaceInputElement.placeholder = Common.UIString.UIString('Replace');
Blink Reformat4c46d092018-04-07 15:32:37103
104 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
105 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
106
Paul Lewis9950e182019-12-16 16:06:07107 const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
Blink Reformat4c46d092018-04-07 15:32:37108
109 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51110 this._caseSensitiveButton = new ToolbarToggle(Common.UIString.UIString('Match Case'));
Blink Reformat4c46d092018-04-07 15:32:37111 this._caseSensitiveButton.setText('Aa');
Paul Lewis9950e182019-12-16 16:06:07112 this._caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37113 toolbar.appendToolbarItem(this._caseSensitiveButton);
114 }
115
116 if (this._searchProvider.supportsRegexSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51117 this._regexButton = new ToolbarToggle(Common.UIString.UIString('Use Regular Expression'));
Blink Reformat4c46d092018-04-07 15:32:37118 this._regexButton.setText('.*');
Paul Lewis9950e182019-12-16 16:06:07119 this._regexButton.addEventListener(ToolbarButton.Events.Click, this._toggleRegexSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37120 toolbar.appendToolbarItem(this._regexButton);
121 }
122
123 const cancelButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51124 createTextButton(Common.UIString.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37125 firstRowButtons.appendChild(cancelButtonElement);
126
127 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
128
129 this._replaceButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51130 createTextButton(Common.UIString.UIString('Replace'), this._replace.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37131 this._replaceButtonElement.disabled = true;
132 this._secondRowButtons.appendChild(this._replaceButtonElement);
133
134 this._replaceAllButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51135 createTextButton(Common.UIString.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37136 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
137 this._replaceAllButtonElement.disabled = true;
138
139 this._minimalSearchQuerySize = 3;
140 this._loadSetting();
141 }
142
143 /**
144 * @param {?Element} element
Tim van der Lippe0830b3d2019-10-03 13:20:07145 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37146 */
147 static fromElement(element) {
148 let view = null;
149 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07150 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37151 element = element.parentElementOrShadowHost();
152 }
153 return view;
154 }
155
156 _toggleCaseSensitiveSearch() {
157 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
158 this._saveSetting();
159 this._performSearch(false, true);
160 }
161
162 _toggleRegexSearch() {
163 this._regexButton.setToggled(!this._regexButton.toggled());
164 this._saveSetting();
165 this._performSearch(false, true);
166 }
167
168 _toggleReplace() {
169 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
170 this._updateSecondRowVisibility();
171 }
172
173 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34174 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37175 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34176 }
Blink Reformat4c46d092018-04-07 15:32:37177 const settingValue = this._setting.get() || {};
178 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
179 settingValue.isRegex = this._regexButton.toggled();
180 this._setting.set(settingValue);
181 }
182
183 _loadSetting() {
184 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34185 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37186 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34187 }
188 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37189 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34190 }
Blink Reformat4c46d092018-04-07 15:32:37191 }
192
193 /**
194 * @param {number} minimalSearchQuerySize
195 */
196 setMinimalSearchQuerySize(minimalSearchQuerySize) {
197 this._minimalSearchQuerySize = minimalSearchQuerySize;
198 }
199
200 /**
201 * @param {string} placeholder
202 */
203 setPlaceholder(placeholder) {
204 this._searchInputElement.placeholder = placeholder;
205 }
206
207 /**
208 * @param {boolean} replaceable
209 */
210 setReplaceable(replaceable) {
211 this._replaceable = replaceable;
212 }
213
214 /**
215 * @param {number} matches
Tim van der Lippe0830b3d2019-10-03 13:20:07216 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37217 */
218 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34219 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37220 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34221 }
Blink Reformat4c46d092018-04-07 15:32:37222 this._searchProvider.currentSearchMatches = matches;
223 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
224 }
225
226 /**
227 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07228 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37229 */
230 updateCurrentMatchIndex(currentMatchIndex) {
231 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
232 }
233
234 /**
235 * @return {boolean}
236 */
237 isSearchVisible() {
238 return this._searchIsVisible;
239 }
240
241 closeSearch() {
242 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34243 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37244 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34245 }
Blink Reformat4c46d092018-04-07 15:32:37246 }
247
248 _toggleSearchBar(toggled) {
249 this._footerElementContainer.classList.toggle('hidden', !toggled);
250 this.doResize();
251 }
252
253 cancelSearch() {
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 delete this._searchIsVisible;
259 this._toggleSearchBar(false);
260 }
261
262 resetSearch() {
263 this._clearSearch();
264 this._updateReplaceVisibility();
265 this._matchesElement.textContent = '';
266 }
267
268 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34269 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37270 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 }
Blink Reformat4c46d092018-04-07 15:32:37272 this.resetSearch();
273 this._performSearch(false, false);
274 }
275
276 /**
277 * @return {boolean}
278 */
279 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34280 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37281 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34282 }
Blink Reformat4c46d092018-04-07 15:32:37283 this._searchProvider.jumpToNextSearchResult();
284 return true;
285 }
286
287 /**
288 * @return {boolean}
289 */
290 handleFindPreviousShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34291 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37292 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34293 }
Blink Reformat4c46d092018-04-07 15:32:37294 this._searchProvider.jumpToPreviousSearchResult();
295 return true;
296 }
297
298 /**
299 * @return {boolean}
300 */
301 handleFindShortcut() {
302 this.showSearchField();
303 return true;
304 }
305
306 /**
307 * @return {boolean}
308 */
309 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34310 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37311 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34312 }
Blink Reformat4c46d092018-04-07 15:32:37313 this.closeSearch();
314 return true;
315 }
316
317 /**
318 * @param {boolean} enabled
319 */
320 _updateSearchNavigationButtonState(enabled) {
321 this._replaceButtonElement.disabled = !enabled;
322 this._replaceAllButtonElement.disabled = !enabled;
323 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
324 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
325 }
326
327 /**
328 * @param {number} matches
329 * @param {number} currentMatchIndex
330 */
331 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34332 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37333 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34334 } else if (matches === 0 || currentMatchIndex >= 0) {
Paul Lewis17e384e2020-01-08 15:46:51335 this._matchesElement.textContent = Common.UIString.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34336 } else if (matches === 1) {
Paul Lewis17e384e2020-01-08 15:46:51337 this._matchesElement.textContent = Common.UIString.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34338 } else {
Paul Lewis17e384e2020-01-08 15:46:51339 this._matchesElement.textContent = Common.UIString.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34340 }
Blink Reformat4c46d092018-04-07 15:32:37341 this._updateSearchNavigationButtonState(matches > 0);
342 }
343
344 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34345 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37346 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 }
Blink Reformat4c46d092018-04-07 15:32:37348
349 let queryCandidate;
350 if (!this._searchInputElement.hasFocus()) {
Tim van der Lippe80d82652020-08-27 13:53:44351 const selection = InspectorView.instance().element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34352 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37353 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34354 }
Blink Reformat4c46d092018-04-07 15:32:37355 }
356
357 this._toggleSearchBar(true);
358 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34359 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37360 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34361 }
Blink Reformat4c46d092018-04-07 15:32:37362 this._performSearch(false, false);
363 this._searchInputElement.focus();
364 this._searchInputElement.select();
365 this._searchIsVisible = true;
366 }
367
368 _updateReplaceVisibility() {
369 this._replaceToggleButton.setVisible(this._replaceable);
370 if (!this._replaceable) {
371 this._replaceToggleButton.setToggled(false);
372 this._updateSecondRowVisibility();
373 }
374 }
375
376 /**
377 * @param {!Event} event
378 */
379 _onSearchKeyDown(event) {
380 if (isEscKey(event)) {
381 this.closeSearch();
382 event.consume(true);
383 return;
384 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34385 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37386 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 }
Blink Reformat4c46d092018-04-07 15:32:37388
Tim van der Lippe1d6e57a2019-09-30 11:55:34389 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37390 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34391 } else {
Blink Reformat4c46d092018-04-07 15:32:37392 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34393 }
Blink Reformat4c46d092018-04-07 15:32:37394 }
395
396 /**
397 * @param {!Event} event
398 */
399 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34400 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37401 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34402 }
Blink Reformat4c46d092018-04-07 15:32:37403 }
404
405 /**
406 * @param {boolean=} isBackwardSearch
407 */
408 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37410 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34411 }
Blink Reformat4c46d092018-04-07 15:32:37412
Tim van der Lippe1d6e57a2019-09-30 11:55:34413 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37414 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 } else {
Blink Reformat4c46d092018-04-07 15:32:37416 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34417 }
Blink Reformat4c46d092018-04-07 15:32:37418 }
419
420 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34421 if (!this._searchNavigationNextElement.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();
425 this._searchInputElement.focus();
426 }
427
428 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34429 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37430 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34431 }
Blink Reformat4c46d092018-04-07 15:32:37432 this._jumpToNextSearchResult(true);
433 this._searchInputElement.focus();
434 }
435
436 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34437 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37438 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34439 } else {
Blink Reformat4c46d092018-04-07 15:32:37440 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34441 }
Blink Reformat4c46d092018-04-07 15:32:37442 this._searchInputElement.focus();
443 }
444
445 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34446 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37447 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34448 } else {
Blink Reformat4c46d092018-04-07 15:32:37449 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34450 }
Blink Reformat4c46d092018-04-07 15:32:37451 this._searchInputElement.focus();
452 }
453
Tim van der Lippe0830b3d2019-10-03 13:20:07454 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37455 _clearSearch() {
456 delete this._currentQuery;
457 if (!!this._searchProvider.currentQuery) {
458 delete this._searchProvider.currentQuery;
459 this._searchProvider.searchCanceled();
460 }
461 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
462 }
463
464 /**
465 * @param {boolean} forceSearch
466 * @param {boolean} shouldJump
467 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07468 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37469 */
470 _performSearch(forceSearch, shouldJump, jumpBackwards) {
471 const query = this._searchInputElement.value;
472 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
473 this._clearSearch();
474 return;
475 }
476
477 this._currentQuery = query;
478 this._searchProvider.currentQuery = query;
479
480 const searchConfig = this._currentSearchConfig();
481 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
482 }
483
484 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07485 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37486 */
487 _currentSearchConfig() {
488 const query = this._searchInputElement.value;
489 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
490 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07491 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37492 }
493
494 _updateSecondRowVisibility() {
495 const secondRowVisible = this._replaceToggleButton.toggled();
496 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
497 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
498 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
499
Tim van der Lippe1d6e57a2019-09-30 11:55:34500 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37501 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34502 } else {
Blink Reformat4c46d092018-04-07 15:32:37503 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34504 }
Blink Reformat4c46d092018-04-07 15:32:37505 this.doResize();
506 }
507
508 _replace() {
509 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07510 /** @type {!Replaceable} */ (this._searchProvider)
Blink Reformat4c46d092018-04-07 15:32:37511 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
512 delete this._currentQuery;
513 this._performSearch(true, true);
514 }
515
516 _replaceAll() {
517 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07518 /** @type {!Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
Blink Reformat4c46d092018-04-07 15:32:37519 }
520
521 /**
522 * @param {!Event} event
523 */
524 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34525 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37526 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34527 }
Blink Reformat4c46d092018-04-07 15:32:37528 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
529 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
530 }
531
532 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34533 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37534 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34535 }
Blink Reformat4c46d092018-04-07 15:32:37536 delete this._valueChangedTimeoutId;
537 this._performSearch(false, true);
538 }
Tim van der Lippe0830b3d2019-10-03 13:20:07539}
Blink Reformat4c46d092018-04-07 15:32:37540
Tim van der Lippe0830b3d2019-10-03 13:20:07541export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37542
543
544/**
545 * @interface
546 */
Tim van der Lippe0830b3d2019-10-03 13:20:07547export class Searchable {
548 searchCanceled() {
549 }
Blink Reformat4c46d092018-04-07 15:32:37550
551 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07552 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37553 * @param {boolean} shouldJump
554 * @param {boolean=} jumpBackwards
555 */
Tim van der Lippe0830b3d2019-10-03 13:20:07556 performSearch(searchConfig, shouldJump, jumpBackwards) {
557 }
Blink Reformat4c46d092018-04-07 15:32:37558
Tim van der Lippe0830b3d2019-10-03 13:20:07559 jumpToNextSearchResult() {
560 }
Blink Reformat4c46d092018-04-07 15:32:37561
Tim van der Lippe0830b3d2019-10-03 13:20:07562 jumpToPreviousSearchResult() {
563 }
Blink Reformat4c46d092018-04-07 15:32:37564
565 /**
566 * @return {boolean}
567 */
Tim van der Lippe0830b3d2019-10-03 13:20:07568 supportsCaseSensitiveSearch() {
569 }
Blink Reformat4c46d092018-04-07 15:32:37570
571 /**
572 * @return {boolean}
573 */
574 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07575}
Blink Reformat4c46d092018-04-07 15:32:37576
577/**
578 * @interface
579 */
Tim van der Lippe0830b3d2019-10-03 13:20:07580export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37581 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07582 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37583 * @param {string} replacement
584 */
Tim van der Lippe0830b3d2019-10-03 13:20:07585 replaceSelectionWith(searchConfig, replacement) {
586 }
Blink Reformat4c46d092018-04-07 15:32:37587
588 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07589 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37590 * @param {string} replacement
591 */
592 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07593}
Blink Reformat4c46d092018-04-07 15:32:37594
595/**
596 * @unrestricted
597 */
Tim van der Lippe0830b3d2019-10-03 13:20:07598export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37599 /**
600 * @param {string} query
601 * @param {boolean} caseSensitive
602 * @param {boolean} isRegex
603 */
604 constructor(query, caseSensitive, isRegex) {
605 this.query = query;
606 this.caseSensitive = caseSensitive;
607 this.isRegex = isRegex;
608 }
609
610 /**
611 * @param {boolean=} global
612 * @return {!RegExp}
613 */
614 toSearchRegex(global) {
615 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34616 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37617 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34618 }
Blink Reformat4c46d092018-04-07 15:32:37619 const query = this.isRegex ? '/' + this.query + '/' : this.query;
620
621 let regex;
622
623 // First try creating regex if user knows the / / hint.
624 try {
625 if (/^\/.+\/$/.test(query)) {
626 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
627 regex.__fromRegExpQuery = true;
628 }
629 } catch (e) {
630 // Silent catch.
631 }
632
633 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34634 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37635 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34636 }
Blink Reformat4c46d092018-04-07 15:32:37637
638 return regex;
639 }
Tim van der Lippe0830b3d2019-10-03 13:20:07640}