| /* |
| * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. |
| * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). |
| * Copyright (C) 2009 Joseph Pecoraro |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.VBox} |
| * @param {!WebInspector.Searchable} searchable |
| * @param {string=} settingName |
| */ |
| WebInspector.SearchableView = function(searchable, settingName) |
| { |
| WebInspector.VBox.call(this, true); |
| this.registerRequiredCSS("ui/searchableView.css"); |
| |
| this._searchProvider = searchable; |
| this._setting = settingName ? WebInspector.settings.createSetting(settingName, {}) : null; |
| |
| this.element.addEventListener("keydown", this._onKeyDown.bind(this), false); |
| |
| this.contentElement.createChild("content"); |
| this._footerElementContainer = this.contentElement.createChild("div", "search-bar hidden"); |
| this._footerElementContainer.style.order = 100; |
| |
| var toolbar = new WebInspector.Toolbar(this._footerElementContainer); |
| |
| if (this._searchProvider.supportsCaseSensitiveSearch()) { |
| this._caseSensitiveButton = new WebInspector.ToolbarTextButton(WebInspector.UIString("Case sensitive"), "case-sensitive-search-toolbar-item", "Aa", 2); |
| this._caseSensitiveButton.addEventListener("click", this._toggleCaseSensitiveSearch, this); |
| toolbar.appendToolbarItem(this._caseSensitiveButton); |
| } |
| |
| if (this._searchProvider.supportsRegexSearch()) { |
| this._regexButton = new WebInspector.ToolbarTextButton(WebInspector.UIString("Regex"), "regex-search-toolbar-item", ".*", 2); |
| this._regexButton.addEventListener("click", this._toggleRegexSearch, this); |
| toolbar.appendToolbarItem(this._regexButton); |
| } |
| |
| this._footerElement = this._footerElementContainer.createChild("table", "toolbar-search"); |
| this._footerElement.cellSpacing = 0; |
| |
| this._firstRowElement = this._footerElement.createChild("tr"); |
| this._secondRowElement = this._footerElement.createChild("tr", "hidden"); |
| |
| // Column 1 |
| var searchControlElementColumn = this._firstRowElement.createChild("td"); |
| this._searchControlElement = searchControlElementColumn.createChild("span", "toolbar-search-control"); |
| |
| this._searchInputElement = WebInspector.HistoryInput.create(); |
| this._searchInputElement.classList.add("search-replace"); |
| this._searchControlElement.appendChild(this._searchInputElement); |
| |
| this._searchInputElement.id = "search-input-field"; |
| this._searchInputElement.placeholder = WebInspector.UIString("Find"); |
| |
| this._matchesElement = this._searchControlElement.createChild("label", "search-results-matches"); |
| this._matchesElement.setAttribute("for", "search-input-field"); |
| |
| this._searchNavigationElement = this._searchControlElement.createChild("div", "toolbar-search-navigation-controls"); |
| |
| this._searchNavigationPrevElement = this._searchNavigationElement.createChild("div", "toolbar-search-navigation toolbar-search-navigation-prev"); |
| this._searchNavigationPrevElement.addEventListener("click", this._onPrevButtonSearch.bind(this), false); |
| this._searchNavigationPrevElement.title = WebInspector.UIString("Search Previous"); |
| |
| this._searchNavigationNextElement = this._searchNavigationElement.createChild("div", "toolbar-search-navigation toolbar-search-navigation-next"); |
| this._searchNavigationNextElement.addEventListener("click", this._onNextButtonSearch.bind(this), false); |
| this._searchNavigationNextElement.title = WebInspector.UIString("Search Next"); |
| |
| this._searchInputElement.addEventListener("mousedown", this._onSearchFieldManualFocus.bind(this), false); // when the search field is manually selected |
| this._searchInputElement.addEventListener("keydown", this._onSearchKeyDown.bind(this), true); |
| this._searchInputElement.addEventListener("input", this._onInput.bind(this), false); |
| |
| this._replaceInputElement = this._secondRowElement.createChild("td").createChild("input", "search-replace toolbar-replace-control"); |
| this._replaceInputElement.addEventListener("keydown", this._onReplaceKeyDown.bind(this), true); |
| this._replaceInputElement.placeholder = WebInspector.UIString("Replace"); |
| |
| // Column 2 |
| this._findButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button hidden"); |
| this._findButtonElement.textContent = WebInspector.UIString("Find"); |
| this._findButtonElement.tabIndex = -1; |
| this._findButtonElement.addEventListener("click", this._onFindClick.bind(this), false); |
| |
| this._replaceButtonElement = this._secondRowElement.createChild("td").createChild("button", "search-action-button"); |
| this._replaceButtonElement.textContent = WebInspector.UIString("Replace"); |
| this._replaceButtonElement.disabled = true; |
| this._replaceButtonElement.tabIndex = -1; |
| this._replaceButtonElement.addEventListener("click", this._replace.bind(this), false); |
| |
| // Column 3 |
| this._prevButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button hidden"); |
| this._prevButtonElement.textContent = WebInspector.UIString("Previous"); |
| this._prevButtonElement.tabIndex = -1; |
| this._prevButtonElement.addEventListener("click", this._onPreviousClick.bind(this), false); |
| |
| this._replaceAllButtonElement = this._secondRowElement.createChild("td").createChild("button", "search-action-button"); |
| this._replaceAllButtonElement.textContent = WebInspector.UIString("Replace All"); |
| this._replaceAllButtonElement.addEventListener("click", this._replaceAll.bind(this), false); |
| |
| // Column 4 |
| this._replaceElement = this._firstRowElement.createChild("td").createChild("span"); |
| |
| this._replaceLabelElement = createCheckboxLabel(WebInspector.UIString("Replace")); |
| this._replaceCheckboxElement = this._replaceLabelElement.checkboxElement; |
| this._uniqueId = ++WebInspector.SearchableView._lastUniqueId; |
| var replaceCheckboxId = "search-replace-trigger" + this._uniqueId; |
| this._replaceCheckboxElement.id = replaceCheckboxId; |
| this._replaceCheckboxElement.addEventListener("change", this._updateSecondRowVisibility.bind(this), false); |
| |
| this._replaceElement.appendChild(this._replaceLabelElement); |
| |
| // Column 5 |
| var cancelButtonElement = this._firstRowElement.createChild("td").createChild("button", "search-action-button"); |
| cancelButtonElement.textContent = WebInspector.UIString("Cancel"); |
| cancelButtonElement.tabIndex = -1; |
| cancelButtonElement.addEventListener("click", this.closeSearch.bind(this), false); |
| this._minimalSearchQuerySize = 3; |
| |
| this._registerShortcuts(); |
| this._loadSetting(); |
| } |
| |
| WebInspector.SearchableView._lastUniqueId = 0; |
| |
| /** |
| * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} |
| */ |
| WebInspector.SearchableView.findShortcuts = function() |
| { |
| if (WebInspector.SearchableView._findShortcuts) |
| return WebInspector.SearchableView._findShortcuts; |
| WebInspector.SearchableView._findShortcuts = [WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta)]; |
| if (!WebInspector.isMac()) |
| WebInspector.SearchableView._findShortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F3)); |
| return WebInspector.SearchableView._findShortcuts; |
| } |
| |
| /** |
| * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} |
| */ |
| WebInspector.SearchableView.cancelSearchShortcuts = function() |
| { |
| if (WebInspector.SearchableView._cancelSearchShortcuts) |
| return WebInspector.SearchableView._cancelSearchShortcuts; |
| WebInspector.SearchableView._cancelSearchShortcuts = [WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Esc)]; |
| return WebInspector.SearchableView._cancelSearchShortcuts; |
| } |
| |
| /** |
| * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} |
| */ |
| WebInspector.SearchableView.findNextShortcut = function() |
| { |
| if (WebInspector.SearchableView._findNextShortcut) |
| return WebInspector.SearchableView._findNextShortcut; |
| WebInspector.SearchableView._findNextShortcut = []; |
| if (WebInspector.isMac()) |
| WebInspector.SearchableView._findNextShortcut.push(WebInspector.KeyboardShortcut.makeDescriptor("g", WebInspector.KeyboardShortcut.Modifiers.Meta)); |
| return WebInspector.SearchableView._findNextShortcut; |
| } |
| |
| /** |
| * @return {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} |
| */ |
| WebInspector.SearchableView.findPreviousShortcuts = function() |
| { |
| if (WebInspector.SearchableView._findPreviousShortcuts) |
| return WebInspector.SearchableView._findPreviousShortcuts; |
| WebInspector.SearchableView._findPreviousShortcuts = []; |
| if (WebInspector.isMac()) |
| WebInspector.SearchableView._findPreviousShortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor("g", WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Shift)); |
| return WebInspector.SearchableView._findPreviousShortcuts; |
| } |
| |
| WebInspector.SearchableView.prototype = { |
| _toggleCaseSensitiveSearch: function() |
| { |
| this._caseSensitiveButton.setToggled(!this._caseSensitiveButton.toggled()); |
| this._saveSetting(); |
| this._performSearch(false, true); |
| }, |
| |
| _toggleRegexSearch: function() |
| { |
| this._regexButton.setToggled(!this._regexButton.toggled()); |
| this._saveSetting(); |
| this._performSearch(false, true); |
| }, |
| |
| _saveSetting: function() |
| { |
| if (!this._setting) |
| return; |
| var settingValue = this._setting.get() || {}; |
| settingValue.caseSensitive = this._caseSensitiveButton.toggled(); |
| settingValue.isRegex = this._regexButton.toggled(); |
| this._setting.set(settingValue); |
| }, |
| |
| _loadSetting: function() |
| { |
| var settingValue = this._setting ? (this._setting.get() || {}) : {}; |
| if (this._searchProvider.supportsCaseSensitiveSearch()) |
| this._caseSensitiveButton.setToggled(!!settingValue.caseSensitive); |
| if (this._searchProvider.supportsRegexSearch()) |
| this._regexButton.setToggled(!!settingValue.isRegex); |
| }, |
| |
| /** |
| * @override |
| * @return {!Element} |
| */ |
| defaultFocusedElement: function() |
| { |
| var children = this.children(); |
| for (var i = 0; i < children.length; ++i) { |
| var element = children[i].defaultFocusedElement(); |
| if (element) |
| return element; |
| } |
| return WebInspector.Widget.prototype.defaultFocusedElement.call(this); |
| }, |
| |
| /** |
| * @param {!Event} event |
| */ |
| _onKeyDown: function(event) |
| { |
| var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(/**@type {!KeyboardEvent}*/(event)); |
| var handler = this._shortcuts[shortcutKey]; |
| if (handler && handler(event)) |
| event.consume(true); |
| }, |
| |
| _registerShortcuts: function() |
| { |
| this._shortcuts = {}; |
| |
| /** |
| * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts |
| * @param {function()} handler |
| * @this {WebInspector.SearchableView} |
| */ |
| function register(shortcuts, handler) |
| { |
| for (var i = 0; i < shortcuts.length; ++i) |
| this._shortcuts[shortcuts[i].key] = handler; |
| } |
| |
| register.call(this, WebInspector.SearchableView.findShortcuts(), this.handleFindShortcut.bind(this)); |
| register.call(this, WebInspector.SearchableView.cancelSearchShortcuts(), this.handleCancelSearchShortcut.bind(this)); |
| register.call(this, WebInspector.SearchableView.findNextShortcut(), this.handleFindNextShortcut.bind(this)); |
| register.call(this, WebInspector.SearchableView.findPreviousShortcuts(), this.handleFindPreviousShortcut.bind(this)); |
| }, |
| |
| /** |
| * @param {number} minimalSearchQuerySize |
| */ |
| setMinimalSearchQuerySize: function(minimalSearchQuerySize) |
| { |
| this._minimalSearchQuerySize = minimalSearchQuerySize; |
| }, |
| |
| /** |
| * @param {string} placeholder |
| */ |
| setPlaceholder: function(placeholder) |
| { |
| this._searchInputElement.placeholder = placeholder; |
| }, |
| |
| /** |
| * @param {boolean} replaceable |
| */ |
| setReplaceable: function(replaceable) |
| { |
| this._replaceable = replaceable; |
| }, |
| |
| /** |
| * @param {number} matches |
| */ |
| updateSearchMatchesCount: function(matches) |
| { |
| this._searchProvider.currentSearchMatches = matches; |
| this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentQuery ? matches : 0, -1); |
| }, |
| |
| /** |
| * @param {number} currentMatchIndex |
| */ |
| updateCurrentMatchIndex: function(currentMatchIndex) |
| { |
| this._updateSearchMatchesCountAndCurrentMatchIndex(this._searchProvider.currentSearchMatches, currentMatchIndex); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| isSearchVisible: function() |
| { |
| return this._searchIsVisible; |
| }, |
| |
| closeSearch: function() |
| { |
| this.cancelSearch(); |
| if (WebInspector.currentFocusElement() && WebInspector.currentFocusElement().isDescendant(this._footerElementContainer)) |
| this.focus(); |
| }, |
| |
| _toggleSearchBar: function(toggled) |
| { |
| this._footerElementContainer.classList.toggle("hidden", !toggled); |
| this.doResize(); |
| }, |
| |
| cancelSearch: function() |
| { |
| if (!this._searchIsVisible) |
| return; |
| this.resetSearch(); |
| delete this._searchIsVisible; |
| this._toggleSearchBar(false); |
| }, |
| |
| resetSearch: function() |
| { |
| this._clearSearch(); |
| this._updateReplaceVisibility(); |
| this._matchesElement.textContent = ""; |
| }, |
| |
| refreshSearch: function() |
| { |
| if (!this._searchIsVisible) |
| return; |
| this.resetSearch(); |
| this._performSearch(false, false); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| handleFindNextShortcut: function() |
| { |
| if (!this._searchIsVisible) |
| return false; |
| this._searchProvider.jumpToNextSearchResult(); |
| return true; |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| handleFindPreviousShortcut: function() |
| { |
| if (!this._searchIsVisible) |
| return false; |
| this._searchProvider.jumpToPreviousSearchResult(); |
| return true; |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| handleFindShortcut: function() |
| { |
| this.showSearchField(); |
| return true; |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| handleCancelSearchShortcut: function() |
| { |
| if (!this._searchIsVisible) |
| return false; |
| this.closeSearch(); |
| return true; |
| }, |
| |
| /** |
| * @param {boolean} enabled |
| */ |
| _updateSearchNavigationButtonState: function(enabled) |
| { |
| this._replaceButtonElement.disabled = !enabled; |
| if (enabled) { |
| this._searchNavigationPrevElement.classList.add("enabled"); |
| this._searchNavigationNextElement.classList.add("enabled"); |
| } else { |
| this._searchNavigationPrevElement.classList.remove("enabled"); |
| this._searchNavigationNextElement.classList.remove("enabled"); |
| } |
| }, |
| |
| /** |
| * @param {number} matches |
| * @param {number} currentMatchIndex |
| */ |
| _updateSearchMatchesCountAndCurrentMatchIndex: function(matches, currentMatchIndex) |
| { |
| if (!this._currentQuery) |
| this._matchesElement.textContent = ""; |
| else if (matches === 0 || currentMatchIndex >= 0) |
| this._matchesElement.textContent = WebInspector.UIString("%d of %d", currentMatchIndex + 1, matches); |
| else if (matches === 1) |
| this._matchesElement.textContent = WebInspector.UIString("1 match"); |
| else |
| this._matchesElement.textContent = WebInspector.UIString("%d matches", matches); |
| this._updateSearchNavigationButtonState(matches > 0); |
| }, |
| |
| showSearchField: function() |
| { |
| if (this._searchIsVisible) |
| this.cancelSearch(); |
| |
| var queryCandidate; |
| if (WebInspector.currentFocusElement() !== this._searchInputElement) { |
| var selection = this._searchInputElement.getComponentSelection(); |
| if (selection.rangeCount) |
| queryCandidate = selection.toString().replace(/\r?\n.*/, ""); |
| } |
| |
| this._toggleSearchBar(true); |
| this._updateReplaceVisibility(); |
| if (queryCandidate) |
| this._searchInputElement.value = queryCandidate; |
| this._performSearch(false, false); |
| this._searchInputElement.focus(); |
| this._searchInputElement.select(); |
| this._searchIsVisible = true; |
| }, |
| |
| _updateReplaceVisibility: function() |
| { |
| this._replaceElement.classList.toggle("hidden", !this._replaceable); |
| if (!this._replaceable) { |
| this._replaceCheckboxElement.checked = false; |
| this._updateSecondRowVisibility(); |
| } |
| }, |
| |
| /** |
| * @param {!Event} event |
| */ |
| _onSearchFieldManualFocus: function(event) |
| { |
| WebInspector.setCurrentFocusElement(/** @type {?Node} */ (event.target)); |
| }, |
| |
| /** |
| * @param {!Event} event |
| */ |
| _onSearchKeyDown: function(event) |
| { |
| if (!isEnterKey(event)) |
| return; |
| |
| if (!this._currentQuery) |
| this._performSearch(true, true, event.shiftKey); |
| else |
| this._jumpToNextSearchResult(event.shiftKey); |
| }, |
| |
| /** |
| * @param {!Event} event |
| */ |
| _onReplaceKeyDown: function(event) |
| { |
| if (isEnterKey(event)) |
| this._replace(); |
| }, |
| |
| /** |
| * @param {boolean=} isBackwardSearch |
| */ |
| _jumpToNextSearchResult: function(isBackwardSearch) |
| { |
| if (!this._currentQuery || !this._searchNavigationPrevElement.classList.contains("enabled")) |
| return; |
| |
| if (isBackwardSearch) |
| this._searchProvider.jumpToPreviousSearchResult(); |
| else |
| this._searchProvider.jumpToNextSearchResult(); |
| }, |
| |
| _onNextButtonSearch: function(event) |
| { |
| if (!this._searchNavigationNextElement.classList.contains("enabled")) |
| return; |
| this._jumpToNextSearchResult(); |
| this._searchInputElement.focus(); |
| }, |
| |
| _onPrevButtonSearch: function(event) |
| { |
| if (!this._searchNavigationPrevElement.classList.contains("enabled")) |
| return; |
| this._jumpToNextSearchResult(true); |
| this._searchInputElement.focus(); |
| }, |
| |
| _onFindClick: function(event) |
| { |
| if (!this._currentQuery) |
| this._performSearch(true, true); |
| else |
| this._jumpToNextSearchResult(); |
| this._searchInputElement.focus(); |
| }, |
| |
| _onPreviousClick: function(event) |
| { |
| if (!this._currentQuery) |
| this._performSearch(true, true, true); |
| else |
| this._jumpToNextSearchResult(true); |
| this._searchInputElement.focus(); |
| }, |
| |
| _clearSearch: function() |
| { |
| delete this._currentQuery; |
| if (!!this._searchProvider.currentQuery) { |
| delete this._searchProvider.currentQuery; |
| this._searchProvider.searchCanceled(); |
| } |
| this._updateSearchMatchesCountAndCurrentMatchIndex(0, -1); |
| }, |
| |
| /** |
| * @param {boolean} forceSearch |
| * @param {boolean} shouldJump |
| * @param {boolean=} jumpBackwards |
| */ |
| _performSearch: function(forceSearch, shouldJump, jumpBackwards) |
| { |
| var query = this._searchInputElement.value; |
| if (!query || (!forceSearch && query.length < this._minimalSearchQuerySize && !this._currentQuery)) { |
| this._clearSearch(); |
| return; |
| } |
| |
| this._currentQuery = query; |
| this._searchProvider.currentQuery = query; |
| |
| var searchConfig = this._currentSearchConfig(); |
| this._searchProvider.performSearch(searchConfig, shouldJump, jumpBackwards); |
| }, |
| |
| /** |
| * @return {!WebInspector.SearchableView.SearchConfig} |
| */ |
| _currentSearchConfig: function() |
| { |
| var query = this._searchInputElement.value; |
| var caseSensitive = this._caseSensitiveButton ? this._caseSensitiveButton.toggled() : false; |
| var isRegex = this._regexButton ? this._regexButton.toggled() : false; |
| return new WebInspector.SearchableView.SearchConfig(query, caseSensitive, isRegex); |
| }, |
| |
| _updateSecondRowVisibility: function() |
| { |
| var secondRowVisible = this._replaceCheckboxElement.checked; |
| this._footerElementContainer.classList.toggle("replaceable", secondRowVisible); |
| this._footerElement.classList.toggle("toolbar-search-replace", secondRowVisible); |
| this._secondRowElement.classList.toggle("hidden", !secondRowVisible); |
| this._prevButtonElement.classList.toggle("hidden", !secondRowVisible); |
| this._findButtonElement.classList.toggle("hidden", !secondRowVisible); |
| this._replaceCheckboxElement.tabIndex = secondRowVisible ? -1 : 0; |
| |
| if (secondRowVisible) |
| this._replaceInputElement.focus(); |
| else |
| this._searchInputElement.focus(); |
| this.doResize(); |
| }, |
| |
| _replace: function() |
| { |
| var searchConfig = this._currentSearchConfig(); |
| /** @type {!WebInspector.Replaceable} */ (this._searchProvider).replaceSelectionWith(searchConfig, this._replaceInputElement.value); |
| delete this._currentQuery; |
| this._performSearch(true, true); |
| }, |
| |
| _replaceAll: function() |
| { |
| var searchConfig = this._currentSearchConfig(); |
| /** @type {!WebInspector.Replaceable} */ (this._searchProvider).replaceAllWith(searchConfig, this._replaceInputElement.value); |
| }, |
| |
| /** |
| * @param {!Event} event |
| */ |
| _onInput: function(event) |
| { |
| if (this._valueChangedTimeoutId) |
| clearTimeout(this._valueChangedTimeoutId); |
| var timeout = this._searchInputElement.value.length < 3 ? 200 : 0; |
| this._valueChangedTimeoutId = setTimeout(this._onValueChanged.bind(this), timeout); |
| }, |
| |
| _onValueChanged: function() |
| { |
| delete this._valueChangedTimeoutId; |
| this._performSearch(false, true); |
| }, |
| |
| __proto__: WebInspector.VBox.prototype |
| } |
| |
| /** |
| * @interface |
| */ |
| WebInspector.Searchable = function() |
| { |
| } |
| |
| WebInspector.Searchable.prototype = { |
| searchCanceled: function() { }, |
| |
| /** |
| * @param {!WebInspector.SearchableView.SearchConfig} searchConfig |
| * @param {boolean} shouldJump |
| * @param {boolean=} jumpBackwards |
| */ |
| performSearch: function(searchConfig, shouldJump, jumpBackwards) { }, |
| |
| jumpToNextSearchResult: function() { }, |
| |
| jumpToPreviousSearchResult: function() { }, |
| |
| /** |
| * @return {boolean} |
| */ |
| supportsCaseSensitiveSearch: function() { }, |
| |
| /** |
| * @return {boolean} |
| */ |
| supportsRegexSearch: function() { } |
| } |
| |
| /** |
| * @interface |
| */ |
| WebInspector.Replaceable = function() |
| { |
| } |
| |
| WebInspector.Replaceable.prototype = { |
| /** |
| * @param {!WebInspector.SearchableView.SearchConfig} searchConfig |
| * @param {string} replacement |
| */ |
| replaceSelectionWith: function(searchConfig, replacement) { }, |
| |
| /** |
| * @param {!WebInspector.SearchableView.SearchConfig} searchConfig |
| * @param {string} replacement |
| */ |
| replaceAllWith: function(searchConfig, replacement) { } |
| } |
| |
| /** |
| * @constructor |
| * @param {string} query |
| * @param {boolean} caseSensitive |
| * @param {boolean} isRegex |
| */ |
| WebInspector.SearchableView.SearchConfig = function(query, caseSensitive, isRegex) |
| { |
| this.query = query; |
| this.caseSensitive = caseSensitive; |
| this.isRegex = isRegex; |
| } |
| |
| WebInspector.SearchableView.SearchConfig.prototype = { |
| /** |
| * @param {boolean=} global |
| * @return {!RegExp} |
| */ |
| toSearchRegex: function(global) |
| { |
| var modifiers = this.caseSensitive ? "" : "i"; |
| if (global) |
| modifiers += "g"; |
| var query = this.isRegex ? "/" + this.query + "/" : this.query; |
| |
| var regex; |
| |
| // First try creating regex if user knows the / / hint. |
| try { |
| if (/^\/.+\/$/.test(query)) { |
| regex = new RegExp(query.substring(1, query.length - 1), modifiers); |
| regex.__fromRegExpQuery = true; |
| } |
| } catch (e) { |
| // Silent catch. |
| } |
| |
| // Otherwise just do a plain text search. |
| if (!regex) |
| regex = createPlainTextSearchRegex(query, modifiers); |
| |
| return regex; |
| } |
| } |