blob: bcf994a24fbb8d574736e9f8a3f67d3cd7647de8 [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
Sigurd Schneiderb8205132020-09-08 14:36:1737import * as ARIAUtils from './ARIAUtils.js';
Paul Lewis9950e182019-12-16 16:06:0738import {HistoryInput} from './HistoryInput.js';
Tim van der Lippe80d82652020-08-27 13:53:4439import {InspectorView} from './InspectorView.js';
Paul Lewis9950e182019-12-16 16:06:0740import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
41import {createTextButton} from './UIUtils.js';
42import {VBox} from './Widget.js';
43
Blink Reformat4c46d092018-04-07 15:32:3744/**
45 * @unrestricted
46 */
Paul Lewis9950e182019-12-16 16:06:0747export class SearchableView extends VBox {
Blink Reformat4c46d092018-04-07 15:32:3748 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0749 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3750 * @param {string=} settingName
51 */
52 constructor(searchable, settingName) {
53 super(true);
Jack Franklin71519f82020-11-03 12:08:5954 this.registerRequiredCSS('ui/searchableView.css', {enableLegacyPatching: true});
Tim van der Lippe0830b3d2019-10-03 13:20:0755 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3756
57 this._searchProvider = searchable;
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');
Sigurd Schneiderb8205132020-09-08 14:36:1790 ARIAUtils.setAccessibleName(this._searchNavigationPrevElement, Common.UIString.UIString('Search previous'));
Blink Reformat4c46d092018-04-07 15:32:3791
92 this._searchNavigationNextElement =
93 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
94 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5195 this._searchNavigationNextElement.title = Common.UIString.UIString('Search next');
Sigurd Schneiderb8205132020-09-08 14:36:1796 ARIAUtils.setAccessibleName(this._searchNavigationNextElement, Common.UIString.UIString('Search next'));
Blink Reformat4c46d092018-04-07 15:32:3797
98 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
99 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
100
101 this._replaceInputElement =
102 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
103 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
Paul Lewis17e384e2020-01-08 15:46:51104 this._replaceInputElement.placeholder = Common.UIString.UIString('Replace');
Blink Reformat4c46d092018-04-07 15:32:37105
106 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
107 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
108
Paul Lewis9950e182019-12-16 16:06:07109 const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
Blink Reformat4c46d092018-04-07 15:32:37110
111 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51112 this._caseSensitiveButton = new ToolbarToggle(Common.UIString.UIString('Match Case'));
Blink Reformat4c46d092018-04-07 15:32:37113 this._caseSensitiveButton.setText('Aa');
Paul Lewis9950e182019-12-16 16:06:07114 this._caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37115 toolbar.appendToolbarItem(this._caseSensitiveButton);
116 }
117
118 if (this._searchProvider.supportsRegexSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51119 this._regexButton = new ToolbarToggle(Common.UIString.UIString('Use Regular Expression'));
Blink Reformat4c46d092018-04-07 15:32:37120 this._regexButton.setText('.*');
Paul Lewis9950e182019-12-16 16:06:07121 this._regexButton.addEventListener(ToolbarButton.Events.Click, this._toggleRegexSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37122 toolbar.appendToolbarItem(this._regexButton);
123 }
124
125 const cancelButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51126 createTextButton(Common.UIString.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37127 firstRowButtons.appendChild(cancelButtonElement);
128
129 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
130
131 this._replaceButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51132 createTextButton(Common.UIString.UIString('Replace'), this._replace.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37133 this._replaceButtonElement.disabled = true;
134 this._secondRowButtons.appendChild(this._replaceButtonElement);
135
136 this._replaceAllButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51137 createTextButton(Common.UIString.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37138 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
139 this._replaceAllButtonElement.disabled = true;
140
141 this._minimalSearchQuerySize = 3;
142 this._loadSetting();
143 }
144
145 /**
146 * @param {?Element} element
Tim van der Lippe0830b3d2019-10-03 13:20:07147 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37148 */
149 static fromElement(element) {
150 let view = null;
151 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07152 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37153 element = element.parentElementOrShadowHost();
154 }
155 return view;
156 }
157
158 _toggleCaseSensitiveSearch() {
159 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
160 this._saveSetting();
161 this._performSearch(false, true);
162 }
163
164 _toggleRegexSearch() {
165 this._regexButton.setToggled(!this._regexButton.toggled());
166 this._saveSetting();
167 this._performSearch(false, true);
168 }
169
170 _toggleReplace() {
171 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
172 this._updateSecondRowVisibility();
173 }
174
175 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34176 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37177 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34178 }
Blink Reformat4c46d092018-04-07 15:32:37179 const settingValue = this._setting.get() || {};
180 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
181 settingValue.isRegex = this._regexButton.toggled();
182 this._setting.set(settingValue);
183 }
184
185 _loadSetting() {
186 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34187 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37188 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34189 }
190 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37191 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34192 }
Blink Reformat4c46d092018-04-07 15:32:37193 }
194
195 /**
196 * @param {number} minimalSearchQuerySize
197 */
198 setMinimalSearchQuerySize(minimalSearchQuerySize) {
199 this._minimalSearchQuerySize = minimalSearchQuerySize;
200 }
201
202 /**
203 * @param {string} placeholder
Sigurd Schneiderb8205132020-09-08 14:36:17204 * @param {string=} ariaLabel
Blink Reformat4c46d092018-04-07 15:32:37205 */
Sigurd Schneiderb8205132020-09-08 14:36:17206 setPlaceholder(placeholder, ariaLabel) {
Blink Reformat4c46d092018-04-07 15:32:37207 this._searchInputElement.placeholder = placeholder;
Sigurd Schneiderb8205132020-09-08 14:36:17208 if (ariaLabel) {
209 ARIAUtils.setAccessibleName(this._searchInputElement, ariaLabel);
210 }
Blink Reformat4c46d092018-04-07 15:32:37211 }
212
213 /**
214 * @param {boolean} replaceable
215 */
216 setReplaceable(replaceable) {
217 this._replaceable = replaceable;
218 }
219
220 /**
221 * @param {number} matches
Tim van der Lippe0830b3d2019-10-03 13:20:07222 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37223 */
224 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34225 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37226 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34227 }
Blink Reformat4c46d092018-04-07 15:32:37228 this._searchProvider.currentSearchMatches = matches;
229 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
230 }
231
232 /**
233 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07234 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37235 */
236 updateCurrentMatchIndex(currentMatchIndex) {
237 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
238 }
239
240 /**
241 * @return {boolean}
242 */
243 isSearchVisible() {
244 return this._searchIsVisible;
245 }
246
247 closeSearch() {
248 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37250 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 }
Blink Reformat4c46d092018-04-07 15:32:37252 }
253
254 _toggleSearchBar(toggled) {
255 this._footerElementContainer.classList.toggle('hidden', !toggled);
256 this.doResize();
257 }
258
259 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34260 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37261 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34262 }
Blink Reformat4c46d092018-04-07 15:32:37263 this.resetSearch();
264 delete this._searchIsVisible;
265 this._toggleSearchBar(false);
266 }
267
268 resetSearch() {
269 this._clearSearch();
270 this._updateReplaceVisibility();
271 this._matchesElement.textContent = '';
272 }
273
274 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34275 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37276 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34277 }
Blink Reformat4c46d092018-04-07 15:32:37278 this.resetSearch();
279 this._performSearch(false, false);
280 }
281
282 /**
283 * @return {boolean}
284 */
285 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34286 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37287 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34288 }
Blink Reformat4c46d092018-04-07 15:32:37289 this._searchProvider.jumpToNextSearchResult();
290 return true;
291 }
292
293 /**
294 * @return {boolean}
295 */
296 handleFindPreviousShortcut() {
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._searchProvider.jumpToPreviousSearchResult();
301 return true;
302 }
303
304 /**
305 * @return {boolean}
306 */
307 handleFindShortcut() {
308 this.showSearchField();
309 return true;
310 }
311
312 /**
313 * @return {boolean}
314 */
315 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34316 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37317 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34318 }
Blink Reformat4c46d092018-04-07 15:32:37319 this.closeSearch();
320 return true;
321 }
322
323 /**
324 * @param {boolean} enabled
325 */
326 _updateSearchNavigationButtonState(enabled) {
327 this._replaceButtonElement.disabled = !enabled;
328 this._replaceAllButtonElement.disabled = !enabled;
329 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
330 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
331 }
332
333 /**
334 * @param {number} matches
335 * @param {number} currentMatchIndex
336 */
337 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34338 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37339 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34340 } else if (matches === 0 || currentMatchIndex >= 0) {
Paul Lewis17e384e2020-01-08 15:46:51341 this._matchesElement.textContent = Common.UIString.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34342 } else if (matches === 1) {
Paul Lewis17e384e2020-01-08 15:46:51343 this._matchesElement.textContent = Common.UIString.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 } else {
Paul Lewis17e384e2020-01-08 15:46:51345 this._matchesElement.textContent = Common.UIString.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34346 }
Blink Reformat4c46d092018-04-07 15:32:37347 this._updateSearchNavigationButtonState(matches > 0);
348 }
349
350 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34351 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37352 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 }
Blink Reformat4c46d092018-04-07 15:32:37354
355 let queryCandidate;
356 if (!this._searchInputElement.hasFocus()) {
Tim van der Lippe80d82652020-08-27 13:53:44357 const selection = InspectorView.instance().element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34358 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37359 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34360 }
Blink Reformat4c46d092018-04-07 15:32:37361 }
362
363 this._toggleSearchBar(true);
364 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34365 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37366 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34367 }
Blink Reformat4c46d092018-04-07 15:32:37368 this._performSearch(false, false);
369 this._searchInputElement.focus();
370 this._searchInputElement.select();
371 this._searchIsVisible = true;
372 }
373
374 _updateReplaceVisibility() {
375 this._replaceToggleButton.setVisible(this._replaceable);
376 if (!this._replaceable) {
377 this._replaceToggleButton.setToggled(false);
378 this._updateSecondRowVisibility();
379 }
380 }
381
382 /**
383 * @param {!Event} event
384 */
385 _onSearchKeyDown(event) {
386 if (isEscKey(event)) {
387 this.closeSearch();
388 event.consume(true);
389 return;
390 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34391 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37392 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34393 }
Blink Reformat4c46d092018-04-07 15:32:37394
Tim van der Lippe1d6e57a2019-09-30 11:55:34395 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37396 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34397 } else {
Blink Reformat4c46d092018-04-07 15:32:37398 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34399 }
Blink Reformat4c46d092018-04-07 15:32:37400 }
401
402 /**
403 * @param {!Event} event
404 */
405 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37407 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 }
Blink Reformat4c46d092018-04-07 15:32:37409 }
410
411 /**
412 * @param {boolean=} isBackwardSearch
413 */
414 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37416 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34417 }
Blink Reformat4c46d092018-04-07 15:32:37418
Tim van der Lippe1d6e57a2019-09-30 11:55:34419 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37420 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34421 } else {
Blink Reformat4c46d092018-04-07 15:32:37422 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34423 }
Blink Reformat4c46d092018-04-07 15:32:37424 }
425
426 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34427 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37428 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34429 }
Blink Reformat4c46d092018-04-07 15:32:37430 this._jumpToNextSearchResult();
431 this._searchInputElement.focus();
432 }
433
434 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34435 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37436 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34437 }
Blink Reformat4c46d092018-04-07 15:32:37438 this._jumpToNextSearchResult(true);
439 this._searchInputElement.focus();
440 }
441
442 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34443 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37444 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34445 } else {
Blink Reformat4c46d092018-04-07 15:32:37446 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34447 }
Blink Reformat4c46d092018-04-07 15:32:37448 this._searchInputElement.focus();
449 }
450
451 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34452 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37453 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34454 } else {
Blink Reformat4c46d092018-04-07 15:32:37455 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34456 }
Blink Reformat4c46d092018-04-07 15:32:37457 this._searchInputElement.focus();
458 }
459
Tim van der Lippe0830b3d2019-10-03 13:20:07460 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37461 _clearSearch() {
462 delete this._currentQuery;
463 if (!!this._searchProvider.currentQuery) {
464 delete this._searchProvider.currentQuery;
465 this._searchProvider.searchCanceled();
466 }
467 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
468 }
469
470 /**
471 * @param {boolean} forceSearch
472 * @param {boolean} shouldJump
473 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07474 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37475 */
476 _performSearch(forceSearch, shouldJump, jumpBackwards) {
477 const query = this._searchInputElement.value;
478 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
479 this._clearSearch();
480 return;
481 }
482
483 this._currentQuery = query;
484 this._searchProvider.currentQuery = query;
485
486 const searchConfig = this._currentSearchConfig();
487 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
488 }
489
490 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07491 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37492 */
493 _currentSearchConfig() {
494 const query = this._searchInputElement.value;
495 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
496 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07497 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37498 }
499
500 _updateSecondRowVisibility() {
501 const secondRowVisible = this._replaceToggleButton.toggled();
502 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
503 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
504 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
505
Tim van der Lippe1d6e57a2019-09-30 11:55:34506 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37507 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34508 } else {
Blink Reformat4c46d092018-04-07 15:32:37509 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34510 }
Blink Reformat4c46d092018-04-07 15:32:37511 this.doResize();
512 }
513
514 _replace() {
515 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07516 /** @type {!Replaceable} */ (this._searchProvider)
Blink Reformat4c46d092018-04-07 15:32:37517 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
518 delete this._currentQuery;
519 this._performSearch(true, true);
520 }
521
522 _replaceAll() {
523 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07524 /** @type {!Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
Blink Reformat4c46d092018-04-07 15:32:37525 }
526
527 /**
528 * @param {!Event} event
529 */
530 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34531 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37532 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34533 }
Blink Reformat4c46d092018-04-07 15:32:37534 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
535 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
536 }
537
538 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34539 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37540 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34541 }
Blink Reformat4c46d092018-04-07 15:32:37542 delete this._valueChangedTimeoutId;
543 this._performSearch(false, true);
544 }
Tim van der Lippe0830b3d2019-10-03 13:20:07545}
Blink Reformat4c46d092018-04-07 15:32:37546
Tim van der Lippe0830b3d2019-10-03 13:20:07547export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37548
549
550/**
551 * @interface
552 */
Tim van der Lippe0830b3d2019-10-03 13:20:07553export class Searchable {
554 searchCanceled() {
555 }
Blink Reformat4c46d092018-04-07 15:32:37556
557 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07558 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37559 * @param {boolean} shouldJump
560 * @param {boolean=} jumpBackwards
561 */
Tim van der Lippe0830b3d2019-10-03 13:20:07562 performSearch(searchConfig, shouldJump, jumpBackwards) {
563 }
Blink Reformat4c46d092018-04-07 15:32:37564
Tim van der Lippe0830b3d2019-10-03 13:20:07565 jumpToNextSearchResult() {
566 }
Blink Reformat4c46d092018-04-07 15:32:37567
Tim van der Lippe0830b3d2019-10-03 13:20:07568 jumpToPreviousSearchResult() {
569 }
Blink Reformat4c46d092018-04-07 15:32:37570
571 /**
572 * @return {boolean}
573 */
Tim van der Lippe0830b3d2019-10-03 13:20:07574 supportsCaseSensitiveSearch() {
575 }
Blink Reformat4c46d092018-04-07 15:32:37576
577 /**
578 * @return {boolean}
579 */
580 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07581}
Blink Reformat4c46d092018-04-07 15:32:37582
583/**
584 * @interface
585 */
Tim van der Lippe0830b3d2019-10-03 13:20:07586export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37587 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07588 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37589 * @param {string} replacement
590 */
Tim van der Lippe0830b3d2019-10-03 13:20:07591 replaceSelectionWith(searchConfig, replacement) {
592 }
Blink Reformat4c46d092018-04-07 15:32:37593
594 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07595 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37596 * @param {string} replacement
597 */
598 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07599}
Blink Reformat4c46d092018-04-07 15:32:37600
601/**
602 * @unrestricted
603 */
Tim van der Lippe0830b3d2019-10-03 13:20:07604export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37605 /**
606 * @param {string} query
607 * @param {boolean} caseSensitive
608 * @param {boolean} isRegex
609 */
610 constructor(query, caseSensitive, isRegex) {
611 this.query = query;
612 this.caseSensitive = caseSensitive;
613 this.isRegex = isRegex;
614 }
615
616 /**
617 * @param {boolean=} global
618 * @return {!RegExp}
619 */
620 toSearchRegex(global) {
621 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34622 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37623 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34624 }
Blink Reformat4c46d092018-04-07 15:32:37625 const query = this.isRegex ? '/' + this.query + '/' : this.query;
626
627 let regex;
628
629 // First try creating regex if user knows the / / hint.
630 try {
631 if (/^\/.+\/$/.test(query)) {
632 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
633 regex.__fromRegExpQuery = true;
634 }
635 } catch (e) {
636 // Silent catch.
637 }
638
639 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34640 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37641 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34642 }
Blink Reformat4c46d092018-04-07 15:32:37643
644 return regex;
645 }
Tim van der Lippe0830b3d2019-10-03 13:20:07646}