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..aefa34b4c466619c8281fd176f51453b97828b28 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._contentElement.addEventListener("keypress", this._handleKeyPressForHighlighting.bind(this), true); |
lushnikov
2016/04/06 00:22:36
this.element.addEventListener...
allada
2016/04/09 00:42:47
Done.
|
+ this.element.addEventListener("blur", this._clearFilter.bind(this), true); |
lushnikov
2016/04/06 00:22:36
is capturing actually needed in these three events
|
+ this.element.addEventListener("click", this._clearFilter.bind(this), true); |
+ |
+ this._currentSelectionFilterString = ""; |
+ this._interactiveFilterEnabled = false; |
+ /** @type {!Array.<!TreeElement>} */ |
+ this._highlightedNodes = [] |
} |
TreeOutline.Events = { |
@@ -75,6 +84,106 @@ TreeOutline.prototype = { |
}, |
/** |
+ * @param {boolean} enable |
+ */ |
+ setInteractiveFilterable: function (enable) |
+ { |
+ if (!enable) |
+ this._setCurrentSelectionFilterString(""); |
+ |
+ this._interactiveFilterEnabled = enable; |
+ }, |
+ |
+ /** |
+ * @param {string} filterString |
+ */ |
+ _setCurrentSelectionFilterString: function (filterString) |
+ { |
+ this._currentSelectionFilterString = filterString; |
+ this._refreshHighlighting(); |
+ }, |
+ |
+ /** |
+ * @param {string} filterString |
+ * @return {!RegExp} |
+ */ |
+ _makeFilterRegExpFromString: function (filterString) |
+ { |
+ return new RegExp(filterString.escapeForRegExp(), "gi") |
+ }, |
+ |
+ _refreshHighlighting: function () |
lushnikov
2016/04/06 00:22:37
nit: _refreshHighlight:
allada
2016/04/09 00:42:48
Done.
|
+ { |
+ if (!this._rootElement) |
+ return; |
+ |
+ var filterRegExp = this._makeFilterRegExpFromString(this._currentSelectionFilterString); |
lushnikov
2016/04/06 00:22:36
nit: filterRegex =
allada
2016/04/09 00:42:48
Done.
|
+ |
+ 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 node = this._rootElement.firstChild(); |
+ do { |
lushnikov
2016/04/06 00:22:36
nit: no need for do-while; simple while will work
allada
2016/04/09 00:42:48
Done.
|
+ if (node._applyHighlightFilter(filterRegExp)) |
+ this._highlightedNodes.push(node); |
+ node = node.traverseNextTreeElement(true, null, true); |
+ } while(node); |
+ }, |
+ |
+ /** |
+ * @param {!TreeElement} treeElement |
+ * @return {boolean} |
+ */ |
+ _checkFilter: function (treeElement) |
lushnikov
2016/04/06 00:22:36
Let's move this method into TreeElement; treeEleme
allada
2016/04/09 00:42:48
Done.
|
+ { |
+ return this._currentSelectionFilterString ? this._makeFilterRegExpFromString(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; |
+ |
+ switch (event.data) { |
+ case "\r": |
+ case "\n": |
+ break; |
+ case " ": |
+ if (!currentFilterString) |
+ break; |
+ default: |
+ this._setCurrentSelectionFilterString(currentFilterString + event.data); |
+ } |
+ }, |
+ |
+ /** |
* @return {?TreeElement} |
*/ |
firstChild: function() |
@@ -152,9 +261,9 @@ TreeOutline.prototype = { |
setFocusable: function(focusable) |
{ |
if (focusable) |
- this._contentElement.setAttribute("tabIndex", 0); |
+ this.element.setAttribute("tabIndex", 0); |
lushnikov
2016/04/06 00:22:36
this and below seems to be unnecessary
allada
2016/04/09 00:42:48
This is needed to be able to capture keyboard even
|
else |
- this._contentElement.removeAttribute("tabIndex"); |
+ this.element.removeAttribute("tabIndex"); |
}, |
focus: function() |
@@ -229,30 +338,38 @@ 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") { |
- if (this.selectedTreeElement.expanded) { |
- if (event.altKey) |
- this.selectedTreeElement.collapseRecursively(); |
- else |
- this.selectedTreeElement.collapse(); |
+ |
+ switch (key) { |
+ case WebInspector.KeyboardShortcut.Keys.Esc.code: |
+ if (this._interactiveFilterEnabled) { |
+ if (currentFilterString) |
+ handled = true; |
+ this._clearFilter(); |
+ } |
+ break; |
+ case WebInspector.KeyboardShortcut.Keys.Delete.code: |
+ if (this._interactiveFilterEnabled && currentFilterString) { |
handled = true; |
- } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { |
+ this._clearFilter(); |
+ } else |
+ handled = this.selectedTreeElement.ondelete(); |
+ break; |
+ case WebInspector.KeyboardShortcut.Keys.Backspace.code: |
+ if (this._interactiveFilterEnabled && currentFilterString) { |
handled = true; |
- if (this.selectedTreeElement.parent.selectable) { |
- nextSelectedElement = this.selectedTreeElement.parent; |
- while (nextSelectedElement && !nextSelectedElement.selectable) |
- nextSelectedElement = nextSelectedElement.parent; |
- handled = nextSelectedElement ? true : false; |
- } else if (this.selectedTreeElement.parent) |
- this.selectedTreeElement.parent.collapse(); |
+ this._setCurrentSelectionFilterString(currentFilterString.substr(0, currentFilterString.length - 1)); |
+ } else { |
+ handled = this.selectedTreeElement.ondelete(); |
} |
- } 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 +379,7 @@ TreeOutline.prototype = { |
nextSelectedElement = this.selectedTreeElement.firstChild(); |
while (nextSelectedElement && !nextSelectedElement.selectable) |
nextSelectedElement = nextSelectedElement.nextSibling; |
+ |
lushnikov
2016/04/06 00:22:36
nit: stray line
allada
2016/04/09 00:42:47
Done.
|
handled = nextSelectedElement ? true : false; |
} else { |
if (event.altKey) |
@@ -270,12 +388,51 @@ 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.Left.code: |
+ if (this._interactiveFilterEnabled) |
+ this._clearFilter(); |
+ |
+ if (this.selectedTreeElement.expanded) { |
lushnikov
2016/04/06 00:22:36
Are there any changes in this if-else-if code?
ni
allada
2016/04/09 00:42:48
Done.
|
+ if (event.altKey) |
+ this.selectedTreeElement.collapseRecursively(); |
+ else |
+ this.selectedTreeElement.collapse(); |
+ |
+ handled = true; |
+ } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { |
+ handled = true; |
+ if (this.selectedTreeElement.parent.selectable) { |
+ nextSelectedElement = this.selectedTreeElement.parent; |
+ while (nextSelectedElement && !nextSelectedElement.selectable) |
+ nextSelectedElement = nextSelectedElement.parent; |
+ |
+ handled = nextSelectedElement ? true : false; |
+ } else if (this.selectedTreeElement.parent) { |
+ this.selectedTreeElement.parent.collapse(); |
+ } |
+ } |
+ break; |
+ case WebInspector.KeyboardShortcut.Keys.Down.code: |
+ if (!event.altKey) |
+ handled = this.selectNext(); |
+ break; |
+ case WebInspector.KeyboardShortcut.Keys.Up.code: |
+ if (!event.altKey) |
+ handled = this.selectPrevious(); |
+ 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 +534,9 @@ function TreeElement(title, expandable) |
this.selected = false; |
this.setExpandable(expandable || false); |
this._collapsible = true; |
+ |
+ /** @type {!Array.<!Object>} */ |
+ this._highlightChanges = []; |
} |
/** @const */ |
@@ -384,6 +544,36 @@ 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); |
+ |
+ if (this._highlightChanges.length) |
lushnikov
2016/04/06 00:22:36
return !!this._highlightChanges.length;
allada
2016/04/09 00:42:47
Done.
|
+ return true; |
+ |
+ return false; |
+ }, |
+ |
+ _revertHighlightChanges: function () |
+ { |
+ WebInspector.revertDomChanges(this._highlightChanges); |
+ this._highlightChanges = []; |
+ }, |
+ |
+ /** |
* @param {?TreeElement} ancestor |
* @return {boolean} |
*/ |
@@ -603,7 +793,7 @@ TreeElement.prototype = { |
get selectable() |
{ |
- if (this._hidden) |
+ if (this._hidden || !this.treeOutline._checkFilter(this)) |
return false; |
return this._selectable; |
}, |