+2012-01-17 Vsevolod Vlasov <vsevik@chromium.org>
+
+ Web Inspector: Refactor JavaScriptOutlineDialog: extract FilteredItemSelectionDialog and reuse DialogDelegate.
+ https://bugs.webkit.org/show_bug.cgi?id=76455
+
+ Reviewed by Yury Semikhatsky.
+
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * inspector/compile-front-end.sh:
+ * inspector/front-end/Dialog.js:
+ (WebInspector.Dialog):
+ (WebInspector.Dialog.prototype._hide):
+ * inspector/front-end/FilteredItemSelectionDialog.js: Added.
+ (WebInspector.FilteredItemSelectionDialog):
+ (WebInspector.FilteredItemSelectionDialog.prototype.position):
+ (WebInspector.FilteredItemSelectionDialog.prototype.focus):
+ (WebInspector.FilteredItemSelectionDialog.prototype.willHide):
+ (WebInspector.FilteredItemSelectionDialog.prototype.onEnter):
+ (WebInspector.FilteredItemSelectionDialog.prototype.get _itemsLoaded):
+ (WebInspector.FilteredItemSelectionDialog.prototype._createItemElement):
+ (WebInspector.FilteredItemSelectionDialog.prototype._hideItemElement):
+ (WebInspector.FilteredItemSelectionDialog.prototype._itemElementVisible):
+ (WebInspector.FilteredItemSelectionDialog.prototype._showItemElement):
+ (WebInspector.FilteredItemSelectionDialog.prototype._checkItemAt):
+ (WebInspector.FilteredItemSelectionDialog.prototype._createSearchRegExp):
+ (WebInspector.FilteredItemSelectionDialog.prototype._filterItems):
+ (WebInspector.FilteredItemSelectionDialog.prototype._onKeyDown):
+ (WebInspector.FilteredItemSelectionDialog.prototype._scheduleFilter):
+ (WebInspector.FilteredItemSelectionDialog.prototype._updateSelection):
+ (WebInspector.FilteredItemSelectionDialog.prototype._onMouseMove):
+ (WebInspector.FilteredItemSelectionDialog.prototype._onScroll):
+ (WebInspector.FilteredItemSelectionDialog.prototype._highlightItems):
+ (WebInspector.FilteredItemSelectionDialog.prototype._clearHighlight):
+ (WebInspector.FilteredItemSelectionDialog.prototype._clearElementHighlight.changes.this._elementHighlightChanges.get if):
+ (WebInspector.FilteredItemSelectionDialog.prototype._clearElementHighlight):
+ (WebInspector.FilteredItemSelectionDialog.prototype._highlightItem.get var):
+ (WebInspector.FilteredItemSelectionDialog.prototype._highlightItem):
+ (WebInspector.FilteredItemSelectionDialog.prototype._itemElementInViewport):
+ (WebInspector.SelectionDialogContentProvider):
+ (WebInspector.SelectionDialogContentProvider.prototype.itemTitleAt):
+ (WebInspector.SelectionDialogContentProvider.prototype.itemKeyAt):
+ (WebInspector.SelectionDialogContentProvider.prototype.itemsCount):
+ (WebInspector.SelectionDialogContentProvider.prototype.requestItems):
+ (WebInspector.SelectionDialogContentProvider.prototype.selectItem):
+ (WebInspector.JavaScriptOutlineDialog):
+ (WebInspector.JavaScriptOutlineDialog.didAddChunk):
+ (WebInspector.JavaScriptOutlineDialog.install):
+ (WebInspector.JavaScriptOutlineDialog._show):
+ (WebInspector.JavaScriptOutlineDialog.createShortcut):
+ (WebInspector.JavaScriptOutlineDialog.prototype.itemTitleAt):
+ (WebInspector.JavaScriptOutlineDialog.prototype.itemKeyAt):
+ (WebInspector.JavaScriptOutlineDialog.prototype.itemsCount):
+ (WebInspector.JavaScriptOutlineDialog.prototype.requestItems):
+ (WebInspector.JavaScriptOutlineDialog.prototype.selectItem):
+ (WebInspector.JavaScriptOutlineDialog.prototype._appendItemElements):
+ * inspector/front-end/JavaScriptOutlineDialog.js: Removed.
+ * inspector/front-end/WebKit.qrc:
+ * inspector/front-end/filteredItemSelectionDialog.css: Renamed from Source/WebCore/inspector/front-end/javaScriptOutlineDialog.css.
+ (.js-outline-dialog > input):
+ (.js-outline-dialog > div.progress):
+ (.js-outline-dialog > div.container):
+ (.js-outline-dialog > .container > div.item):
+ (.js-outline-dialog > .container > div.item.selected):
+ (.js-outline-dialog > .container > div.item > span.highlight):
+ * inspector/front-end/inspector.html:
+
2012-01-17 Peter Rybin <peter.rybin@gmail.com>
Web Inspector: CodeGeneratorInspector.py: start using typedefs
'inspector/front-end/ExtensionPanel.js',
'inspector/front-end/ExtensionRegistryStub.js',
'inspector/front-end/ExtensionServer.js',
+ 'inspector/front-end/FilteredItemSelectionDialog.js',
'inspector/front-end/FontView.js',
'inspector/front-end/GoToLineDialog.js',
'inspector/front-end/HAREntry.js',
'inspector/front-end/InjectedFakeWorker.js',
'inspector/front-end/inspector.js',
'inspector/front-end/JavaScriptFormatter.js',
- 'inspector/front-end/JavaScriptOutlineDialog.js',
'inspector/front-end/JavaScriptSourceFrame.js',
'inspector/front-end/KeyboardShortcut.js',
'inspector/front-end/MetricsSidebarPane.js',
'inspector/front-end/auditsPanel.css',
'inspector/front-end/dataGrid.css',
'inspector/front-end/elementsPanel.css',
+ 'inspector/front-end/filteredItemSelectionDialog.css',
'inspector/front-end/heapProfiler.css',
'inspector/front-end/inspectorCommon.css',
- 'inspector/front-end/javaScriptOutlineDialog.css',
'inspector/front-end/networkLogView.css',
'inspector/front-end/networkPanel.css',
'inspector/front-end/panelEnablerView.css',
>
</File>
<File
+ RelativePath="..\inspector\front-end\FilteredItemSelectionDialog.js"
+ >
+ </File>
+ <File
+ RelativePath="..\inspector\front-end\filteredItemSelectionDialog.css"
+ >
+ </File>
+ <File
RelativePath="..\inspector\front-end\FontView.js"
>
</File>
>
</File>
<File
- RelativePath="..\inspector\front-end\JavaScriptOutlineDialog.js"
- >
- </File>
- <File
- RelativePath="..\inspector\front-end\javaScriptOutlineDialog.css"
- >
- </File>
- <File
RelativePath="..\inspector\front-end\JavaScriptSourceFrame.js"
>
</File>
--js Source/WebCore/inspector/front-end/DOMPresentationUtils.js \
--js Source/WebCore/inspector/front-end/ElementsTreeOutline.js \
--js Source/WebCore/inspector/front-end/EventListenersSidebarPane.js \
+ --js Source/WebCore/inspector/front-end/FilteredItemSelectionDialog.js \
--js Source/WebCore/inspector/front-end/GoToLineDialog.js \
--js Source/WebCore/inspector/front-end/JavaScriptContextManager.js \
- --js Source/WebCore/inspector/front-end/JavaScriptOutlineDialog.js \
--js Source/WebCore/inspector/front-end/ObjectPopoverHelper.js \
--js Source/WebCore/inspector/front-end/ObjectPropertiesSection.js \
--js Source/WebCore/inspector/front-end/PropertiesSidebarPane.js \
delegate.element.addStyleClass("dialog-contents");
this._element.appendChild(delegate.element);
- this._delegate.wasShown();
this._position();
this._windowResizeHandler = this._position.bind(this);
window.addEventListener("resize", this._windowResizeHandler, true);
this._delegate.willHide();
WebInspector.setCurrentFocusElement(this._previousFocusElement);
- WebInspector.Dialog._instance = null;
+ delete WebInspector.Dialog._instance;
document.body.removeChild(this._glassPaneElement);
window.removeEventListener("resize", this._windowResizeHandler, true);
},
}
WebInspector.DialogDelegate.prototype = {
- wasShown: function() { },
-
+ /**
+ * @param {Element} element
+ * @param {Element} relativeToElement
+ */
position: function(element, relativeToElement)
{
var offset = relativeToElement.offsetRelativeToWindow(window);
--- /dev/null
+/*
+ * Copyright (C) 2012 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.DialogDelegate}
+ * @param {WebInspector.SelectionDialogContentProvider} delegate
+ */
+WebInspector.FilteredItemSelectionDialog = function(delegate)
+{
+ WebInspector.DialogDelegate.call(this);
+
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "filteredItemSelectionDialog.css", false);
+ xhr.send(null);
+
+ this.element = document.createElement("div");
+ this.element.className = "js-outline-dialog";
+ this.element.addEventListener("keydown", this._onKeyDown.bind(this), false);
+ this.element.addEventListener("mousemove", this._onMouseMove.bind(this), false);
+ this.element.addEventListener("click", this._onClick.bind(this), false);
+ var styleElement = this.element.createChild("style");
+ styleElement.type = "text/css";
+ styleElement.textContent = xhr.responseText;
+
+ this._previousInputLength = 0;
+ this._itemElements = [];
+ this._elementIndexes = new Map();
+ this._elementHighlightChanges = new Map();
+
+ this._promptElement = this.element.createChild("input", "monospace");
+ this._promptElement.type = "text";
+ this._promptElement.setAttribute("spellcheck", "false");
+
+ this._progressElement = this.element.createChild("div", "progress");
+
+ this._itemElementsContainer = document.createElement("div");
+ this._itemElementsContainer.className = "container monospace";
+ this._itemElementsContainer.addEventListener("scroll", this._onScroll.bind(this), false);
+ this.element.appendChild(this._itemElementsContainer);
+
+ this._delegate = delegate;
+
+ this._delegate.requestItems(this._itemsLoaded.bind(this));
+}
+
+WebInspector.FilteredItemSelectionDialog.prototype = {
+ /**
+ * @param {Element} element
+ * @param {Element} relativeToElement
+ */
+ position: function(element, relativeToElement)
+ {
+ const minWidth = 500;
+ const minHeight = 204;
+ var width = Math.max(relativeToElement.offsetWidth * 2 / 3, minWidth);
+ var height = Math.max(relativeToElement.offsetHeight * 2 / 3, minHeight);
+
+ this.element.style.width = width + "px";
+ this.element.style.height = height + "px";
+
+ const shadowPadding = 10;
+ element.positionAt(
+ relativeToElement.totalOffsetLeft() + Math.max(relativeToElement.offsetWidth - width - shadowPadding, shadowPadding),
+ relativeToElement.totalOffsetTop() + Math.max((relativeToElement.offsetHeight - height) / 2 + shadowPadding, shadowPadding));
+ },
+
+ focus: function()
+ {
+ WebInspector.setCurrentFocusElement(this._promptElement);
+ },
+
+ willHide: function()
+ {
+ if (this._isHiding)
+ return;
+ this._isHiding = true;
+ if (this._filterTimer)
+ clearTimeout(this._filterTimer);
+ },
+
+ onEnter: function()
+ {
+ this._delegate.selectItem(this._elementIndexes.get(this._selectedElement));
+ },
+
+ /**
+ * @param {number} index
+ * @param {number} chunkLength
+ * @param {number} chunkIndex
+ * @param {number} chunkCount
+ */
+ _itemsLoaded: function(index, chunkLength, chunkIndex, chunkCount)
+ {
+ var fragment = document.createDocumentFragment();
+ var candidateItem = this._selectedElement;
+ for (var i = index; i < index + chunkLength; ++i) {
+ var itemElement = this._createItemElement(i, this._delegate.itemTitleAt(i));
+ if (this._checkItemAt(i, this._promptElement.value)) {
+ if (!candidateItem)
+ candidateItem = itemElement;
+ } else
+ this._hideItemElement(itemElement);
+ fragment.appendChild(itemElement);
+ }
+ this._itemElementsContainer.appendChild(fragment);
+ this._updateSelection(candidateItem);
+
+ if (chunkIndex === chunkCount)
+ this._progressElement.style.backgroundImage = "";
+ else {
+ const color = "rgb(66, 129, 235)";
+ const percent = ((chunkIndex / chunkCount) * 100) + "%";
+ this._progressElement.style.backgroundImage = "-webkit-linear-gradient(left, " + color + ", " + color + " " + percent + ", transparent " + percent + ")";
+ }
+ },
+
+ /**
+ * @param {number} index
+ * @param {string} title
+ */
+ _createItemElement: function(index, title)
+ {
+ if (this._itemElements[index])
+ return this._itemElements[index];
+
+ var itemElement = document.createElement("div");
+ itemElement.className = "item";
+ itemElement.textContent = title;
+ this._elementIndexes.put(itemElement, index);
+ this._itemElements.push(itemElement);
+
+ return itemElement;
+ },
+
+ /**
+ * @param {Element} itemElement
+ */
+ _hideItemElement: function(itemElement)
+ {
+ itemElement.style.display = "none";
+ },
+
+ /**
+ * @param {Element} itemElement
+ */
+ _itemElementVisible: function(itemElement)
+ {
+ return itemElement.style.display !== "none";
+ },
+
+ /**
+ * @param {Element} itemElement
+ */
+ _showItemElement: function(itemElement)
+ {
+ itemElement.style.display = "";
+ },
+
+ /**
+ * @param {number} index
+ */
+ _checkItemAt: function(index, query)
+ {
+ if (!query)
+ return true;
+ var regExp = this._createSearchRegExp(query);
+ var key = this._delegate.itemKeyAt(index);
+ return regExp.test(key);
+ },
+
+ /**
+ * @param {string=} query
+ * @param {boolean=} isGlobal
+ */
+ _createSearchRegExp: function(query, isGlobal)
+ {
+ var trimmedQuery = query.trim();
+ var regExpString = trimmedQuery.escapeForRegExp().replace(/\\\*/g, ".*").replace(/(?!^)([A-Z])/g, "[^A-Z]*$1");
+ var isSuffix = (query.charAt(query.length - 1) === " ");
+ if (isSuffix)
+ regExpString += "$";
+ return new RegExp(regExpString, (trimmedQuery === trimmedQuery.toLowerCase() ? "i" : "") + (isGlobal ? "g" : ""));
+ },
+
+ _filterItems: function()
+ {
+ delete this._filterTimer;
+
+ var query = this._promptElement.value;
+ var charsAdded = this._previousInputLength < query.length;
+ this._previousInputLength = query.length;
+ query = query.trim();
+
+ var firstElement;
+ for (var i = 0; i < this._itemElements.length; ++i) {
+ var itemElement = this._itemElements[i];
+
+ if (this._itemElementVisible(itemElement)) {
+ if (!this._checkItemAt(i, query))
+ this._hideItemElement(itemElement);
+ } else if (!charsAdded && this._checkItemAt(i, query))
+ this._showItemElement(itemElement);
+
+ if (!firstElement && this._itemElementVisible(itemElement))
+ firstElement = itemElement;
+ }
+
+ this._updateSelection(firstElement);
+ if (query) {
+ this._highlightItems(query);
+ this._query = query;
+ } else {
+ this._clearHighlight();
+ delete this._query;
+ }
+ },
+
+ _onKeyDown: function(event)
+ {
+ function nextItem(itemElement, isPageScroll, forward)
+ {
+ var scrollItemsLeft = isPageScroll && this._rowsPerViewport ? this._rowsPerViewport : 1;
+ var candidate = itemElement;
+ var lastVisibleCandidate = candidate;
+ do {
+ candidate = forward ? candidate.nextSibling : candidate.previousSibling;
+ if (!candidate) {
+ if (isPageScroll)
+ return lastVisibleCandidate;
+ else
+ candidate = forward ? this._itemElementsContainer.firstChild : this._itemElementsContainer.lastChild;
+ }
+ if (!this._itemElementVisible(candidate))
+ continue;
+ lastVisibleCandidate = candidate;
+ --scrollItemsLeft;
+ } while (scrollItemsLeft && candidate !== this._selectedElement);
+
+ return candidate;
+ }
+
+ var isPageScroll = false;
+
+ if (this._selectedElement) {
+ var candidate;
+ switch (event.keyCode) {
+ case WebInspector.KeyboardShortcut.Keys.Down.code:
+ candidate = nextItem.call(this, this._selectedElement, false, true);
+ break;
+ case WebInspector.KeyboardShortcut.Keys.Up.code:
+ candidate = nextItem.call(this, this._selectedElement, false, false);
+ break;
+ case WebInspector.KeyboardShortcut.Keys.PageDown.code:
+ candidate = nextItem.call(this, this._selectedElement, true, true);
+ break;
+ case WebInspector.KeyboardShortcut.Keys.PageUp.code:
+ candidate = nextItem.call(this, this._selectedElement, true, false);
+ break;
+ }
+
+ if (candidate) {
+ this._updateSelection(candidate);
+ event.preventDefault();
+ return;
+ }
+ }
+
+ if (event.keyIdentifier !== "Shift" && event.keyIdentifier !== "Ctrl" && event.keyIdentifier !== "Meta" && event.keyIdentifier !== "Left" && event.keyIdentifier !== "Right")
+ this._scheduleFilter();
+ },
+
+ _scheduleFilter: function()
+ {
+ if (this._filterTimer)
+ return;
+ this._filterTimer = setTimeout(this._filterItems.bind(this), 0);
+ },
+
+ /**
+ * @param {Element} newSelectedElement
+ */
+ _updateSelection: function(newSelectedElement)
+ {
+ if (this._selectedElement === newSelectedElement)
+ return;
+ if (this._selectedElement)
+ this._selectedElement.removeStyleClass("selected");
+
+ this._selectedElement = newSelectedElement;
+ if (newSelectedElement) {
+ newSelectedElement.addStyleClass("selected");
+ newSelectedElement.scrollIntoViewIfNeeded(false);
+ if (!this._itemHeight) {
+ this._itemHeight = newSelectedElement.offsetHeight;
+ this._rowsPerViewport = Math.floor(this._itemElementsContainer.offsetHeight / this._itemHeight);
+ }
+ }
+ },
+
+ _onClick: function(event)
+ {
+ var itemElement = event.target.enclosingNodeOrSelfWithClass("item");
+ if (!itemElement)
+ return;
+ this._updateSelection(itemElement);
+ this._delegate.selectItem(this._elementIndexes.get(this._selectedElement));
+ WebInspector.Dialog.hide();
+ },
+
+ _onMouseMove: function(event)
+ {
+ var itemElement = event.target.enclosingNodeOrSelfWithClass("item");
+ if (!itemElement)
+ return;
+ this._updateSelection(itemElement);
+ },
+
+ _onScroll: function()
+ {
+ if (this._query)
+ this._highlightItems(this._query);
+ else
+ this._clearHighlight();
+ },
+
+ /**
+ * @param {string=} query
+ */
+ _highlightItems: function(query)
+ {
+ var regex = this._createSearchRegExp(query, true);
+ for (var i = 0; i < this._delegate.itemsCount(); ++i) {
+ var itemElement = this._itemElements[i];
+ if (this._itemElementVisible(itemElement) && this._itemElementInViewport(itemElement))
+ this._highlightItem(itemElement, regex);
+ }
+ },
+
+ _clearHighlight: function()
+ {
+ for (var i = 0; i < this._delegate.itemsCount(); ++i)
+ this._clearElementHighlight(this._itemElements[i]);
+ },
+
+ /**
+ * @param {Element} itemElement
+ */
+ _clearElementHighlight: function(itemElement)
+ {
+ var changes = this._elementHighlightChanges.get(itemElement)
+ if (changes) {
+ revertDomChanges(changes);
+ this._elementHighlightChanges.remove(itemElement);
+ }
+ },
+
+ /**
+ * @param {Element} itemElement
+ * @param {RegExp} regex
+ */
+ _highlightItem: function(itemElement, regex)
+ {
+ this._clearElementHighlight(itemElement);
+
+ var key = this._delegate.itemKeyAt(this._elementIndexes.get(itemElement));
+ var ranges = [];
+
+ var match;
+ while ((match = regex.exec(key)) !== null) {
+ ranges.push({ offset: match.index, length: regex.lastIndex - match.index });
+ }
+
+ var changes = [];
+ highlightRangesWithStyleClass(itemElement, ranges, "highlight", changes);
+
+ if (changes.length)
+ this._elementHighlightChanges.put(itemElement, changes);
+ },
+
+ /**
+ * @param {Element} itemElement
+ * @return {boolean}
+ */
+ _itemElementInViewport: function(itemElement)
+ {
+ if (itemElement.offsetTop + this._itemHeight < this._itemElementsContainer.scrollTop)
+ return false;
+ if (itemElement.offsetTop > this._itemElementsContainer.scrollTop + this._itemHeight * (this._rowsPerViewport + 1))
+ return false;
+ return true;
+ }
+}
+
+WebInspector.FilteredItemSelectionDialog.prototype.__proto__ = WebInspector.DialogDelegate.prototype;
+
+/**
+ * @interface
+ */
+WebInspector.SelectionDialogContentProvider = function()
+{
+}
+
+WebInspector.SelectionDialogContentProvider.prototype = {
+ /**
+ * @param {number} itemIndex
+ * @return {string}
+ */
+ itemTitleAt: function(itemIndex) { },
+
+ /**
+ * @param {number} itemIndex
+ * @return {string}
+ */
+ itemKeyAt: function(itemIndex) { },
+
+ /**
+ * @return {number}
+ */
+ itemsCount: function() { },
+
+ /**
+ * @param {function(number, number, number, number)} callback
+ */
+ requestItems: function(callback) { },
+
+ /**
+ * @param {number} itemIndex
+ */
+ selectItem: function(itemIndex) { }
+};
+
+/**
+ * @constructor
+ * @implements {WebInspector.SelectionDialogContentProvider}
+ */
+WebInspector.JavaScriptOutlineDialog = function(panel, view)
+{
+ WebInspector.SelectionDialogContentProvider.call(this);
+
+ this._functionItems = [];
+
+ this._panel = panel;
+ this._view = view;
+}
+
+/**
+ * @param {{chunk, index, total, id}} data
+ */
+WebInspector.JavaScriptOutlineDialog.didAddChunk = function(data)
+{
+ var instance = WebInspector.JavaScriptOutlineDialog._instance;
+ if (!instance)
+ return;
+
+ if (data.id !== instance._view.uiSourceCode.id)
+ return;
+
+ instance._appendItemElements(data.chunk, data.index, data.total);
+},
+
+WebInspector.JavaScriptOutlineDialog.install = function(panel, viewGetter)
+{
+ function showJavaScriptOutlineDialog()
+ {
+ var view = viewGetter();
+ if (view)
+ WebInspector.JavaScriptOutlineDialog._show(panel, view);
+ }
+
+ var javaScriptOutlineShortcut = WebInspector.JavaScriptOutlineDialog.createShortcut();
+ panel.registerShortcut(javaScriptOutlineShortcut.key, showJavaScriptOutlineDialog);
+}
+
+WebInspector.JavaScriptOutlineDialog._show = function(panel, sourceView)
+{
+ if (WebInspector.Dialog.currentInstance())
+ return;
+ if (!sourceView || !sourceView.canHighlightLine())
+ return;
+ WebInspector.JavaScriptOutlineDialog._instance = new WebInspector.JavaScriptOutlineDialog(panel, sourceView);
+
+ var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(WebInspector.JavaScriptOutlineDialog._instance);
+ WebInspector.Dialog.show(sourceView.element, filteredItemSelectionDialog);
+}
+
+WebInspector.JavaScriptOutlineDialog.createShortcut = function()
+{
+ if (WebInspector.isMac())
+ return WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.Meta);
+ return WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
+}
+
+WebInspector.JavaScriptOutlineDialog.prototype = {
+ /**
+ * @param {number} itemIndex
+ * @return {string}
+ */
+ itemTitleAt: function(itemIndex)
+ {
+ var functionItem = this._functionItems[itemIndex];
+ return functionItem.name + (functionItem.arguments ? functionItem.arguments : "");
+ },
+
+ /**
+ * @param {number} itemIndex
+ * @return {string}
+ */
+ itemKeyAt: function(itemIndex)
+ {
+ return this._functionItems[itemIndex].name;
+ },
+
+ /**
+ * @return {number}
+ */
+ itemsCount: function()
+ {
+ return this._functionItems.length;
+ },
+
+ /**
+ * @param {function(number, number, number, number)} callback
+ */
+ requestItems: function(callback)
+ {
+ this._itemsAddedCallback = callback;
+ this._panel.requestVisibleScriptOutline();
+ },
+
+ /**
+ * @param {number} itemIndex
+ */
+ selectItem: function(itemIndex)
+ {
+ var lineNumber = this._functionItems[itemIndex].line;
+ if (!isNaN(lineNumber) && lineNumber >= 0)
+ this._view.highlightLine(lineNumber);
+ delete WebInspector.JavaScriptOutlineDialog._instance;
+ },
+
+ /**
+ * @param {Array.<Object>} chunk
+ * @param {number} chunkIndex
+ * @param {number} chunkCount
+ */
+ _appendItemElements: function(chunk, chunkIndex, chunkCount)
+ {
+ var index = this._functionItems.length;
+ for (var i = 0; i < chunk.length; ++i) {
+ this._functionItems.push(chunk[i]);
+ }
+ this._itemsAddedCallback(index, chunk.length, chunkIndex, chunkCount);
+ }
+}
+
+WebInspector.JavaScriptOutlineDialog.prototype.__proto__ = WebInspector.SelectionDialogContentProvider.prototype;
+++ /dev/null
-/*
- * 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:
- *
- * * 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
- */
-WebInspector.JavaScriptOutlineDialog = function(panel, view)
-{
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "javaScriptOutlineDialog.css", false);
- xhr.send(null);
-
- this._element = document.createElement("div");
- this._element.className = "js-outline-dialog";
- this._element.addEventListener("keydown", this._onKeyDown.bind(this), false);
- this._element.addEventListener("mousemove", this._onMouseMove.bind(this), false);
- this._element.addEventListener("click", this._onClick.bind(this), false);
- var styleElement = this._element.createChild("style");
- styleElement.type = "text/css";
- styleElement.textContent = xhr.responseText;
-
- this._closeKeys = [
- WebInspector.KeyboardShortcut.Keys.Enter.code,
- WebInspector.KeyboardShortcut.Keys.Esc.code,
- ];
- this._itemElements = [];
- this._previousInputLength = 0;
- this._visibleElements = [];
-
- var dialogWindow = this._element;
- this._boundBlurHandler = this._onBlur.bind(this);
-
- this._promptElement = dialogWindow.createChild("input", "monospace");
- this._promptElement.type = "text";
- this._promptElement.setAttribute("spellcheck", "false");
- this._promptElement.addEventListener("blur", this._boundBlurHandler, false);
-
- function onMouseDown(event)
- {
- if (event.target === this._promptElement)
- return;
- var itemElement = event.target.enclosingNodeOrSelfWithClass("item");
- if (!itemElement) {
- event.stopPropagation();
- event.preventDefault();
- }
-
- // Prevent blur listener from prematurely closing the dialog when an item is clicked.
- this._promptElement.removeEventListener("blur", this._boundBlurHandler, false);
- }
- this._element.addEventListener("mousedown", onMouseDown.bind(this), false);
-
- this._progressElement = dialogWindow.createChild("div", "progress");
-
- this._functionItemContainer = document.createElement("div");
- this._functionItemContainer.className = "container monospace";
- this._functionItemContainer.addEventListener("scroll", this._onScroll.bind(this), false);
-
- this._panel = panel;
- this._view = view;
-
- this._panel.requestVisibleScriptOutline();
- this._resizeWindow();
-
- this._previousFocusElement = WebInspector.currentFocusElement();
- WebInspector.setCurrentFocusElement(this._promptElement);
-
- this._highlighter = new WebInspector.JavaScriptOutlineDialog.MatchHighlighter(this);
-}
-
-/**
- * @param {{chunk, index, total, id}} data
- */
-WebInspector.JavaScriptOutlineDialog.didAddChunk = function(data)
-{
- var instance = WebInspector.JavaScriptOutlineDialog._instance;
- if (!instance)
- return;
-
- if (data.id !== instance._view.uiSourceCode.id)
- return;
-
- instance._appendItemElements(data.chunk);
-
- if (data.index === data.total) {
- instance._progressElement.style.backgroundImage = "";
- instance._filterFunctions();
- } else {
- const color = "rgb(66, 129, 235)";
- const percent = ((data.index / data.total) * 100) + "%";
- instance._progressElement.style.backgroundImage = "-webkit-linear-gradient(left, " + color + ", " + color + " " + percent + ", transparent " + percent + ")";
- }
-},
-
-WebInspector.JavaScriptOutlineDialog.install = function(panel, viewGetter)
-{
- function showJavaScriptOutlineDialog()
- {
- var view = viewGetter();
- if (view)
- WebInspector.JavaScriptOutlineDialog._show(panel, view);
- }
-
- var javaScriptOutlineShortcut = WebInspector.JavaScriptOutlineDialog.createShortcut();
- panel.registerShortcut(javaScriptOutlineShortcut.key, showJavaScriptOutlineDialog);
-}
-
-WebInspector.JavaScriptOutlineDialog._show = function(panel, sourceView)
-{
- if (!sourceView || !sourceView.canHighlightLine())
- return;
- if (WebInspector.JavaScriptOutlineDialog._instance)
- return;
- WebInspector.JavaScriptOutlineDialog._instance = new WebInspector.JavaScriptOutlineDialog(panel, sourceView);
-}
-
-WebInspector.JavaScriptOutlineDialog.createShortcut = function()
-{
- if (WebInspector.isMac())
- return WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.Meta);
- return WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
-}
-
-WebInspector.JavaScriptOutlineDialog.prototype = {
- _resizeWindow: function()
- {
- const minWidth = 500;
- const minHeight = 204;
- const totalWidthDelta = 40;
- const totalHeightDelta = 78;
- this._element.appendChild(this._functionItemContainer);
- var width = Math.max(this._view.element.offsetWidth * 2 / 3, minWidth);
- var height = Math.max(this._view.element.offsetHeight * 2 / 3, minHeight);
-
- const shadowPadding = 10;
- this._element.positionAt(
- this._view.element.totalOffsetLeft() + Math.max(this._view.element.offsetWidth - width - shadowPadding, shadowPadding),
- this._view.element.totalOffsetTop() + Math.max((this._view.element.offsetHeight - height) / 2 + shadowPadding, shadowPadding));
- this._element.style.width = width + "px";
- this._element.style.height = height + "px";
-
- document.body.appendChild(this._element);
- },
-
- _appendItemElements: function(chunk)
- {
- var regExp;
- if (this._promptElement.value)
- regExp = this._createSearchRegExp(this._promptElement.value);
- var fragment = document.createDocumentFragment();
- var candidateItem = this._selectedElement;
- for (var i = 0; i < chunk.length; ++i) {
- var isVisible = true;
- var entry = chunk[i];
- var functionItem = document.createElement("div");
- functionItem.className = "item";
- functionItem._text = entry.name;
- functionItem._arguments = (entry.arguments ? entry.arguments : "");
- functionItem.textContent = functionItem._text + functionItem._arguments;
- if (regExp && !regExp.test(functionItem._text)) {
- functionItem.style.display = "none";
- isVisible = false;
- }
- functionItem._line = entry.line;
- this._itemElements.push(functionItem);
- if (!candidateItem && isVisible)
- candidateItem = functionItem;
- fragment.appendChild(functionItem);
- this._visibleElements.push(functionItem);
- }
- this._functionItemContainer.appendChild(fragment);
- this._updateSelection(candidateItem);
- },
-
- /**
- * @param {boolean=} isGlobal
- */
- _createSearchRegExp: function(query, isGlobal)
- {
- var trimmedQuery = query.trim();
- var regExpString = trimmedQuery.escapeForRegExp().replace(/\\\*/g, ".*").replace(/(?!^)([A-Z])/g, "[^A-Z]*$1");
- var isSuffix = (query.charAt(query.length - 1) === " ");
- if (isSuffix)
- regExpString += "$";
- return new RegExp(regExpString, (trimmedQuery === trimmedQuery.toLowerCase() ? "i" : "") + (isGlobal ? "g" : ""));
- },
-
- _filterFunctions: function()
- {
- delete this._filterTimer;
-
- var query = this._promptElement.value;
- var charsAdded = this._previousInputLength < query.length;
- this._previousInputLength = query.length;
- if (!query.trim()) {
- this._visibleElements = [];
- for (var i = 0; i < this._itemElements.length; ++i) {
- var element = this._itemElements[i];
- element.style.display = "";
- this._visibleElements.push(element);
- }
- this._updateSelection(this._functionItemContainer.firstChild);
- delete this._query;
- this._highlighter.clearHighlight();
- return;
- }
-
- this._query = query;
- var regExp = this._createSearchRegExp(query);
- var firstElement;
- var newVisibleElements = [];
- if (charsAdded) {
- for (var i = 0; i < this._visibleElements.length; ++i) {
- var element = this._visibleElements[i];
- if (regExp.test(element._text)) {
- if (!firstElement)
- firstElement = element;
- newVisibleElements.push(element);
- } else
- element.style.display = "none";
- }
- this._visibleElements = newVisibleElements;
- this._updateSelection(firstElement);
- this._highlighter.highlightViewportItems(query);
- return;
- }
-
- for (var i = 0; i < this._itemElements.length; ++i) {
- var element = this._itemElements[i];
- if (regExp.test(element._text)) {
- if (!firstElement)
- firstElement = element;
- element.style.display = "";
- newVisibleElements.push(element);
- } else
- element.style.display = "none";
- }
- this._visibleElements = newVisibleElements;
- this._updateSelection(firstElement);
- this._highlighter.highlightViewportItems(query);
- },
-
- _selectFirstItem: function()
- {
- var selectedElement;
- for (var child = this._functionItemContainer.firstChild; child; child = child.nextSibling) {
- if (child.style.display !== "none") {
- selectedElement = child;
- break;
- }
- }
- this._updateSelection(selectedElement);
- },
-
- _hide: function()
- {
- if (this._isHiding)
- return;
- this._isHiding = true;
- if (this._filterTimer)
- clearTimeout(this._filterTimer);
- this._element.parentElement.removeChild(this._element);
- WebInspector.JavaScriptOutlineDialog._instance = null;
-
- WebInspector.setCurrentFocusElement(this._previousFocusElement);
- },
-
- _onBlur: function(event)
- {
- this._hide();
- },
-
- _onKeyDown: function(event)
- {
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) {
- event.preventDefault();
- return;
- }
-
- function previousItem(itemElement, isPageScroll)
- {
- var scrollItemsLeft = isPageScroll && this._rowsPerViewport ? this._rowsPerViewport : 1;
- var candidate = itemElement;
- var lastVisibleCandidate = candidate;
- do {
- candidate = candidate.previousSibling;
- if (!candidate) {
- if (isPageScroll)
- return lastVisibleCandidate;
- else
- candidate = this._functionItemContainer.lastChild;
- }
- if (candidate.style.display === "none")
- continue;
- lastVisibleCandidate = candidate;
- --scrollItemsLeft;
- } while (scrollItemsLeft && candidate !== this._selectedElement);
-
- return candidate;
- }
-
- function nextItem(itemElement, isPageScroll)
- {
- var scrollItemsLeft = isPageScroll && this._rowsPerViewport ? this._rowsPerViewport : 1;
- var candidate = itemElement;
- var lastVisibleCandidate = candidate;
- do {
- candidate = candidate.nextSibling;
- if (!candidate) {
- if (isPageScroll)
- return lastVisibleCandidate;
- else
- candidate = this._functionItemContainer.firstChild;
- }
- if (candidate.style.display === "none")
- continue;
- lastVisibleCandidate = candidate;
- --scrollItemsLeft;
- } while (scrollItemsLeft && candidate !== this._selectedElement);
-
- return candidate;
- }
-
- var delta = 1;
- var isPageScroll = false;
-
- switch (event.keyCode) {
- case WebInspector.KeyboardShortcut.Keys.Up.code:
- case WebInspector.KeyboardShortcut.Keys.PageUp.code:
- if (!this._selectedElement)
- return;
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.PageUp.code)
- isPageScroll = true;
-
- var candidate = previousItem.call(this, this._selectedElement, isPageScroll);
- this._updateSelection(candidate);
- event.preventDefault();
- return;
-
- case WebInspector.KeyboardShortcut.Keys.Down.code:
- case WebInspector.KeyboardShortcut.Keys.PageDown.code:
- if (!this._selectedElement)
- return;
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.PageDown.code)
- isPageScroll = true;
-
- var candidate = nextItem.call(this, this._selectedElement, isPageScroll);
- this._updateSelection(candidate);
- event.preventDefault();
- return;
- }
-
- if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code)
- this._highlightFunctionLine();
-
- if (this._closeKeys.indexOf(event.keyCode) >= 0) {
- this._hide();
- event.preventDefault();
- event.stopPropagation();
- } else if (event.keyIdentifier !== "Shift" && event.keyIdentifier !== "Ctrl" && event.keyIdentifier !== "Meta" && event.keyIdentifier !== "Left" && event.keyIdentifier !== "Right")
- this._scheduleFilter();
- },
-
- _scheduleFilter: function()
- {
- if (this._filterTimer)
- return;
- this._filterTimer = setTimeout(this._filterFunctions.bind(this), 0);
- },
-
- _updateSelection: function(newSelectedElement)
- {
- if (this._selectedElement === newSelectedElement)
- return;
- if (this._selectedElement)
- this._selectedElement.removeStyleClass("selected");
-
- this._selectedElement = newSelectedElement;
- if (newSelectedElement) {
- newSelectedElement.addStyleClass("selected");
- newSelectedElement.scrollIntoViewIfNeeded(false);
- if (!this._itemHeight) {
- this._itemHeight = newSelectedElement.offsetHeight;
- this._rowsPerViewport = Math.floor(this._functionItemContainer.offsetHeight / this._itemHeight);
- }
- }
- },
-
- _onClick: function(event)
- {
- var itemElement = event.target.enclosingNodeOrSelfWithClass("item");
- if (!itemElement)
- return;
- this._updateSelection(itemElement);
- this._highlightFunctionLine();
- this._hide();
- },
-
- _onMouseMove: function(event)
- {
- var itemElement = event.target.enclosingNodeOrSelfWithClass("item");
- if (!itemElement)
- return;
- this._updateSelection(itemElement);
- },
-
- _onScroll: function()
- {
- if (this._query)
- this._highlighter.highlightViewportItems(this._query);
- else
- this._highlighter.clearHighlight();
- },
-
- _highlightFunctionLine: function()
- {
- var lineNumber = this._selectedElement._line;
- if (!isNaN(lineNumber) && lineNumber >= 0)
- this._view.highlightLine(lineNumber);
- }
-}
-
-/**
-* @constructor
-*/
-WebInspector.JavaScriptOutlineDialog.MatchHighlighter = function(dialog)
-{
- this._dialog = dialog;
-}
-
-WebInspector.JavaScriptOutlineDialog.MatchHighlighter.prototype = {
- highlightViewportItems: function(query)
- {
- var regex = this._dialog._createSearchRegExp(query, true);
- var range = this._viewportRowRange();
- var visibleElements = this._dialog._visibleElements;
- for (var i = range[0]; i < range[1]; ++i)
- this._highlightItem(visibleElements[i], regex);
- },
-
- clearHighlight: function()
- {
- var range = this._viewportRowRange();
- var visibleElements = this._dialog._visibleElements;
- for (var i = range[0]; i < range[1]; ++i) {
- var element = visibleElements[i];
- if (element._domChanges) {
- revertDomChanges(element._domChanges);
- delete element._domChanges;
- }
- }
- },
-
- _highlightItem: function(element, regex)
- {
- if (element._domChanges) {
- revertDomChanges(element._domChanges);
- delete element._domChanges;
- }
-
- var text = element._text;
- var ranges = [];
-
- var match;
- while ((match = regex.exec(text)) !== null) {
- ranges.push({ offset: match.index, length: regex.lastIndex - match.index });
- }
-
- var changes = [];
- highlightRangesWithStyleClass(element, ranges, "highlight", changes);
-
- if (changes.length)
- element._domChanges = changes;
- },
-
- _viewportRowRange: function()
- {
- var dialog = this._dialog;
- var startIndex = Math.floor(dialog._functionItemContainer.scrollTop / dialog._itemHeight);
- var endIndex = Math.min(dialog._visibleElements.length, startIndex + dialog._rowsPerViewport + 1);
- return [startIndex, endIndex];
- }
-}
/**
* @param {WebInspector.Resource} resource
- * @param {?NetworkAgent.Response} response
+ * @param {NetworkAgent.Response=} response
*/
_updateResourceWithResponse: function(resource, response)
{
<file>ExtensionPanel.js</file>
<file>ExtensionRegistryStub.js</file>
<file>ExtensionServer.js</file>
+ <file>FilteredItemSelectionDialog.js</file>
<file>FontView.js</file>
<file>GoToLineDialog.js</file>
<file>HAREntry.js</file>
<file>InspectorView.js</file>
<file>JavaScriptContextManager.js</file>
<file>JavaScriptFormatter.js</file>
- <file>JavaScriptOutlineDialog.js</file>
<file>JavaScriptSourceFrame.js</file>
<file>KeyboardShortcut.js</file>
<file>MetricsSidebarPane.js</file>
<file>UglifyJS/parse-js.js</file>
<file>auditsPanel.css</file>
<file>dataGrid.css</file>
- <file>elementsPanel.css</file>
<file>dialog.css</file>
+ <file>elementsPanel.css</file>
+ <file>filteredItemSelectionDialog.css</file>
<file>heapProfiler.css</file>
<file>helpScreen.css</file>
<file>inspector.css</file>
<file>inspectorCommon.css</file>
<file>inspectorSyntaxHighlight.css</file>
- <file>javaScriptOutlineDialog.css</file>
<file>networkLogView.css</file>
<file>networkPanel.css</file>
<file>panelEnablerView.css</file>
-.js-outline-dialog {
- position: absolute;
- top: 20%;
- left: 20%;
- z-index: 1900;
- overflow: hidden;
-
- background-color: whitesmoke;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- padding: 10px;
- border-radius: 10px;
- border: 1px solid gray;
- -webkit-box-shadow: rgb(40,40,40) 0px 0px 50px;
-
- font-size: 11px;
- font-family: 'Lucida Grande', sans-serif;
-}
-
.js-outline-dialog > input {
font-size: 11px;
width: 100%;
<script type="text/javascript" src="TextViewer.js"></script>
<script type="text/javascript" src="SourceFrame.js"></script>
<script type="text/javascript" src="ResourceView.js"></script>
- <script type="text/javascript" src="JavaScriptOutlineDialog.js"></script>
<script type="text/javascript" src="JavaScriptSourceFrame.js"></script>
<script type="text/javascript" src="SplitView.js"></script>
<script type="text/javascript" src="TabbedEditorContainer.js"></script>
<script type="text/javascript" src="HelpScreen.js"></script>
<script type="text/javascript" src="Dialog.js"></script>
<script type="text/javascript" src="GoToLineDialog.js"></script>
+ <script type="text/javascript" src="FilteredItemSelectionDialog.js"></script>
<script type="text/javascript" src="SettingsScreen.js"></script>
<script type="text/javascript" src="ShortcutsScreen.js"></script>
<script type="text/javascript" src="HAREntry.js"></script>