Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
| index 47c9b79fb1bab592d240aaedacbf23d13fe4f67e..a2f9930feafce320a37d6712e6058b008451764a 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
| @@ -43,9 +43,18 @@ function TreeOutline(nonFocusable) |
| this._contentElement = this._rootElement._childrenListNode; |
| this._contentElement.addEventListener("keydown", this._treeKeyDown.bind(this), true); |
| + this.element = this._contentElement; |
| + |
| this.setFocusable(!nonFocusable); |
| - this.element = this._contentElement; |
| + this.element.addEventListener("keypress", this._handleKeyPressForHighlighting.bind(this), true); |
| + this.element.addEventListener("blur", this._clearFilter.bind(this), true); |
| + this.element.addEventListener("click", this._clearFilter.bind(this), true); |
| + |
| + this._currentSelectionFilterString = ""; |
| + this._interactiveFilterEnabled = false; |
| + /** @type {!Array.<!TreeElement>} */ |
| + this._highlightedNodes = [] |
| } |
| TreeOutline.Events = { |
| @@ -75,6 +84,98 @@ TreeOutline.prototype = { |
| }, |
| /** |
| + * @param {boolean} enable |
| + */ |
| + setInteractiveFilterable: function(enable) |
| + { |
| + if (enable === this._interactiveFilterEnabled) |
| + return; |
| + if (!enable) |
|
lushnikov
2016/04/13 17:57:41
nit: do we need this if statement?
allada
2016/04/13 19:33:06
Yes, if setInteractiveFilter is called to turn it
|
| + this._setCurrentSelectionFilterString(""); |
| + this._interactiveFilterEnabled = enable; |
| + }, |
| + |
| + /** |
| + * @param {string} filterString |
| + */ |
| + _setCurrentSelectionFilterString: function(filterString) |
| + { |
| + this._currentSelectionFilterString = filterString; |
| + this._refreshHighlighting(); |
| + }, |
| + |
| + /** |
| + * @param {string} filterString |
| + * @return {!RegExp} |
| + */ |
| + _makeFilterRegExFromString: function(filterString) |
|
lushnikov
2016/04/13 17:57:41
nit: _makeFilterRegexFromString
allada
2016/04/13 19:33:06
Done.
|
| + { |
| + return new RegExp(filterString.escapeForRegExp(), "gi") |
| + }, |
| + |
| + _refreshHighlighting: function() |
| + { |
| + if (!this._rootElement) |
| + return; |
| + |
| + for (var changedNode of this._highlightedNodes) |
| + changedNode._revertHighlightChanges(); |
| + |
| + this._highlightedNodes = []; |
| + |
| + if (!this._currentSelectionFilterString) |
| + return; |
| + |
| + if (this.selectedTreeElement && !this.selectedTreeElement.selectable) { |
| + if (!this.selectNext()) |
| + this.selectPrevious(); |
| + } |
| + |
| + var filterRegEx = this._makeFilterRegExFromString(this._currentSelectionFilterString); |
|
lushnikov
2016/04/13 17:57:41
nit: filterRegex
allada
2016/04/13 19:33:06
Done.
|
| + var node = this._rootElement.firstChild(); |
| + while (node) { |
| + if (node._applyHighlightFilter(filterRegEx)) |
| + this._highlightedNodes.push(node); |
| + node = node.traverseNextTreeElement(true, null, true); |
| + } |
| + }, |
| + |
| + /** |
| + * @param {!TreeElement} treeElement |
| + * @return {boolean} |
| + */ |
| + _checkFilter: function(treeElement) |
|
lushnikov
2016/04/13 17:57:41
let's move this inside TreeElement.
allada
2016/04/13 19:33:06
Done.
|
| + { |
| + return this._currentSelectionFilterString ? this._makeFilterRegExFromString(this._currentSelectionFilterString).test(treeElement._titleElement.textContent) : true; |
| + }, |
| + |
| + _clearFilter: function() |
| + { |
| + if (this._interactiveFilterEnabled) |
| + this._setCurrentSelectionFilterString(""); |
| + }, |
| + |
| + /** |
| + * @param {!Event} event |
| + */ |
| + _handleKeyPressForHighlighting: function(event) |
| + { |
| + if (!this._interactiveFilterEnabled) |
| + return; |
| + |
| + if (event.target !== this._contentElement) |
| + return; |
| + |
| + if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) |
| + return; |
| + |
| + var currentFilterString = this._currentSelectionFilterString; |
| + var key = event.data; |
| + if (key !== "\r" && key !== "\n" && (key !== " " || currentFilterString)) |
| + this._setCurrentSelectionFilterString(currentFilterString + event.data); |
| + }, |
| + |
| + /** |
| * @return {?TreeElement} |
| */ |
| firstChild: function() |
| @@ -152,9 +253,9 @@ TreeOutline.prototype = { |
| setFocusable: function(focusable) |
| { |
| if (focusable) |
| - this._contentElement.setAttribute("tabIndex", 0); |
| + this.element.setAttribute("tabIndex", 0); |
| else |
| - this._contentElement.removeAttribute("tabIndex"); |
| + this.element.removeAttribute("tabIndex"); |
| }, |
| focus: function() |
| @@ -229,18 +330,30 @@ TreeOutline.prototype = { |
| if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) |
| return; |
| + var currentFilterString = this._currentSelectionFilterString; |
| var handled = false; |
| + var key = event.keyCode; |
| var nextSelectedElement; |
| - if (event.keyIdentifier === "Up" && !event.altKey) { |
| - handled = this.selectPrevious(); |
| - } else if (event.keyIdentifier === "Down" && !event.altKey) { |
| - handled = this.selectNext(); |
| - } else if (event.keyIdentifier === "Left") { |
| + |
| + switch (key) { |
| + case WebInspector.KeyboardShortcut.Keys.Up.code: |
| + if (!event.altKey) |
| + handled = this.selectPrevious(); |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Down.code: |
| + if (!event.altKey) |
| + handled = this.selectNext(); |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Left.code: |
| + if (this._interactiveFilterEnabled) |
| + this._clearFilter(); |
| + |
| if (this.selectedTreeElement.expanded) { |
| if (event.altKey) |
| this.selectedTreeElement.collapseRecursively(); |
| else |
| this.selectedTreeElement.collapse(); |
| + |
|
lushnikov
2016/04/13 17:57:41
nit: stray line
allada
2016/04/13 19:33:06
Done.
|
| handled = true; |
| } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { |
| handled = true; |
| @@ -248,11 +361,17 @@ TreeOutline.prototype = { |
| nextSelectedElement = this.selectedTreeElement.parent; |
| while (nextSelectedElement && !nextSelectedElement.selectable) |
| nextSelectedElement = nextSelectedElement.parent; |
| + |
|
lushnikov
2016/04/13 17:57:41
nit: stray line
allada
2016/04/13 19:33:06
Done.
|
| handled = nextSelectedElement ? true : false; |
| - } else if (this.selectedTreeElement.parent) |
| + } else if (this.selectedTreeElement.parent) { |
| this.selectedTreeElement.parent.collapse(); |
| + } |
| } |
| - } else if (event.keyIdentifier === "Right") { |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Right.code: |
| + if (this._interactiveFilterEnabled) |
| + this._clearFilter(); |
| + |
| if (!this.selectedTreeElement.revealed()) { |
| this.selectedTreeElement.reveal(); |
| handled = true; |
| @@ -262,6 +381,7 @@ TreeOutline.prototype = { |
| nextSelectedElement = this.selectedTreeElement.firstChild(); |
| while (nextSelectedElement && !nextSelectedElement.selectable) |
| nextSelectedElement = nextSelectedElement.nextSibling; |
| + |
|
lushnikov
2016/04/13 17:57:41
nit: stray line
allada
2016/04/13 19:33:06
Done.
|
| handled = nextSelectedElement ? true : false; |
| } else { |
| if (event.altKey) |
| @@ -270,12 +390,41 @@ TreeOutline.prototype = { |
| this.selectedTreeElement.expand(); |
| } |
| } |
| - } else if (event.keyCode === 8 /* Backspace */ || event.keyCode === 46 /* Delete */) |
| - handled = this.selectedTreeElement.ondelete(); |
| - else if (isEnterKey(event)) |
| - handled = this.selectedTreeElement.onenter(); |
| - else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) |
| - handled = this.selectedTreeElement.onspace(); |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Backspace.code: |
| + if (this._interactiveFilterEnabled && currentFilterString) { |
| + handled = true; |
| + this._setCurrentSelectionFilterString(currentFilterString.substr(0, currentFilterString.length - 1)); |
| + } else { |
| + handled = this.selectedTreeElement.ondelete(); |
| + } |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Delete.code: |
| + if (this._interactiveFilterEnabled && currentFilterString) { |
| + handled = true; |
| + this._clearFilter(); |
| + } else |
| + handled = this.selectedTreeElement.ondelete(); |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Esc.code: |
| + if (this._interactiveFilterEnabled) { |
| + if (currentFilterString) |
| + handled = true; |
| + this._clearFilter(); |
| + } |
| + break; |
| + case WebInspector.KeyboardShortcut.Keys.Space.code: |
| + if (!currentFilterString) |
| + handled = this.selectedTreeElement.onspace(); |
| + break; |
| + default: |
| + if (isEnterKey(event)) { |
| + if (this._interactiveFilterEnabled) |
| + this._clearFilter(); |
| + |
| + handled = this.selectedTreeElement.onenter(); |
| + } |
| + } |
| if (nextSelectedElement) { |
| nextSelectedElement.reveal(); |
| @@ -377,6 +526,9 @@ function TreeElement(title, expandable) |
| this.selected = false; |
| this.setExpandable(expandable || false); |
| this._collapsible = true; |
| + |
| + /** @type {!Array.<!Object>} */ |
| + this._highlightChanges = []; |
| } |
| /** @const */ |
| @@ -384,6 +536,33 @@ TreeElement._ArrowToggleWidth = 10; |
| TreeElement.prototype = { |
| /** |
| + * @param {!RegExp} regex |
| + * @return {boolean} |
| + */ |
| + _applyHighlightFilter: function(regex) { |
| + var textContent = this._listItemNode.textContent; |
| + var ranges = []; |
| + |
| + this._revertHighlightChanges(); |
| + |
| + var match = regex.exec(textContent); |
| + while (match) { |
| + ranges.push(new WebInspector.SourceRange(match.index, match[0].length)); |
| + match = regex.exec(textContent); |
| + } |
| + if (ranges.length) |
| + WebInspector.highlightRangesWithStyleClass(this._listItemNode, ranges, "tree-text-interactive-highlight", this._highlightChanges); |
| + |
| + return !!this._highlightChanges.length |
| + }, |
| + |
| + _revertHighlightChanges: function() |
| + { |
| + WebInspector.revertDomChanges(this._highlightChanges); |
| + this._highlightChanges = []; |
| + }, |
| + |
| + /** |
| * @param {?TreeElement} ancestor |
| * @return {boolean} |
| */ |
| @@ -603,7 +782,7 @@ TreeElement.prototype = { |
| get selectable() |
| { |
| - if (this._hidden) |
| + if (this._hidden || !this.treeOutline._checkFilter(this)) |
| return false; |
| return this._selectable; |
| }, |