summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js765
1 files changed, 765 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js b/chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js
new file mode 100644
index 00000000000..e4f1585aa08
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/components/FilterBar.js
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.Object}
+ */
+WebInspector.FilterBar = function()
+{
+ this._filtersShown = false;
+ this._element = document.createElement("div");
+ this._element.className = "hbox";
+
+ this._filterButton = new WebInspector.StatusBarButton(WebInspector.UIString("Filter"), "filters-toggle", 3);
+ this._filterButton.element.addEventListener("click", this._handleFilterButtonClick.bind(this), false);
+
+ this._filters = [];
+}
+
+WebInspector.FilterBar.Events = {
+ FiltersToggled: "FiltersToggled"
+}
+
+WebInspector.FilterBar.FilterBarState = {
+ Inactive : "inactive",
+ Active : "active",
+ Shown : "shown"
+};
+
+WebInspector.FilterBar.prototype = {
+ /**
+ * @param {string} name
+ */
+ setName: function(name)
+ {
+ this._stateSetting = WebInspector.settings.createSetting("filterBar-" + name + "-toggled", false);
+ this._setState(this._stateSetting.get());
+ },
+
+ /**
+ * @return {!WebInspector.StatusBarButton}
+ */
+ filterButton: function()
+ {
+ return this._filterButton;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ filtersElement: function()
+ {
+ return this._element;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ filtersToggled: function()
+ {
+ return this._filtersShown;
+ },
+
+ /**
+ * @param {!WebInspector.FilterUI} filter
+ */
+ addFilter: function(filter)
+ {
+ this._filters.push(filter);
+ this._element.appendChild(filter.element());
+ filter.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged, this);
+ this._updateFilterButton();
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _filterChanged: function(event)
+ {
+ this._updateFilterButton();
+ },
+
+ /**
+ * @return {string}
+ */
+ _filterBarState: function()
+ {
+ if (this._filtersShown)
+ return WebInspector.FilterBar.FilterBarState.Shown;
+ var isActive = false;
+ for (var i = 0; i < this._filters.length; ++i) {
+ if (this._filters[i].isActive())
+ return WebInspector.FilterBar.FilterBarState.Active;
+ }
+ return WebInspector.FilterBar.FilterBarState.Inactive;
+ },
+
+ _updateFilterButton: function()
+ {
+ this._filterButton.state = this._filterBarState();
+ },
+
+ /**
+ * @param {?Event} event
+ */
+ _handleFilterButtonClick: function(event)
+ {
+ this._setState(!this._filtersShown);
+ },
+
+ /**
+ * @param {boolean} filtersShown
+ */
+ _setState: function(filtersShown)
+ {
+ if (this._filtersShown === filtersShown)
+ return;
+
+ this._filtersShown = filtersShown;
+ if (this._stateSetting)
+ this._stateSetting.set(filtersShown);
+
+ this._updateFilterButton();
+ this.dispatchEventToListeners(WebInspector.FilterBar.Events.FiltersToggled, this._filtersShown);
+ if (this._filtersShown) {
+ for (var i = 0; i < this._filters.length; ++i) {
+ if (this._filters[i] instanceof WebInspector.TextFilterUI) {
+ var textFilterUI = /** @type {!WebInspector.TextFilterUI} */ (this._filters[i]);
+ textFilterUI.focus();
+ }
+ }
+ }
+ },
+
+ clear: function()
+ {
+ this._element.removeChildren();
+ this._filters = [];
+ this._updateFilterButton();
+ },
+
+ __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @interface
+ * @extends {WebInspector.EventTarget}
+ */
+WebInspector.FilterUI = function()
+{
+}
+
+WebInspector.FilterUI.Events = {
+ FilterChanged: "FilterChanged"
+}
+
+WebInspector.FilterUI.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isActive: function() { },
+
+ /**
+ * @return {!Element}
+ */
+ element: function() { }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @implements {WebInspector.FilterUI}
+ * @implements {WebInspector.SuggestBoxDelegate}
+ * @param {boolean=} supportRegex
+ */
+WebInspector.TextFilterUI = function(supportRegex)
+{
+ this._supportRegex = !!supportRegex;
+ this._regex = null;
+
+ this._filterElement = document.createElement("div");
+ this._filterElement.className = "filter-text-filter";
+
+ this._filterInputElement = /** @type {!HTMLInputElement} */ (this._filterElement.createChild("input", "search-replace toolbar-replace-control"));
+ this._filterInputElement.placeholder = WebInspector.UIString("Filter");
+ this._filterInputElement.id = "filter-input-field";
+ this._filterInputElement.addEventListener("mousedown", this._onFilterFieldManualFocus.bind(this), false); // when the search field is manually selected
+ this._filterInputElement.addEventListener("input", this._onInput.bind(this), false);
+ this._filterInputElement.addEventListener("change", this._onChange.bind(this), false);
+ this._filterInputElement.addEventListener("keydown", this._onInputKeyDown.bind(this), true);
+ this._filterInputElement.addEventListener("blur", this._onBlur.bind(this), true);
+
+ /** @type {?WebInspector.TextFilterUI.SuggestionBuilder} */
+ this._suggestionBuilder = null;
+
+ this._suggestBox = new WebInspector.SuggestBox(this);
+
+ if (this._supportRegex) {
+ this._filterElement.classList.add("supports-regex");
+ this._regexCheckBox = this._filterElement.createChild("input");
+ this._regexCheckBox.type = "checkbox";
+ this._regexCheckBox.id = "text-filter-regex";
+ this._regexCheckBox.addEventListener("change", this._onInput.bind(this), false);
+
+ this._regexLabel = this._filterElement.createChild("label");
+ this._regexLabel.htmlFor = "text-filter-regex";
+ this._regexLabel.textContent = WebInspector.UIString("Regex");
+ }
+}
+
+WebInspector.TextFilterUI.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isActive: function()
+ {
+ return !!this._filterInputElement.value;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ element: function()
+ {
+ return this._filterElement;
+ },
+
+ /**
+ * @return {string}
+ */
+ value: function()
+ {
+ return this._filterInputElement.value;
+ },
+
+ /**
+ * @param {string} value
+ */
+ setValue: function(value)
+ {
+ this._filterInputElement.value = value;
+ this._valueChanged(false);
+ },
+
+ /**
+ * @return {?RegExp}
+ */
+ regex: function()
+ {
+ return this._regex;
+ },
+
+ /**
+ * @param {?Event} event
+ */
+ _onFilterFieldManualFocus: function(event)
+ {
+ WebInspector.setCurrentFocusElement(event.target);
+ },
+
+ /**
+ * @param {?Event} event
+ */
+ _onBlur: function(event)
+ {
+ this._cancelSuggestion();
+ },
+
+ _cancelSuggestion: function()
+ {
+ if (this._suggestionBuilder && this._suggestBox.visible) {
+ this._suggestionBuilder.unapplySuggestion(this._filterInputElement);
+ this._suggestBox.hide();
+ }
+ },
+
+ _onInput: function()
+ {
+ this._valueChanged(true);
+ },
+
+ _onChange: function()
+ {
+ this._valueChanged(false);
+ },
+
+ focus: function()
+ {
+ this._filterInputElement.focus();
+ },
+
+ /**
+ * @param {?WebInspector.TextFilterUI.SuggestionBuilder} suggestionBuilder
+ */
+ setSuggestionBuilder: function(suggestionBuilder)
+ {
+ this._cancelSuggestion();
+ this._suggestionBuilder = suggestionBuilder;
+ },
+
+ _updateSuggestions: function()
+ {
+ if (!this._suggestionBuilder)
+ return;
+ var suggestions = this._suggestionBuilder.buildSuggestions(this._filterInputElement);
+ if (suggestions && suggestions.length) {
+ if (this._suppressSuggestion)
+ delete this._suppressSuggestion;
+ else
+ this._suggestionBuilder.applySuggestion(this._filterInputElement, suggestions[0], true);
+ var anchorBox = this._filterInputElement.boxInWindow().relativeTo(new AnchorBox(-3, 0));
+ this._suggestBox.updateSuggestions(anchorBox, suggestions, 0, true, "");
+ } else {
+ this._suggestBox.hide();
+ }
+ },
+
+ /**
+ * @param {boolean} showSuggestions
+ */
+ _valueChanged: function(showSuggestions)
+ {
+ if (showSuggestions)
+ this._updateSuggestions();
+ else
+ this._suggestBox.hide();
+
+ var filterQuery = this.value();
+
+ this._regex = null;
+ this._filterInputElement.classList.remove("filter-text-invalid");
+ if (filterQuery) {
+ if (this._supportRegex && this._regexCheckBox.checked) {
+ try {
+ this._regex = new RegExp(filterQuery, "i");
+ } catch (e) {
+ this._filterInputElement.classList.add("filter-text-invalid");
+ }
+ } else {
+ this._regex = createPlainTextSearchRegex(filterQuery, "i");
+ }
+ }
+
+ this._dispatchFilterChanged();
+ },
+
+ _dispatchFilterChanged: function()
+ {
+ this.dispatchEventToListeners(WebInspector.FilterUI.Events.FilterChanged, null);
+ },
+
+ /**
+ * @param {?Event} event
+ * @return {boolean}
+ */
+ _onInputKeyDown: function(event)
+ {
+ var handled = false;
+ if (event.keyIdentifier === "U+0008") { // Backspace
+ this._suppressSuggestion = true;
+ } else if (this._suggestBox.visible()) {
+ if (event.keyIdentifier === "U+001B") { // Esc
+ this._cancelSuggestion();
+ handled = true;
+ } else if (event.keyIdentifier === "U+0009") { // Tab
+ this._suggestBox.acceptSuggestion();
+ this._valueChanged(true);
+ handled = true;
+ } else {
+ handled = this._suggestBox.keyPressed(/** @type {!KeyboardEvent} */ (event));
+ }
+ }
+ if (handled)
+ event.consume(true);
+ return handled;
+ },
+
+ /**
+ * @override
+ * @param {string} suggestion
+ * @param {boolean=} isIntermediateSuggestion
+ */
+ applySuggestion: function(suggestion, isIntermediateSuggestion)
+ {
+ if (!this._suggestionBuilder)
+ return;
+ this._suggestionBuilder.applySuggestion(this._filterInputElement, suggestion, !!isIntermediateSuggestion);
+ if (isIntermediateSuggestion)
+ this._dispatchFilterChanged();
+ },
+
+ /** @override */
+ acceptSuggestion: function()
+ {
+ this._filterInputElement.scrollLeft = this._filterInputElement.scrollWidth;
+ this._valueChanged(true);
+ },
+
+ __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @interface
+ */
+WebInspector.TextFilterUI.SuggestionBuilder = function()
+{
+}
+
+WebInspector.TextFilterUI.SuggestionBuilder.prototype = {
+ /**
+ * @param {!HTMLInputElement} input
+ * @return {?Array.<string>}
+ */
+ buildSuggestions: function(input) { },
+
+ /**
+ * @param {!HTMLInputElement} input
+ * @param {string} suggestion
+ * @param {boolean} isIntermediate
+ */
+ applySuggestion: function(input, suggestion, isIntermediate) { },
+
+ /**
+ * @param {!HTMLInputElement} input
+ */
+ unapplySuggestion: function(input) { }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @implements {WebInspector.FilterUI}
+ * @param {!Array.<!WebInspector.NamedBitSetFilterUI.Item>} items
+ * @param {!WebInspector.Setting=} setting
+ */
+WebInspector.NamedBitSetFilterUI = function(items, setting)
+{
+ this._filtersElement = document.createElement("div");
+ this._filtersElement.className = "filter-bitset-filter status-bar-item";
+ this._filtersElement.title = WebInspector.UIString("Use %s Click to select multiple types.", WebInspector.KeyboardShortcut.shortcutToString("", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta));
+
+ this._allowedTypes = {};
+ this._typeFilterElements = {};
+ this._addBit(WebInspector.NamedBitSetFilterUI.ALL_TYPES, WebInspector.UIString("All"));
+ this._filtersElement.createChild("div", "filter-bitset-filter-divider");
+
+ for (var i = 0; i < items.length; ++i)
+ this._addBit(items[i].name, items[i].label);
+
+ if (setting) {
+ this._setting = setting;
+ setting.addChangeListener(this._settingChanged.bind(this));
+ this._settingChanged();
+ } else {
+ this._toggleTypeFilter(WebInspector.NamedBitSetFilterUI.ALL_TYPES, false);
+ }
+}
+
+/** @typedef {{name: string, label: string}} */
+WebInspector.NamedBitSetFilterUI.Item;
+
+WebInspector.NamedBitSetFilterUI.ALL_TYPES = "all";
+
+WebInspector.NamedBitSetFilterUI.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isActive: function()
+ {
+ return !this._allowedTypes[WebInspector.NamedBitSetFilterUI.ALL_TYPES];
+ },
+
+ /**
+ * @return {!Element}
+ */
+ element: function()
+ {
+ return this._filtersElement;
+ },
+
+ /**
+ * @param {string} typeName
+ * @return {boolean}
+ */
+ accept: function(typeName)
+ {
+ return !!this._allowedTypes[WebInspector.NamedBitSetFilterUI.ALL_TYPES] || !!this._allowedTypes[typeName];
+ },
+
+ _settingChanged: function()
+ {
+ var allowedTypes = this._setting.get();
+ this._allowedTypes = {};
+ for (var typeName in this._typeFilterElements) {
+ if (allowedTypes[typeName])
+ this._allowedTypes[typeName] = true;
+ }
+ this._update();
+ },
+
+ _update: function()
+ {
+ if ((Object.keys(this._allowedTypes).length === 0) || this._allowedTypes[WebInspector.NamedBitSetFilterUI.ALL_TYPES]) {
+ this._allowedTypes = {};
+ this._allowedTypes[WebInspector.NamedBitSetFilterUI.ALL_TYPES] = true;
+ }
+ for (var typeName in this._typeFilterElements)
+ this._typeFilterElements[typeName].classList.toggle("selected", this._allowedTypes[typeName]);
+ this.dispatchEventToListeners(WebInspector.FilterUI.Events.FilterChanged, null);
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} label
+ */
+ _addBit: function(name, label)
+ {
+ var typeFilterElement = this._filtersElement.createChild("li", name);
+ typeFilterElement.typeName = name;
+ typeFilterElement.createTextChild(label);
+ typeFilterElement.addEventListener("click", this._onTypeFilterClicked.bind(this), false);
+ this._typeFilterElements[name] = typeFilterElement;
+ },
+
+ /**
+ * @param {?Event} e
+ */
+ _onTypeFilterClicked: function(e)
+ {
+ var toggle;
+ if (WebInspector.isMac())
+ toggle = e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey;
+ else
+ toggle = e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey;
+ this._toggleTypeFilter(e.target.typeName, toggle);
+ },
+
+ /**
+ * @param {string} typeName
+ * @param {boolean} allowMultiSelect
+ */
+ _toggleTypeFilter: function(typeName, allowMultiSelect)
+ {
+ if (allowMultiSelect && typeName !== WebInspector.NamedBitSetFilterUI.ALL_TYPES)
+ this._allowedTypes[WebInspector.NamedBitSetFilterUI.ALL_TYPES] = false;
+ else
+ this._allowedTypes = {};
+
+ this._allowedTypes[typeName] = !this._allowedTypes[typeName];
+
+ if (this._setting)
+ this._setting.set(this._allowedTypes);
+ else
+ this._update();
+ },
+
+ __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.FilterUI}
+ * @extends {WebInspector.Object}
+ * @param {!Array.<!{value: *, label: string, title: string}>} options
+ */
+WebInspector.ComboBoxFilterUI = function(options)
+{
+ this._filterElement = document.createElement("div");
+ this._filterElement.className = "filter-combobox-filter";
+
+ this._options = options;
+ this._filterComboBox = new WebInspector.StatusBarComboBox(this._filterChanged.bind(this));
+ for (var i = 0; i < options.length; ++i) {
+ var filterOption = options[i];
+ var option = document.createElement("option");
+ option.text = filterOption.label;
+ option.title = filterOption.title;
+ this._filterComboBox.addOption(option);
+ this._filterComboBox.element.title = this._filterComboBox.selectedOption().title;
+ }
+ this._filterElement.appendChild(this._filterComboBox.element);
+}
+
+WebInspector.ComboBoxFilterUI.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isActive: function()
+ {
+ return this._filterComboBox.selectedIndex() !== 0;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ element: function()
+ {
+ return this._filterElement;
+ },
+
+ /**
+ * @param {string} typeName
+ * @return {*}
+ */
+ value: function(typeName)
+ {
+ var option = this._options[this._filterComboBox.selectedIndex()];
+ return option.value;
+ },
+
+ /**
+ * @param {number} index
+ */
+ setSelectedIndex: function(index)
+ {
+ this._filterComboBox.setSelectedIndex(index);
+ },
+
+ /**
+ * @return {number}
+ */
+ selectedIndex: function(index)
+ {
+ return this._filterComboBox.selectedIndex();
+ },
+
+ /**
+ * @param {?Event} event
+ */
+ _filterChanged: function(event)
+ {
+ var option = this._options[this._filterComboBox.selectedIndex()];
+ this._filterComboBox.element.title = option.title;
+ this.dispatchEventToListeners(WebInspector.FilterUI.Events.FilterChanged, null);
+ },
+
+ __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.FilterUI}
+ * @extends {WebInspector.Object}
+ * @param {string} className
+ * @param {string} title
+ * @param {boolean=} activeWhenChecked
+ * @param {!WebInspector.Setting=} setting
+ */
+WebInspector.CheckboxFilterUI = function(className, title, activeWhenChecked, setting)
+{
+ this._filterElement = document.createElement("div");
+ this._filterElement.classList.add("filter-checkbox-filter", "filter-checkbox-filter-" + className);
+ this._activeWhenChecked = !!activeWhenChecked;
+ this._createCheckbox(title);
+
+ if (setting) {
+ this._setting = setting;
+ setting.addChangeListener(this._settingChanged.bind(this));
+ this._settingChanged();
+ } else {
+ this._checked = !this._activeWhenChecked;
+ this._update();
+ }
+}
+
+WebInspector.CheckboxFilterUI.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isActive: function()
+ {
+ return this._activeWhenChecked === this._checked;
+ },
+
+ /**
+ * @return {!Element}
+ */
+ element: function()
+ {
+ return this._filterElement;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ checked: function()
+ {
+ return this._checked;
+ },
+
+ /**
+ * @param {boolean} state
+ */
+ setState: function(state)
+ {
+ this._checked = state;
+ this._update();
+ },
+
+ _update: function()
+ {
+ this._checkElement.classList.toggle("checkbox-filter-checkbox-checked", this._checked);
+ this.dispatchEventToListeners(WebInspector.FilterUI.Events.FilterChanged, null);
+ },
+
+ _settingChanged: function()
+ {
+ this._checked = this._setting.get();
+ this._update();
+ },
+
+ /**
+ * @param {?Event} event
+ */
+ _onClick: function(event)
+ {
+ this._checked = !this._checked;
+ if (this._setting)
+ this._setting.set(this._checked);
+ else
+ this._update();
+ },
+
+ /**
+ * @param {string} title
+ */
+ _createCheckbox: function(title)
+ {
+ var label = this._filterElement.createChild("label");
+ var checkBorder = label.createChild("div", "checkbox-filter-checkbox");
+ this._checkElement = checkBorder.createChild("div", "checkbox-filter-checkbox-check");
+ this._filterElement.addEventListener("click", this._onClick.bind(this), false);
+ var typeElement = label.createChild("span", "type");
+ typeElement.textContent = title;
+ },
+
+ __proto__: WebInspector.Object.prototype
+}