blob: e8916e94b9e361fe168f6e0757a91a7d95c3c986 [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 Lewis2d7d65c2020-03-16 17:26:3033
Paul Lewis9950e182019-12-16 16:06:0734import {HistoryInput} from './HistoryInput.js';
35import {Toolbar, ToolbarButton, ToolbarToggle} from './Toolbar.js';
36import {createTextButton} from './UIUtils.js';
37import {VBox} from './Widget.js';
38
Blink Reformat4c46d092018-04-07 15:32:3739/**
40 * @unrestricted
41 */
Paul Lewis9950e182019-12-16 16:06:0742export class SearchableView extends VBox {
Blink Reformat4c46d092018-04-07 15:32:3743 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0744 * @param {!Searchable} searchable
Blink Reformat4c46d092018-04-07 15:32:3745 * @param {string=} settingName
46 */
47 constructor(searchable, settingName) {
48 super(true);
49 this.registerRequiredCSS('ui/searchableView.css');
Tim van der Lippe0830b3d2019-10-03 13:20:0750 this.element[_symbol] = this;
Blink Reformat4c46d092018-04-07 15:32:3751
52 this._searchProvider = searchable;
Paul Lewis17e384e2020-01-08 15:46:5153 // Note: go via self.Common for globally-namespaced singletons.
Paul Lewis2d7d65c2020-03-16 17:26:3054 this._setting = settingName ? Common.Settings.Settings.instance().createSetting(settingName, {}) : null;
Blink Reformat4c46d092018-04-07 15:32:3755 this._replaceable = false;
56
Joel Einbinder7fbe24c2019-01-24 05:19:0157 this.contentElement.createChild('slot');
Blink Reformat4c46d092018-04-07 15:32:3758 this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden');
59 this._footerElementContainer.style.order = 100;
60 this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
61
Paul Lewis9950e182019-12-16 16:06:0762 const replaceToggleToolbar = new Toolbar('replace-toggle-toolbar', this._footerElement);
Paul Lewis17e384e2020-01-08 15:46:5163 this._replaceToggleButton = new ToolbarToggle(Common.UIString.UIString('Replace'), 'mediumicon-replace');
Paul Lewis9950e182019-12-16 16:06:0764 this._replaceToggleButton.addEventListener(ToolbarButton.Events.Click, this._toggleReplace, this);
Blink Reformat4c46d092018-04-07 15:32:3765 replaceToggleToolbar.appendToolbarItem(this._replaceToggleButton);
66
67 const searchInputElements = this._footerElement.createChild('div', 'toolbar-search-inputs');
68 const searchControlElement = searchInputElements.createChild('div', 'toolbar-search-control');
69
Paul Lewis9950e182019-12-16 16:06:0770 this._searchInputElement = HistoryInput.create();
Blink Reformat4c46d092018-04-07 15:32:3771 this._searchInputElement.classList.add('search-replace');
72 this._searchInputElement.id = 'search-input-field';
Paul Lewis17e384e2020-01-08 15:46:5173 this._searchInputElement.placeholder = Common.UIString.UIString('Find');
Blink Reformat4c46d092018-04-07 15:32:3774 searchControlElement.appendChild(this._searchInputElement);
75
76 this._matchesElement = searchControlElement.createChild('label', 'search-results-matches');
77 this._matchesElement.setAttribute('for', 'search-input-field');
78
79 const searchNavigationElement = searchControlElement.createChild('div', 'toolbar-search-navigation-controls');
80
81 this._searchNavigationPrevElement =
82 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-prev');
83 this._searchNavigationPrevElement.addEventListener('click', this._onPrevButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5184 this._searchNavigationPrevElement.title = Common.UIString.UIString('Search previous');
Blink Reformat4c46d092018-04-07 15:32:3785
86 this._searchNavigationNextElement =
87 searchNavigationElement.createChild('div', 'toolbar-search-navigation toolbar-search-navigation-next');
88 this._searchNavigationNextElement.addEventListener('click', this._onNextButtonSearch.bind(this), false);
Paul Lewis17e384e2020-01-08 15:46:5189 this._searchNavigationNextElement.title = Common.UIString.UIString('Search next');
Blink Reformat4c46d092018-04-07 15:32:3790
91 this._searchInputElement.addEventListener('keydown', this._onSearchKeyDown.bind(this), true);
92 this._searchInputElement.addEventListener('input', this._onInput.bind(this), false);
93
94 this._replaceInputElement =
95 searchInputElements.createChild('input', 'search-replace toolbar-replace-control hidden');
96 this._replaceInputElement.addEventListener('keydown', this._onReplaceKeyDown.bind(this), true);
Paul Lewis17e384e2020-01-08 15:46:5197 this._replaceInputElement.placeholder = Common.UIString.UIString('Replace');
Blink Reformat4c46d092018-04-07 15:32:3798
99 this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons');
100 const firstRowButtons = this._buttonsContainer.createChild('div', 'first-row-buttons');
101
Paul Lewis9950e182019-12-16 16:06:07102 const toolbar = new Toolbar('toolbar-search-options', firstRowButtons);
Blink Reformat4c46d092018-04-07 15:32:37103
104 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51105 this._caseSensitiveButton = new ToolbarToggle(Common.UIString.UIString('Match Case'));
Blink Reformat4c46d092018-04-07 15:32:37106 this._caseSensitiveButton.setText('Aa');
Paul Lewis9950e182019-12-16 16:06:07107 this._caseSensitiveButton.addEventListener(ToolbarButton.Events.Click, this._toggleCaseSensitiveSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37108 toolbar.appendToolbarItem(this._caseSensitiveButton);
109 }
110
111 if (this._searchProvider.supportsRegexSearch()) {
Paul Lewis17e384e2020-01-08 15:46:51112 this._regexButton = new ToolbarToggle(Common.UIString.UIString('Use Regular Expression'));
Blink Reformat4c46d092018-04-07 15:32:37113 this._regexButton.setText('.*');
Paul Lewis9950e182019-12-16 16:06:07114 this._regexButton.addEventListener(ToolbarButton.Events.Click, this._toggleRegexSearch, this);
Blink Reformat4c46d092018-04-07 15:32:37115 toolbar.appendToolbarItem(this._regexButton);
116 }
117
118 const cancelButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51119 createTextButton(Common.UIString.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37120 firstRowButtons.appendChild(cancelButtonElement);
121
122 this._secondRowButtons = this._buttonsContainer.createChild('div', 'second-row-buttons hidden');
123
124 this._replaceButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51125 createTextButton(Common.UIString.UIString('Replace'), this._replace.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37126 this._replaceButtonElement.disabled = true;
127 this._secondRowButtons.appendChild(this._replaceButtonElement);
128
129 this._replaceAllButtonElement =
Paul Lewis17e384e2020-01-08 15:46:51130 createTextButton(Common.UIString.UIString('Replace all'), this._replaceAll.bind(this), 'search-action-button');
Blink Reformat4c46d092018-04-07 15:32:37131 this._secondRowButtons.appendChild(this._replaceAllButtonElement);
132 this._replaceAllButtonElement.disabled = true;
133
134 this._minimalSearchQuerySize = 3;
135 this._loadSetting();
136 }
137
138 /**
139 * @param {?Element} element
Tim van der Lippe0830b3d2019-10-03 13:20:07140 * @return {?SearchableView}
Blink Reformat4c46d092018-04-07 15:32:37141 */
142 static fromElement(element) {
143 let view = null;
144 while (element && !view) {
Tim van der Lippe0830b3d2019-10-03 13:20:07145 view = element[_symbol];
Blink Reformat4c46d092018-04-07 15:32:37146 element = element.parentElementOrShadowHost();
147 }
148 return view;
149 }
150
151 _toggleCaseSensitiveSearch() {
152 this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled());
153 this._saveSetting();
154 this._performSearch(false, true);
155 }
156
157 _toggleRegexSearch() {
158 this._regexButton.setToggled(!this._regexButton.toggled());
159 this._saveSetting();
160 this._performSearch(false, true);
161 }
162
163 _toggleReplace() {
164 this._replaceToggleButton.setToggled(!this._replaceToggleButton.toggled());
165 this._updateSecondRowVisibility();
166 }
167
168 _saveSetting() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34169 if (!this._setting) {
Blink Reformat4c46d092018-04-07 15:32:37170 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34171 }
Blink Reformat4c46d092018-04-07 15:32:37172 const settingValue = this._setting.get() || {};
173 settingValue.caseSensitive = this._caseSensitiveButton.toggled();
174 settingValue.isRegex = this._regexButton.toggled();
175 this._setting.set(settingValue);
176 }
177
178 _loadSetting() {
179 const settingValue = this._setting ? (this._setting.get() || {}) : {};
Tim van der Lippe1d6e57a2019-09-30 11:55:34180 if (this._searchProvider.supportsCaseSensitiveSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37181 this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive);
Tim van der Lippe1d6e57a2019-09-30 11:55:34182 }
183 if (this._searchProvider.supportsRegexSearch()) {
Blink Reformat4c46d092018-04-07 15:32:37184 this._regexButton.setToggled(!!settingValue.isRegex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34185 }
Blink Reformat4c46d092018-04-07 15:32:37186 }
187
188 /**
189 * @param {number} minimalSearchQuerySize
190 */
191 setMinimalSearchQuerySize(minimalSearchQuerySize) {
192 this._minimalSearchQuerySize = minimalSearchQuerySize;
193 }
194
195 /**
196 * @param {string} placeholder
197 */
198 setPlaceholder(placeholder) {
199 this._searchInputElement.placeholder = placeholder;
200 }
201
202 /**
203 * @param {boolean} replaceable
204 */
205 setReplaceable(replaceable) {
206 this._replaceable = replaceable;
207 }
208
209 /**
210 * @param {number} matches
Tim van der Lippe0830b3d2019-10-03 13:20:07211 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37212 */
213 updateSearchMatchesCount(matches) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34214 if (this._searchProvider.currentSearchMatches === matches) {
Blink Reformat4c46d092018-04-07 15:32:37215 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34216 }
Blink Reformat4c46d092018-04-07 15:32:37217 this._searchProvider.currentSearchMatches = matches;
218 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
219 }
220
221 /**
222 * @param {number} currentMatchIndex
Tim van der Lippe0830b3d2019-10-03 13:20:07223 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37224 */
225 updateCurrentMatchIndex(currentMatchIndex) {
226 this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
227 }
228
229 /**
230 * @return {boolean}
231 */
232 isSearchVisible() {
233 return this._searchIsVisible;
234 }
235
236 closeSearch() {
237 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34238 if (this._footerElementContainer.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:37239 this.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34240 }
Blink Reformat4c46d092018-04-07 15:32:37241 }
242
243 _toggleSearchBar(toggled) {
244 this._footerElementContainer.classList.toggle('hidden', !toggled);
245 this.doResize();
246 }
247
248 cancelSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37250 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 }
Blink Reformat4c46d092018-04-07 15:32:37252 this.resetSearch();
253 delete this._searchIsVisible;
254 this._toggleSearchBar(false);
255 }
256
257 resetSearch() {
258 this._clearSearch();
259 this._updateReplaceVisibility();
260 this._matchesElement.textContent = '';
261 }
262
263 refreshSearch() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34264 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37265 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34266 }
Blink Reformat4c46d092018-04-07 15:32:37267 this.resetSearch();
268 this._performSearch(false, false);
269 }
270
271 /**
272 * @return {boolean}
273 */
274 handleFindNextShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34275 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37276 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34277 }
Blink Reformat4c46d092018-04-07 15:32:37278 this._searchProvider.jumpToNextSearchResult();
279 return true;
280 }
281
282 /**
283 * @return {boolean}
284 */
285 handleFindPreviousShortcut() {
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.jumpToPreviousSearchResult();
290 return true;
291 }
292
293 /**
294 * @return {boolean}
295 */
296 handleFindShortcut() {
297 this.showSearchField();
298 return true;
299 }
300
301 /**
302 * @return {boolean}
303 */
304 handleCancelSearchShortcut() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34305 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37306 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34307 }
Blink Reformat4c46d092018-04-07 15:32:37308 this.closeSearch();
309 return true;
310 }
311
312 /**
313 * @param {boolean} enabled
314 */
315 _updateSearchNavigationButtonState(enabled) {
316 this._replaceButtonElement.disabled = !enabled;
317 this._replaceAllButtonElement.disabled = !enabled;
318 this._searchNavigationPrevElement.classList.toggle('enabled', enabled);
319 this._searchNavigationNextElement.classList.toggle('enabled', enabled);
320 }
321
322 /**
323 * @param {number} matches
324 * @param {number} currentMatchIndex
325 */
326 _updateSearchMatchesCountAndCurrentMatchIndex(matches, currentMatchIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34327 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37328 this._matchesElement.textContent = '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34329 } else if (matches === 0 || currentMatchIndex >= 0) {
Paul Lewis17e384e2020-01-08 15:46:51330 this._matchesElement.textContent = Common.UIString.UIString('%d of %d', currentMatchIndex + 1, matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34331 } else if (matches === 1) {
Paul Lewis17e384e2020-01-08 15:46:51332 this._matchesElement.textContent = Common.UIString.UIString('1 match');
Tim van der Lippe1d6e57a2019-09-30 11:55:34333 } else {
Paul Lewis17e384e2020-01-08 15:46:51334 this._matchesElement.textContent = Common.UIString.UIString('%d matches', matches);
Tim van der Lippe1d6e57a2019-09-30 11:55:34335 }
Blink Reformat4c46d092018-04-07 15:32:37336 this._updateSearchNavigationButtonState(matches > 0);
337 }
338
339 showSearchField() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34340 if (this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37341 this.cancelSearch();
Tim van der Lippe1d6e57a2019-09-30 11:55:34342 }
Blink Reformat4c46d092018-04-07 15:32:37343
344 let queryCandidate;
345 if (!this._searchInputElement.hasFocus()) {
Paul Lewis0a7c6b62020-01-23 16:16:22346 const selection = self.UI.inspectorView.element.window().getSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 if (selection.rangeCount) {
Blink Reformat4c46d092018-04-07 15:32:37348 queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Tim van der Lippe1d6e57a2019-09-30 11:55:34349 }
Blink Reformat4c46d092018-04-07 15:32:37350 }
351
352 this._toggleSearchBar(true);
353 this._updateReplaceVisibility();
Tim van der Lippe1d6e57a2019-09-30 11:55:34354 if (queryCandidate) {
Blink Reformat4c46d092018-04-07 15:32:37355 this._searchInputElement.value = queryCandidate;
Tim van der Lippe1d6e57a2019-09-30 11:55:34356 }
Blink Reformat4c46d092018-04-07 15:32:37357 this._performSearch(false, false);
358 this._searchInputElement.focus();
359 this._searchInputElement.select();
360 this._searchIsVisible = true;
361 }
362
363 _updateReplaceVisibility() {
364 this._replaceToggleButton.setVisible(this._replaceable);
365 if (!this._replaceable) {
366 this._replaceToggleButton.setToggled(false);
367 this._updateSecondRowVisibility();
368 }
369 }
370
371 /**
372 * @param {!Event} event
373 */
374 _onSearchKeyDown(event) {
375 if (isEscKey(event)) {
376 this.closeSearch();
377 event.consume(true);
378 return;
379 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34380 if (!isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37381 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34382 }
Blink Reformat4c46d092018-04-07 15:32:37383
Tim van der Lippe1d6e57a2019-09-30 11:55:34384 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37385 this._performSearch(true, true, event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34386 } else {
Blink Reformat4c46d092018-04-07 15:32:37387 this._jumpToNextSearchResult(event.shiftKey);
Tim van der Lippe1d6e57a2019-09-30 11:55:34388 }
Blink Reformat4c46d092018-04-07 15:32:37389 }
390
391 /**
392 * @param {!Event} event
393 */
394 _onReplaceKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34395 if (isEnterKey(event)) {
Blink Reformat4c46d092018-04-07 15:32:37396 this._replace();
Tim van der Lippe1d6e57a2019-09-30 11:55:34397 }
Blink Reformat4c46d092018-04-07 15:32:37398 }
399
400 /**
401 * @param {boolean=} isBackwardSearch
402 */
403 _jumpToNextSearchResult(isBackwardSearch) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34404 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37405 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 }
Blink Reformat4c46d092018-04-07 15:32:37407
Tim van der Lippe1d6e57a2019-09-30 11:55:34408 if (isBackwardSearch) {
Blink Reformat4c46d092018-04-07 15:32:37409 this._searchProvider.jumpToPreviousSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34410 } else {
Blink Reformat4c46d092018-04-07 15:32:37411 this._searchProvider.jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34412 }
Blink Reformat4c46d092018-04-07 15:32:37413 }
414
415 _onNextButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34416 if (!this._searchNavigationNextElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37417 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34418 }
Blink Reformat4c46d092018-04-07 15:32:37419 this._jumpToNextSearchResult();
420 this._searchInputElement.focus();
421 }
422
423 _onPrevButtonSearch(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34424 if (!this._searchNavigationPrevElement.classList.contains('enabled')) {
Blink Reformat4c46d092018-04-07 15:32:37425 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34426 }
Blink Reformat4c46d092018-04-07 15:32:37427 this._jumpToNextSearchResult(true);
428 this._searchInputElement.focus();
429 }
430
431 _onFindClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34432 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37433 this._performSearch(true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34434 } else {
Blink Reformat4c46d092018-04-07 15:32:37435 this._jumpToNextSearchResult();
Tim van der Lippe1d6e57a2019-09-30 11:55:34436 }
Blink Reformat4c46d092018-04-07 15:32:37437 this._searchInputElement.focus();
438 }
439
440 _onPreviousClick(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34441 if (!this._currentQuery) {
Blink Reformat4c46d092018-04-07 15:32:37442 this._performSearch(true, true, true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34443 } else {
Blink Reformat4c46d092018-04-07 15:32:37444 this._jumpToNextSearchResult(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34445 }
Blink Reformat4c46d092018-04-07 15:32:37446 this._searchInputElement.focus();
447 }
448
Tim van der Lippe0830b3d2019-10-03 13:20:07449 /** @suppress {checkTypes} */
Blink Reformat4c46d092018-04-07 15:32:37450 _clearSearch() {
451 delete this._currentQuery;
452 if (!!this._searchProvider.currentQuery) {
453 delete this._searchProvider.currentQuery;
454 this._searchProvider.searchCanceled();
455 }
456 this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
457 }
458
459 /**
460 * @param {boolean} forceSearch
461 * @param {boolean} shouldJump
462 * @param {boolean=} jumpBackwards
Tim van der Lippe0830b3d2019-10-03 13:20:07463 * @suppress {checkTypes}
Blink Reformat4c46d092018-04-07 15:32:37464 */
465 _performSearch(forceSearch, shouldJump, jumpBackwards) {
466 const query = this._searchInputElement.value;
467 if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
468 this._clearSearch();
469 return;
470 }
471
472 this._currentQuery = query;
473 this._searchProvider.currentQuery = query;
474
475 const searchConfig = this._currentSearchConfig();
476 this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
477 }
478
479 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07480 * @return {!SearchConfig}
Blink Reformat4c46d092018-04-07 15:32:37481 */
482 _currentSearchConfig() {
483 const query = this._searchInputElement.value;
484 const caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false;
485 const isRegex = this._regexButton ? this._regexButton.toggled() : false;
Tim van der Lippe0830b3d2019-10-03 13:20:07486 return new SearchConfig(query, caseSensitive, isRegex);
Blink Reformat4c46d092018-04-07 15:32:37487 }
488
489 _updateSecondRowVisibility() {
490 const secondRowVisible = this._replaceToggleButton.toggled();
491 this._footerElementContainer.classList.toggle('replaceable', secondRowVisible);
492 this._secondRowButtons.classList.toggle('hidden', !secondRowVisible);
493 this._replaceInputElement.classList.toggle('hidden', !secondRowVisible);
494
Tim van der Lippe1d6e57a2019-09-30 11:55:34495 if (secondRowVisible) {
Blink Reformat4c46d092018-04-07 15:32:37496 this._replaceInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34497 } else {
Blink Reformat4c46d092018-04-07 15:32:37498 this._searchInputElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34499 }
Blink Reformat4c46d092018-04-07 15:32:37500 this.doResize();
501 }
502
503 _replace() {
504 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07505 /** @type {!Replaceable} */ (this._searchProvider)
Blink Reformat4c46d092018-04-07 15:32:37506 .replaceSelectionWith(searchConfig, this._replaceInputElement.value);
507 delete this._currentQuery;
508 this._performSearch(true, true);
509 }
510
511 _replaceAll() {
512 const searchConfig = this._currentSearchConfig();
Paul Lewis9950e182019-12-16 16:06:07513 /** @type {!Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
Blink Reformat4c46d092018-04-07 15:32:37514 }
515
516 /**
517 * @param {!Event} event
518 */
519 _onInput(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34520 if (this._valueChangedTimeoutId) {
Blink Reformat4c46d092018-04-07 15:32:37521 clearTimeout(this._valueChangedTimeoutId);
Tim van der Lippe1d6e57a2019-09-30 11:55:34522 }
Blink Reformat4c46d092018-04-07 15:32:37523 const timeout = this._searchInputElement.value.length < 3 ? 200 : 0;
524 this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout);
525 }
526
527 _onValueChanged() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34528 if (!this._searchIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:37529 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34530 }
Blink Reformat4c46d092018-04-07 15:32:37531 delete this._valueChangedTimeoutId;
532 this._performSearch(false, true);
533 }
Tim van der Lippe0830b3d2019-10-03 13:20:07534}
Blink Reformat4c46d092018-04-07 15:32:37535
Tim van der Lippe0830b3d2019-10-03 13:20:07536export const _symbol = Symbol('searchableView');
Blink Reformat4c46d092018-04-07 15:32:37537
538
539/**
540 * @interface
541 */
Tim van der Lippe0830b3d2019-10-03 13:20:07542export class Searchable {
543 searchCanceled() {
544 }
Blink Reformat4c46d092018-04-07 15:32:37545
546 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07547 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37548 * @param {boolean} shouldJump
549 * @param {boolean=} jumpBackwards
550 */
Tim van der Lippe0830b3d2019-10-03 13:20:07551 performSearch(searchConfig, shouldJump, jumpBackwards) {
552 }
Blink Reformat4c46d092018-04-07 15:32:37553
Tim van der Lippe0830b3d2019-10-03 13:20:07554 jumpToNextSearchResult() {
555 }
Blink Reformat4c46d092018-04-07 15:32:37556
Tim van der Lippe0830b3d2019-10-03 13:20:07557 jumpToPreviousSearchResult() {
558 }
Blink Reformat4c46d092018-04-07 15:32:37559
560 /**
561 * @return {boolean}
562 */
Tim van der Lippe0830b3d2019-10-03 13:20:07563 supportsCaseSensitiveSearch() {
564 }
Blink Reformat4c46d092018-04-07 15:32:37565
566 /**
567 * @return {boolean}
568 */
569 supportsRegexSearch() {}
Tim van der Lippe0830b3d2019-10-03 13:20:07570}
Blink Reformat4c46d092018-04-07 15:32:37571
572/**
573 * @interface
574 */
Tim van der Lippe0830b3d2019-10-03 13:20:07575export class Replaceable {
Blink Reformat4c46d092018-04-07 15:32:37576 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07577 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37578 * @param {string} replacement
579 */
Tim van der Lippe0830b3d2019-10-03 13:20:07580 replaceSelectionWith(searchConfig, replacement) {
581 }
Blink Reformat4c46d092018-04-07 15:32:37582
583 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07584 * @param {!SearchConfig} searchConfig
Blink Reformat4c46d092018-04-07 15:32:37585 * @param {string} replacement
586 */
587 replaceAllWith(searchConfig, replacement) {}
Tim van der Lippe0830b3d2019-10-03 13:20:07588}
Blink Reformat4c46d092018-04-07 15:32:37589
590/**
591 * @unrestricted
592 */
Tim van der Lippe0830b3d2019-10-03 13:20:07593export class SearchConfig {
Blink Reformat4c46d092018-04-07 15:32:37594 /**
595 * @param {string} query
596 * @param {boolean} caseSensitive
597 * @param {boolean} isRegex
598 */
599 constructor(query, caseSensitive, isRegex) {
600 this.query = query;
601 this.caseSensitive = caseSensitive;
602 this.isRegex = isRegex;
603 }
604
605 /**
606 * @param {boolean=} global
607 * @return {!RegExp}
608 */
609 toSearchRegex(global) {
610 let modifiers = this.caseSensitive ? '' : 'i';
Tim van der Lippe1d6e57a2019-09-30 11:55:34611 if (global) {
Blink Reformat4c46d092018-04-07 15:32:37612 modifiers += 'g';
Tim van der Lippe1d6e57a2019-09-30 11:55:34613 }
Blink Reformat4c46d092018-04-07 15:32:37614 const query = this.isRegex ? '/' + this.query + '/' : this.query;
615
616 let regex;
617
618 // First try creating regex if user knows the / / hint.
619 try {
620 if (/^\/.+\/$/.test(query)) {
621 regex = new RegExp(query.substring(1, query.length - 1), modifiers);
622 regex.__fromRegExpQuery = true;
623 }
624 } catch (e) {
625 // Silent catch.
626 }
627
628 // Otherwise just do a plain text search.
Tim van der Lippe1d6e57a2019-09-30 11:55:34629 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37630 regex = createPlainTextSearchRegex(query, modifiers);
Tim van der Lippe1d6e57a2019-09-30 11:55:34631 }
Blink Reformat4c46d092018-04-07 15:32:37632
633 return regex;
634 }
Tim van der Lippe0830b3d2019-10-03 13:20:07635}