Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / components / SearchableView.js
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
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
32 /**
33  * @constructor
34  * @extends {WebInspector.VBox}
35  * @param {!WebInspector.Searchable} searchable
36  * @param {string=} settingName
37  */
38 WebInspector.SearchableView = function(searchable, settingName)
39 {
40     WebInspector.VBox.call(this);
41
42     this._searchProvider = searchable;
43     this._settingName = settingName;
44
45     this.element.addEventListener("keydown", this._onKeyDown.bind(this), false);
46
47     this._footerElementContainer = this.element.createChild("div", "search-bar status-bar hidden");
48     this._footerElementContainer.style.order = 100;
49
50     this._footerElement = this._footerElementContainer.createChild("table", "toolbar-search");
51     this._footerElement.cellSpacing = 0;
52
53     this._firstRowElement = this._footerElement.createChild("tr");
54     this._secondRowElement = this._footerElement.createChild("tr", "hidden");
55
56     if (this._searchProvider.supportsCaseSensitiveSearch() || this._searchProvider.supportsRegexSearch()) {
57         var searchSettingsPrefixColumn = this._firstRowElement.createChild("td");
58         searchSettingsPrefixColumn.createChild("div", "search-settings-prefix")
59         this._secondRowElement.createChild("td");
60     }
61
62     if (this._searchProvider.supportsCaseSensitiveSearch()) {
63         var caseSensitiveColumn = this._firstRowElement.createChild("td");
64         this._caseSensitiveButton = new WebInspector.StatusBarTextButton(WebInspector.UIString("Case sensitive"), "case-sensitive-search", "Aa", 2);
65         this._caseSensitiveButton.addEventListener("click", this._toggleCaseSensitiveSearch, this);
66         caseSensitiveColumn.appendChild(this._caseSensitiveButton.element);
67         this._secondRowElement.createChild("td");
68     }
69
70     if (this._searchProvider.supportsRegexSearch()) {
71         var regexColumn = this._firstRowElement.createChild("td");
72         this._regexButton = new WebInspector.StatusBarTextButton(WebInspector.UIString("Regex"), "regex-search", ".*", 2);
73         this._regexButton.addEventListener("click", this._toggleRegexSearch, this);
74         regexColumn.appendChild(this._regexButton.element);
75         this._secondRowElement.createChild("td");
76     }
77
78     // Column 1
79     var searchControlElementColumn = this._firstRowElement.createChild("td");
80     this._searchControlElement = searchControlElementColumn.createChild("span", "toolbar-search-control");
81     this._searchInputElement = this._searchControlElement.createChild("input", "search-replace");
82     this._searchInputElement.id = "search-input-field";
83     this._searchInputElement.placeholder = WebInspector.UIString("Find");
84
85     this._matchesElement = this._searchControlElement.createChild("label", "search-results-matches");
86     this._matchesElement.setAttribute("for", "search-input-field");
87
88     this._searchNavigationElement = this._searchControlElement.createChild("div", "toolbar-search-navigation-controls");
89
90     this._searchNavigationPrevElement = this._searchNavigationElement.createChild("div", "toolbar-search-navigation toolbar-search-navigation-prev");
91     this._searchNavigationPrevElement.addEventListener("click", this._onPrevButtonSearch.bind(this), false);
92     this._searchNavigationPrevElement.title = WebInspector.UIString("Search Previous");
93
94     this._searchNavigationNextElement = this._searchNavigationElement.createChild("div", "toolbar-search-navigation toolbar-search-navigation-next");
95     this._searchNavigationNextElement.addEventListener("click", this._onNextButtonSearch.bind(this), false);
96     this._searchNavigationNextElement.title = WebInspector.UIString("Search Next");
97
98     this._searchInputElement.addEventListener("mousedown", this._onSearchFieldManualFocus.bind(this), false); // when the search field is manually selected
99     this._searchInputElement.addEventListener("keydown", this._onSearchKeyDown.bind(this), true);
100     this._searchInputElement.addEventListener("input", this._onInput.bind(this), false);
101
102     this._replaceInputElement = this._secondRowElement.createChild("td").createChild("input", "search-replace toolbar-replace-control");
103     this._replaceInputElement.addEventListener("keydown", this._onReplaceKeyDown.bind(this), true);
104     this._replaceInputElement.placeholder = WebInspector.UIString("Replace");
105
106     // Column 2
107     this._findButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button hidden");
108     this._findButtonElement.textContent = WebInspector.UIString("Find");
109     this._findButtonElement.tabIndex = -1;
110     this._findButtonElement.addEventListener("click", this._onFindClick.bind(this), false);
111
112     this._replaceButtonElement = this._secondRowElement.createChild("td").createChild("button", "search-action-button");
113     this._replaceButtonElement.textContent = WebInspector.UIString("Replace");
114     this._replaceButtonElement.disabled = true;
115     this._replaceButtonElement.tabIndex = -1;
116     this._replaceButtonElement.addEventListener("click", this._replace.bind(this), false);
117
118     // Column 3
119     this._prevButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button hidden");
120     this._prevButtonElement.textContent = WebInspector.UIString("Previous");
121     this._prevButtonElement.tabIndex = -1;
122     this._prevButtonElement.addEventListener("click", this._onPreviousClick.bind(this), false);
123
124     this._replaceAllButtonElement = this._secondRowElement.createChild("td").createChild("button", "search-action-button");
125     this._replaceAllButtonElement.textContent = WebInspector.UIString("Replace All");
126     this._replaceAllButtonElement.addEventListener("click", this._replaceAll.bind(this), false);
127
128     // Column 4
129     this._replaceElement = this._firstRowElement.createChild("td").createChild("span");
130
131     this._replaceCheckboxElement = this._replaceElement.createChild("input");
132     this._replaceCheckboxElement.type = "checkbox";
133     this._uniqueId = ++WebInspector.SearchableView._lastUniqueId;
134     var replaceCheckboxId = "search-replace-trigger" + this._uniqueId;
135     this._replaceCheckboxElement.id = replaceCheckboxId;
136     this._replaceCheckboxElement.addEventListener("change", this._updateSecondRowVisibility.bind(this), false);
137
138     this._replaceLabelElement = this._replaceElement.createChild("label");
139     this._replaceLabelElement.textContent = WebInspector.UIString("Replace");
140     this._replaceLabelElement.setAttribute("for", replaceCheckboxId);
141
142     // Column 5
143     var cancelButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button");
144     cancelButtonElement.textContent = WebInspector.UIString("Cancel");
145     cancelButtonElement.tabIndex = -1;
146     cancelButtonElement.addEventListener("click", this.closeSearch.bind(this), false);
147     this._minimalSearchQuerySize = 3;
148
149     this._registerShortcuts();
150     this._loadSetting();
151 }
152
153 WebInspector.SearchableView._lastUniqueId = 0;
154
155 /**
156  * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>}
157  */
158 WebInspector.SearchableView.findShortcuts = function()
159 {
160     if (WebInspector.SearchableView._findShortcuts)
161         return WebInspector.SearchableView._findShortcuts;
162     WebInspector.SearchableView._findShortcuts = [WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta)];
163     if (!WebInspector.isMac())
164         WebInspector.SearchableView._findShortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F3));
165     return WebInspector.SearchableView._findShortcuts;
166 }
167
168 /**
169  * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>}
170  */
171 WebInspector.SearchableView.cancelSearchShortcuts = function()
172 {
173     if (WebInspector.SearchableView._cancelSearchShortcuts)
174         return WebInspector.SearchableView._cancelSearchShortcuts;
175     WebInspector.SearchableView._cancelSearchShortcuts = [WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Esc)];
176     return WebInspector.SearchableView._cancelSearchShortcuts;
177 }
178
179 /**
180  * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>}
181  */
182 WebInspector.SearchableView.findNextShortcut = function()
183 {
184     if (WebInspector.SearchableView._findNextShortcut)
185         return WebInspector.SearchableView._findNextShortcut;
186     WebInspector.SearchableView._findNextShortcut = [];
187     if (WebInspector.isMac())
188         WebInspector.SearchableView._findNextShortcut.push(WebInspector.KeyboardShortcut.makeDescriptor("g", WebInspector.KeyboardShortcut.Modifiers.Meta));
189     return WebInspector.SearchableView._findNextShortcut;
190 }
191
192 /**
193  * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>}
194  */
195 WebInspector.SearchableView.findPreviousShortcuts = function()
196 {
197     if (WebInspector.SearchableView._findPreviousShortcuts)
198         return WebInspector.SearchableView._findPreviousShortcuts;
199     WebInspector.SearchableView._findPreviousShortcuts = [];
200     if (WebInspector.isMac())
201         WebInspector.SearchableView._findPreviousShortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor("g", WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Shift));
202     return WebInspector.SearchableView._findPreviousShortcuts;
203 }
204
205 WebInspector.SearchableView.prototype = {
206     _toggleCaseSensitiveSearch: function()
207     {
208         this._caseSensitiveButton.toggled = !this._caseSensitiveButton.toggled;
209         this._saveSetting();
210         this._performSearch(false, true);
211     },
212
213     _toggleRegexSearch: function()
214     {
215         this._regexButton.toggled = !this._regexButton.toggled;
216         this._saveSetting();
217         this._performSearch(false, true);
218     },
219
220     /**
221      * @return {?WebInspector.Setting}
222      */
223     _setting: function()
224     {
225         if (!this._settingName)
226             return null;
227         if (!WebInspector.settings[this._settingName])
228             WebInspector.settings[this._settingName] = WebInspector.settings.createSetting(this._settingName, {});
229         return WebInspector.settings[this._settingName];
230     },
231
232     _saveSetting: function()
233     {
234         var setting = this._setting();
235         if (!setting)
236             return;
237         var settingValue = setting.get() || {};
238         settingValue.caseSensitive = this._caseSensitiveButton.toggled;
239         settingValue.isRegex = this._regexButton.toggled;
240         setting.set(settingValue);
241     },
242
243     _loadSetting: function()
244     {
245         var settingValue = this._setting() ? (this._setting().get() || {}) : {};
246         if (this._searchProvider.supportsCaseSensitiveSearch())
247             this._caseSensitiveButton.toggled = !!settingValue.caseSensitive;
248         if (this._searchProvider.supportsRegexSearch())
249             this._regexButton.toggled = !!settingValue.isRegex;
250     },
251
252     /**
253      * @return {!Element}
254      */
255     defaultFocusedElement: function()
256     {
257         var children = this.children();
258         for (var i = 0; i < children.length; ++i) {
259             var element = children[i].defaultFocusedElement();
260             if (element)
261                 return element;
262         }
263         return WebInspector.View.prototype.defaultFocusedElement.call(this);
264     },
265
266     /**
267      * @param {!Event} event
268      */
269     _onKeyDown: function(event)
270     {
271         var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(/**@type {!KeyboardEvent}*/(event));
272         var handler = this._shortcuts[shortcutKey];
273         if (handler && handler(event))
274             event.consume(true);
275     },
276
277     _registerShortcuts: function()
278     {
279         this._shortcuts = {};
280
281         /**
282          * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts
283          * @param {function()} handler
284          * @this {WebInspector.SearchableView}
285          */
286         function register(shortcuts, handler)
287         {
288             for (var i = 0; i < shortcuts.length; ++i)
289                 this._shortcuts[shortcuts[i].key] = handler;
290         }
291
292         register.call(this, WebInspector.SearchableView.findShortcuts(), this.handleFindShortcut.bind(this));
293         register.call(this, WebInspector.SearchableView.cancelSearchShortcuts(), this.handleCancelSearchShortcut.bind(this));
294         register.call(this, WebInspector.SearchableView.findNextShortcut(), this.handleFindNextShortcut.bind(this));
295         register.call(this, WebInspector.SearchableView.findPreviousShortcuts(), this.handleFindPreviousShortcut.bind(this));
296     },
297
298     /**
299      * @param {number} minimalSearchQuerySize
300      */
301     setMinimalSearchQuerySize: function(minimalSearchQuerySize)
302     {
303         this._minimalSearchQuerySize = minimalSearchQuerySize;
304     },
305
306     /**
307      * @param {boolean} replaceable
308      */
309     setReplaceable: function(replaceable)
310     {
311         this._replaceable = replaceable;
312     },
313
314     /**
315      * @param {number} matches
316      */
317     updateSearchMatchesCount: function(matches)
318     {
319         this._searchProvider.currentSearchMatches = matches;
320         this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1);
321     },
322
323     /**
324      * @param {number} currentMatchIndex
325      */
326     updateCurrentMatchIndex: function(currentMatchIndex)
327     {
328         this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex);
329     },
330
331     /**
332      * @return {boolean}
333      */
334     isSearchVisible: function()
335     {
336         return this._searchIsVisible;
337     },
338
339     closeSearch: function()
340     {
341         this.cancelSearch();
342         if (WebInspector.currentFocusElement().isDescendant(this._footerElementContainer))
343             this.focus();
344     },
345
346     _toggleSearchBar: function(toggled)
347     {
348         this._footerElementContainer.classList.toggle("hidden", !toggled);
349         this.doResize();
350     },
351
352     cancelSearch: function()
353     {
354         if (!this._searchIsVisible)
355             return;
356         this.resetSearch();
357         delete this._searchIsVisible;
358         this._toggleSearchBar(false);
359     },
360
361     resetSearch: function()
362     {
363         this._clearSearch();
364         this._updateReplaceVisibility();
365         this._matchesElement.textContent = "";
366     },
367
368     refreshSearch: function()
369     {
370         if (!this._searchIsVisible)
371             return;
372         this.resetSearch();
373         this._performSearch(false, false);
374     },
375
376     /**
377      * @return {boolean}
378      */
379     handleFindNextShortcut: function()
380     {
381         if (!this._searchIsVisible)
382             return false;
383         this._searchProvider.jumpToNextSearchResult();
384         return true;
385     },
386
387     /**
388      * @return {boolean}
389      */
390     handleFindPreviousShortcut: function()
391     {
392         if (!this._searchIsVisible)
393             return false;
394         this._searchProvider.jumpToPreviousSearchResult();
395         return true;
396     },
397
398     /**
399      * @return {boolean}
400      */
401     handleFindShortcut: function()
402     {
403         this.showSearchField();
404         return true;
405     },
406
407     /**
408      * @return {boolean}
409      */
410     handleCancelSearchShortcut: function()
411     {
412         if (!this._searchIsVisible)
413             return false;
414         this.closeSearch();
415         return true;
416     },
417
418     /**
419      * @param {boolean} enabled
420      */
421     _updateSearchNavigationButtonState: function(enabled)
422     {
423         this._replaceButtonElement.disabled = !enabled;
424         if (enabled) {
425             this._searchNavigationPrevElement.classList.add("enabled");
426             this._searchNavigationNextElement.classList.add("enabled");
427         } else {
428             this._searchNavigationPrevElement.classList.remove("enabled");
429             this._searchNavigationNextElement.classList.remove("enabled");
430         }
431     },
432
433     /**
434      * @param {number} matches
435      * @param {number} currentMatchIndex
436      */
437     _updateSearchMatchesCountAndCurrentMatchIndex: function(matches, currentMatchIndex)
438     {
439         if (!this._currentQuery)
440             this._matchesElement.textContent = "";
441         else if (matches === 0 || currentMatchIndex >= 0)
442             this._matchesElement.textContent = WebInspector.UIString("%d of %d", currentMatchIndex + 1, matches);
443         else if (matches === 1)
444             this._matchesElement.textContent = WebInspector.UIString("1 match");
445         else
446             this._matchesElement.textContent = WebInspector.UIString("%d matches", matches);
447         this._updateSearchNavigationButtonState(matches > 0);
448     },
449
450     showSearchField: function()
451     {
452         if (this._searchIsVisible)
453             this.cancelSearch();
454
455         var queryCandidate;
456         if (WebInspector.currentFocusElement() !== this._searchInputElement) {
457             var selection = window.getSelection();
458             if (selection.rangeCount)
459                 queryCandidate = selection.toString().replace(/\r?\n.*/, "");
460         }
461
462         this._toggleSearchBar(true);
463         this._updateReplaceVisibility();
464         if (queryCandidate)
465             this._searchInputElement.value = queryCandidate;
466         this._performSearch(false, false);
467         this._searchInputElement.focus();
468         this._searchInputElement.select();
469         this._searchIsVisible = true;
470     },
471
472     _updateReplaceVisibility: function()
473     {
474         this._replaceElement.classList.toggle("hidden", !this._replaceable);
475         if (!this._replaceable) {
476             this._replaceCheckboxElement.checked = false;
477             this._updateSecondRowVisibility();
478         }
479     },
480
481     /**
482      * @param {!Event} event
483      */
484     _onSearchFieldManualFocus: function(event)
485     {
486         WebInspector.setCurrentFocusElement(event.target);
487     },
488
489     /**
490      * @param {!Event} event
491      */
492     _onSearchKeyDown: function(event)
493     {
494         if (!isEnterKey(event))
495             return;
496
497         if (!this._currentQuery)
498             this._performSearch(true, true, event.shiftKey);
499         else
500             this._jumpToNextSearchResult(event.shiftKey);
501     },
502
503     /**
504      * @param {!Event} event
505      */
506     _onReplaceKeyDown: function(event)
507     {
508         if (isEnterKey(event))
509             this._replace();
510     },
511
512     /**
513      * @param {boolean=} isBackwardSearch
514      */
515     _jumpToNextSearchResult: function(isBackwardSearch)
516     {
517         if (!this._currentQuery || !this._searchNavigationPrevElement.classList.contains("enabled"))
518             return;
519
520         if (isBackwardSearch)
521             this._searchProvider.jumpToPreviousSearchResult();
522         else
523             this._searchProvider.jumpToNextSearchResult();
524     },
525
526     _onNextButtonSearch: function(event)
527     {
528         if (!this._searchNavigationNextElement.classList.contains("enabled"))
529             return;
530         this._jumpToNextSearchResult();
531         this._searchInputElement.focus();
532     },
533
534     _onPrevButtonSearch: function(event)
535     {
536         if (!this._searchNavigationPrevElement.classList.contains("enabled"))
537             return;
538         this._jumpToNextSearchResult(true);
539         this._searchInputElement.focus();
540     },
541
542     _onFindClick: function(event)
543     {
544         if (!this._currentQuery)
545             this._performSearch(true, true);
546         else
547             this._jumpToNextSearchResult();
548         this._searchInputElement.focus();
549     },
550
551     _onPreviousClick: function(event)
552     {
553         if (!this._currentQuery)
554             this._performSearch(true, true, true);
555         else
556             this._jumpToNextSearchResult(true);
557         this._searchInputElement.focus();
558     },
559
560     _clearSearch: function()
561     {
562         delete this._currentQuery;
563         if (!!this._searchProvider.currentQuery) {
564             delete this._searchProvider.currentQuery;
565             this._searchProvider.searchCanceled();
566         }
567         this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1);
568     },
569
570     /**
571      * @param {boolean} forceSearch
572      * @param {boolean} shouldJump
573      * @param {boolean=} jumpBackwards
574      */
575     _performSearch: function(forceSearch, shouldJump, jumpBackwards)
576     {
577         var query = this._searchInputElement.value;
578         if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) {
579             this._clearSearch();
580             return;
581         }
582
583         this._currentQuery = query;
584         this._searchProvider.currentQuery = query;
585
586         var searchConfig = this._currentSearchConfig();
587         this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards);
588     },
589
590     /**
591      * @return {!WebInspector.SearchableView.SearchConfig}
592      */
593     _currentSearchConfig: function()
594     {
595         var query = this._searchInputElement.value;
596         var caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled : false;
597         var isRegex = this._regexButton ? this._regexButton.toggled : false;
598         return new WebInspector.SearchableView.SearchConfig(query, caseSensitive, isRegex);
599      },
600
601     _updateSecondRowVisibility: function()
602     {
603         var secondRowVisible = this._replaceCheckboxElement.checked;
604         this._footerElementContainer.classList.toggle("replaceable", secondRowVisible);
605         this._footerElement.classList.toggle("toolbar-search-replace", secondRowVisible);
606         this._secondRowElement.classList.toggle("hidden", !secondRowVisible);
607         this._prevButtonElement.classList.toggle("hidden", !secondRowVisible);
608         this._findButtonElement.classList.toggle("hidden", !secondRowVisible);
609         this._replaceCheckboxElement.tabIndex = secondRowVisible ? -1 : 0;
610
611         if (secondRowVisible)
612             this._replaceInputElement.focus();
613         else
614             this._searchInputElement.focus();
615         this.doResize();
616     },
617
618     _replace: function()
619     {
620         var searchConfig = this._currentSearchConfig();
621         /** @type {!WebInspector.Replaceable} */ (this._searchProvider).replaceSelectionWith(searchConfig, this._replaceInputElement.value);
622         delete this._currentQuery;
623         this._performSearch(true, true);
624     },
625
626     _replaceAll: function()
627     {
628         var searchConfig = this._currentSearchConfig();
629         /** @type {!WebInspector.Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value);
630     },
631
632     _onInput: function(event)
633     {
634         this._onValueChanged();
635     },
636
637     _onValueChanged: function()
638     {
639         this._performSearch(false, true);
640     },
641
642     __proto__: WebInspector.VBox.prototype
643 }
644
645 /**
646  * @interface
647  */
648 WebInspector.Searchable = function()
649 {
650 }
651
652 WebInspector.Searchable.prototype = {
653     searchCanceled: function() { },
654
655     /**
656      * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
657      * @param {boolean} shouldJump
658      * @param {boolean=} jumpBackwards
659      */
660     performSearch: function(searchConfig, shouldJump, jumpBackwards) { },
661
662     jumpToNextSearchResult: function() { },
663
664     jumpToPreviousSearchResult: function() { },
665
666     /**
667      * @return {boolean}
668      */
669     supportsCaseSensitiveSearch: function() { },
670
671     /**
672      * @return {boolean}
673      */
674     supportsRegexSearch: function() { }
675 }
676
677 /**
678  * @interface
679  */
680 WebInspector.Replaceable = function()
681 {
682 }
683
684 WebInspector.Replaceable.prototype = {
685     /**
686      * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
687      * @param {string} replacement
688      */
689     replaceSelectionWith: function(searchConfig, replacement) { },
690
691     /**
692      * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
693      * @param {string} replacement
694      */
695     replaceAllWith: function(searchConfig, replacement) { }
696 }
697
698 /**
699  * @constructor
700  * @param {string} query
701  * @param {boolean} caseSensitive
702  * @param {boolean} isRegex
703  */
704 WebInspector.SearchableView.SearchConfig = function(query, caseSensitive, isRegex)
705 {
706     this.query = query;
707     this.caseSensitive = caseSensitive;
708     this.isRegex = isRegex;
709 }