Web Inspector: Filters on Console panel
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2013 15:10:57 +0000 (15:10 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2013 15:10:57 +0000 (15:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=107813

Source/WebCore:

The problem is that third-party libraries may spam javascript console with internal
messages. Now there's filter context-menu option, which allows to hide/show messages
sent from specific scripts or urls.

Patch by Dmitry Zvorygin <zvorygin@chromium.org> on 2013-01-30
Reviewed by Pavel Feldman.

* English.lproj/localizedStrings.js:
* inspector/front-end/ConsoleMessage.js:
(WebInspector.ConsoleMessageImpl.prototype.appendUndefined):
(WebInspector.ConsoleMessageImpl.prototype._printArray):
(WebInspector.ConsoleMessageImpl.prototype._highlightSearchResultsInElement):
* inspector/front-end/ConsolePanel.js:
(WebInspector.ConsolePanel.prototype.performSearch):
* inspector/front-end/ConsoleView.js:
(WebInspector.ConsoleView.get this):
(WebInspector.ConsoleView.prototype._consoleMessageAdded):
(WebInspector.ConsoleView.prototype._appendConsoleMessage):
(WebInspector.ConsoleView.prototype._consoleCleared):
(WebInspector.ConsoleView.prototype._handleContextMenuEvent.get var):
(WebInspector.ConsoleView.prototype._handleContextMenuEvent.set get contextMenu):
(WebInspector.ConsoleView.prototype._shouldBeVisible):
(WebInspector.ConsoleView.prototype._updateMessageList):
(WebInspector.ConsoleGroup.prototype.addMessage):
* inspector/front-end/ContextMenu.js:
(WebInspector.ContextMenuItem.prototype.isEnabled):
(WebInspector.ContextMenuItem.prototype.setEnabled):
* inspector/front-end/Settings.js:

LayoutTests:

The problem is that third-party libraries may spam javascript console
with internal  messages. Now there's filter context-menu option, which
allows to hide/show messages sent from specific scripts or urls.

Patch by Dmitry Zvorygin <zvorygin@chromium.org> on 2013-01-30
Reviewed by Pavel Feldman.

* http/tests/inspector/console-test.js:
(initialize_ConsoleTest.InspectorTest.dumpConsoleMessages):
(initialize_ConsoleTest.InspectorTest.dumpConsoleMessagesWithStyles):
(initialize_ConsoleTest.InspectorTest.dumpConsoleMessagesWithClasses):
(initialize_ConsoleTest.InspectorTest.expandConsoleMessages):
(initialize_ConsoleTest.InspectorTest.checkConsoleMessagesDontHaveParameters):
(initialize_ConsoleTest):
* http/tests/inspector/stacktraces/resources/stacktrace-test.js:
(test.addMessage):
(test):
* inspector/console/console-filter-test-expected.txt: Added.
* inspector/console/console-filter-test.html: Added.
* inspector/console/resources/log-source.js: Added.
(log2):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@141269 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/console-test.js
LayoutTests/http/tests/inspector/stacktraces/resources/stacktrace-test.js
LayoutTests/inspector/console/console-filter-test-expected.txt [new file with mode: 0644]
LayoutTests/inspector/console/console-filter-test.html [new file with mode: 0644]
LayoutTests/inspector/console/resources/log-source.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/English.lproj/localizedStrings.js
Source/WebCore/inspector/front-end/ConsoleMessage.js
Source/WebCore/inspector/front-end/ConsolePanel.js
Source/WebCore/inspector/front-end/ConsoleView.js
Source/WebCore/inspector/front-end/ContextMenu.js
Source/WebCore/inspector/front-end/Settings.js

index ab19b4c..b8c2d9d 100644 (file)
@@ -1,3 +1,29 @@
+2013-01-30  Dmitry Zvorygin  <zvorygin@chromium.org>
+
+        Web Inspector: Filters on Console panel
+        https://bugs.webkit.org/show_bug.cgi?id=107813
+
+        The problem is that third-party libraries may spam javascript console
+        with internal  messages. Now there's filter context-menu option, which
+        allows to hide/show messages sent from specific scripts or urls.
+
+        Reviewed by Pavel Feldman.
+
+        * http/tests/inspector/console-test.js:
+        (initialize_ConsoleTest.InspectorTest.dumpConsoleMessages):
+        (initialize_ConsoleTest.InspectorTest.dumpConsoleMessagesWithStyles):
+        (initialize_ConsoleTest.InspectorTest.dumpConsoleMessagesWithClasses):
+        (initialize_ConsoleTest.InspectorTest.expandConsoleMessages):
+        (initialize_ConsoleTest.InspectorTest.checkConsoleMessagesDontHaveParameters):
+        (initialize_ConsoleTest):
+        * http/tests/inspector/stacktraces/resources/stacktrace-test.js:
+        (test.addMessage):
+        (test):
+        * inspector/console/console-filter-test-expected.txt: Added.
+        * inspector/console/console-filter-test.html: Added.
+        * inspector/console/resources/log-source.js: Added.
+        (log2):
+
 2013-01-30  Ádám Kallai  <kadam@inf.u-szeged.hu>
 
         [Qt] Unreviewed gardening. Skip some failing tests.
index 5beb321..707d7e4 100644 (file)
@@ -9,7 +9,7 @@ InspectorTest.showConsolePanel = function()
 InspectorTest.dumpConsoleMessages = function(printOriginatingCommand)
 {
     var result = [];
-    var messages = WebInspector.consoleView.messages;
+    var messages = WebInspector.consoleView._visibleMessages;
     for (var i = 0; i < messages.length; ++i) {
         var element = messages[i].toMessageElement();
         InspectorTest.addResult(element.textContent.replace(/\u200b/g, ""));
@@ -24,7 +24,7 @@ InspectorTest.dumpConsoleMessages = function(printOriginatingCommand)
 InspectorTest.dumpConsoleMessagesWithStyles = function(sortMessages)
 {
     var result = [];
-    var messages = WebInspector.consoleView.messages;
+    var messages = WebInspector.consoleView._visibleMessages;
     for (var i = 0; i < messages.length; ++i) {
         var element = messages[i].toMessageElement();
         InspectorTest.addResult(element.textContent.replace(/\u200b/g, ""));
@@ -36,7 +36,7 @@ InspectorTest.dumpConsoleMessagesWithStyles = function(sortMessages)
 
 InspectorTest.dumpConsoleMessagesWithClasses = function(sortMessages) {
     var result = [];
-    var messages = WebInspector.consoleView.messages;
+    var messages = WebInspector.consoleView._visibleMessages;
     for (var i = 0; i < messages.length; ++i) {
         var element = messages[i].toMessageElement();
         result.push(element.textContent.replace(/\u200b/g, "") + " " + element.getAttribute("class"));
@@ -49,7 +49,7 @@ InspectorTest.dumpConsoleMessagesWithClasses = function(sortMessages) {
 
 InspectorTest.expandConsoleMessages = function()
 {
-    var messages = WebInspector.consoleView.messages;
+    var messages = WebInspector.consoleView._visibleMessages;
     for (var i = 0; i < messages.length; ++i) {
         var element = messages[i].toMessageElement();
         var node = element;
@@ -63,7 +63,7 @@ InspectorTest.expandConsoleMessages = function()
 
 InspectorTest.checkConsoleMessagesDontHaveParameters = function()
 {
-    var messages = WebInspector.console.messages;
+    var messages = WebInspector.consoleView._visibleMessages;
     for (var i = 0; i < messages.length; ++i) {
         var m = messages[i];
         InspectorTest.addResult("Message[" + i + "]:");
index 76ff1d4..0351f0a 100644 (file)
@@ -2,7 +2,7 @@ function test() {
     InspectorTest.addConsoleSniffer(addMessage);
 
     function addMessage(message) {
-        var messages = WebInspector.consoleView.messages;
+        var messages = WebInspector.consoleView._visibleMessages;
         for (var i = 0; i < messages.length; ++i) {
             var m = messages[i];
             InspectorTest.addResult("Message[" + i + "]: " + WebInspector.displayNameForURL(m.url) + ":" + m.line + " " + m.message);
diff --git a/LayoutTests/inspector/console/console-filter-test-expected.txt b/LayoutTests/inspector/console/console-filter-test-expected.txt
new file mode 100644 (file)
index 0000000..fb6d8c9
--- /dev/null
@@ -0,0 +1,60 @@
+CONSOLE MESSAGE: line 9: 0
+CONSOLE MESSAGE: line 3: 1
+CONSOLE MESSAGE: line 9: 2
+CONSOLE MESSAGE: line 3: 3
+CONSOLE MESSAGE: line 9: 4
+CONSOLE MESSAGE: line 3: 5
+CONSOLE MESSAGE: line 9: 6
+CONSOLE MESSAGE: line 3: 7
+CONSOLE MESSAGE: line 9: 8
+CONSOLE MESSAGE: line 3: 9
+CONSOLE MESSAGE: line 22: 10
+Tests that console can filter messages by source.
+
+
+Running: beforeFilter
+beforeFilter
+0 console-filter-test.html:9
+1 log-source.js:3
+2 console-filter-test.html:9
+3 log-source.js:3
+4 console-filter-test.html:9
+5 log-source.js:3
+6 console-filter-test.html:9
+7 log-source.js:3
+8 console-filter-test.html:9
+9 log-source.js:3
+10 console-filter-test.html:22
+
+Running: addURL1Filter
+1 log-source.js:3
+3 log-source.js:3
+5 log-source.js:3
+7 log-source.js:3
+9 log-source.js:3
+
+Running: addURL2Filter
+
+Running: removeURL1Filter
+0 console-filter-test.html:9
+2 console-filter-test.html:9
+4 console-filter-test.html:9
+6 console-filter-test.html:9
+8 console-filter-test.html:9
+10 console-filter-test.html:22
+
+Running: restoreURL1Filter
+
+Running: removeAllFilters
+0 console-filter-test.html:9
+1 log-source.js:3
+2 console-filter-test.html:9
+3 log-source.js:3
+4 console-filter-test.html:9
+5 log-source.js:3
+6 console-filter-test.html:9
+7 log-source.js:3
+8 console-filter-test.html:9
+9 log-source.js:3
+10 console-filter-test.html:22
+
diff --git a/LayoutTests/inspector/console/console-filter-test.html b/LayoutTests/inspector/console/console-filter-test.html
new file mode 100644 (file)
index 0000000..6afed1a
--- /dev/null
@@ -0,0 +1,92 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/console-test.js"></script>
+<script src="resources/log-source.js"></script>
+<script>
+function log1()
+{
+    console.log.apply(console, arguments);
+}
+
+// Create a mix of log messages from different source files
+function onload()
+{
+    for (var i = 0; i < 10; i++) {
+        if (i % 2 == 0)
+            log1(i); // from console-filter-test.html
+        else
+            log2(i); // from log-source.js
+    }
+
+    console.log(10);
+
+    runTest();
+}
+
+function test()
+{
+    var messagesElement = WebInspector.consoleView.messagesElement;
+    var groupMessages = messagesElement.querySelector(".console-group-messages");
+
+    function dumpVisibleMessages()
+    {
+        var children = groupMessages.childNodes;
+
+        for (var i = 0; i < children.length; i++)
+            InspectorTest.addResult(children[i].textContent);
+    }
+
+    var url1 = groupMessages.childNodes[0].message.url;
+    var url2 = groupMessages.childNodes[1].message.url;
+
+    InspectorTest.runTestSuite([
+        function beforeFilter(next)
+        {
+            InspectorTest.addResult(arguments.callee.name);
+            dumpVisibleMessages();
+            next();
+        },
+        function addURL1Filter(next)
+        {
+            WebInspector.consoleView._addMessageURLFilter(url1);
+            dumpVisibleMessages();
+            next();
+        },
+        function addURL2Filter(next)
+        {
+            WebInspector.consoleView._addMessageURLFilter(url2);
+            dumpVisibleMessages();
+            next();
+        },
+        function removeURL1Filter(next)
+        {
+            WebInspector.consoleView._removeMessageURLFilter(url1);
+            dumpVisibleMessages();
+            next();
+        },
+        function restoreURL1Filter(next)
+        {
+            WebInspector.consoleView._addMessageURLFilter(url1);
+            dumpVisibleMessages();
+            next();
+        },
+        function removeAllFilters(next)
+        {
+            WebInspector.consoleView._removeMessageURLFilter();
+            dumpVisibleMessages();
+            next();
+        }
+    ]);
+}
+
+</script>
+</head>
+
+<body onload="onload()">
+<p>
+    Tests that console can filter messages by source.
+</p>
+
+</body>
+</html>
diff --git a/LayoutTests/inspector/console/resources/log-source.js b/LayoutTests/inspector/console/resources/log-source.js
new file mode 100644 (file)
index 0000000..fdab177
--- /dev/null
@@ -0,0 +1,4 @@
+function log2()
+{
+    console.log.apply(console, arguments);
+}
\ No newline at end of file
index ca4e843..d0fbc65 100644 (file)
@@ -1,3 +1,36 @@
+2013-01-30  Dmitry Zvorygin  <zvorygin@chromium.org>
+
+        Web Inspector: Filters on Console panel
+        https://bugs.webkit.org/show_bug.cgi?id=107813
+
+        The problem is that third-party libraries may spam javascript console with internal
+        messages. Now there's filter context-menu option, which allows to hide/show messages
+        sent from specific scripts or urls.
+
+        Reviewed by Pavel Feldman.
+
+        * English.lproj/localizedStrings.js:
+        * inspector/front-end/ConsoleMessage.js:
+        (WebInspector.ConsoleMessageImpl.prototype.appendUndefined):
+        (WebInspector.ConsoleMessageImpl.prototype._printArray):
+        (WebInspector.ConsoleMessageImpl.prototype._highlightSearchResultsInElement):
+        * inspector/front-end/ConsolePanel.js:
+        (WebInspector.ConsolePanel.prototype.performSearch):
+        * inspector/front-end/ConsoleView.js:
+        (WebInspector.ConsoleView.get this):
+        (WebInspector.ConsoleView.prototype._consoleMessageAdded):
+        (WebInspector.ConsoleView.prototype._appendConsoleMessage):
+        (WebInspector.ConsoleView.prototype._consoleCleared):
+        (WebInspector.ConsoleView.prototype._handleContextMenuEvent.get var):
+        (WebInspector.ConsoleView.prototype._handleContextMenuEvent.set get contextMenu):
+        (WebInspector.ConsoleView.prototype._shouldBeVisible):
+        (WebInspector.ConsoleView.prototype._updateMessageList):
+        (WebInspector.ConsoleGroup.prototype.addMessage):
+        * inspector/front-end/ContextMenu.js:
+        (WebInspector.ContextMenuItem.prototype.isEnabled):
+        (WebInspector.ContextMenuItem.prototype.setEnabled):
+        * inspector/front-end/Settings.js:
+
 2013-01-20  Philippe Normand  <pnormand@igalia.com>
 
         [GStreamer] USE(NATIVE_FULLSCREEN_VIDEO) support
index e31b907..cc9b74e 100644 (file)
@@ -195,6 +195,7 @@ localizedStrings["Execute command"] = "Execute command";
 localizedStrings["Expand/collapse"] = "Expand/collapse";
 localizedStrings["Expires / Max-Age"] = "Expires / Max-Age";
 localizedStrings["File size"] = "File size";
+localizedStrings["Filter"] = "Filter";
 localizedStrings["Fit in window"] = "Fit in window";
 localizedStrings["Force Element State"] = "Force Element State";
 localizedStrings["Force element state"] = "Force element state";
@@ -223,6 +224,7 @@ localizedStrings["Heap snapshot profiles show memory distribution among your pag
 localizedStrings["Heavy (Bottom Up)"] = "Heavy (Bottom Up)";
 localizedStrings["Hex Colors"] = "Hex Colors";
 localizedStrings["Hide console."] = "Hide console.";
+localizedStrings["Hide messages from %s"] = "Hide messages from %s";
 localizedStrings["Image"] = "Image";
 localizedStrings["Images"] = "Images";
 localizedStrings["Increment by %f"] = "Increment by %f";
@@ -438,6 +440,7 @@ localizedStrings["Unknown property name."] = "Unknown property name.";
 localizedStrings["Use large resource rows."] = "Use large resource rows.";
 localizedStrings["Use small resource rows."] = "Use small resource rows.";
 localizedStrings["Used Heap Size"] = "Used Heap Size";
+localizedStrings["Unhide all"] = "Unhide all";
 localizedStrings["Value"] = "Value";
 localizedStrings["Waiting"] = "Waiting";
 localizedStrings["Warnings"] = "Warnings";
index 7c27ea7..f87ab34 100644 (file)
@@ -247,6 +247,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
     },
 
     /**
+     * @param {Object} output
      * @param {boolean=} forceObjectFormat
      * @param {boolean=} includePreview
      */
@@ -447,7 +448,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
         {
             if (index - lastNonEmptyIndex <= 1)
                 return;
-            var span = elem.createChild(span, "console-formatted-undefined");
+            var span = elem.createChild("span", "console-formatted-undefined");
             span.textContent = WebInspector.UIString("undefined × %d", index - lastNonEmptyIndex - 1);
         }
 
@@ -480,7 +481,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
     _formatWithSubstitutionString: function(parameters, formattedResult)
     {
-        var formatters = {}
+        var formatters = {};
 
         function parameterFormatter(force, obj)
         {
@@ -595,7 +596,6 @@ WebInspector.ConsoleMessageImpl.prototype = {
         regexObject.lastIndex = 0;
         var text = element.textContent;
         var match = regexObject.exec(text);
-        var offset = 0;
         var matchRanges = [];
         while (match) {
             matchRanges.push({ offset: match.index, length: match[0].length });
index c6e7c2b..b03ea50 100644 (file)
@@ -81,7 +81,7 @@ WebInspector.ConsolePanel.prototype = {
         this._searchRegex = createPlainTextSearchRegex(query, "gi");
 
         this._searchResults = [];
-        var messages = WebInspector.consoleView.messages;
+        var messages = WebInspector.console.messages;
         for (var i = 0; i < messages.length; i++) {
             if (messages[i].matchesRegex(this._searchRegex)) {
                 this._searchResults.push(messages[i]);
index 4b93da5..3f5b681 100644 (file)
@@ -37,7 +37,9 @@ WebInspector.ConsoleView = function(hideContextSelector)
     WebInspector.View.call(this);
 
     this.element.id = "console-view";
-    this.messages = [];
+    this._messageURLFilters = WebInspector.settings.messageURLFilters.get();
+    this._visibleMessages = [];
+    this._urlToMessageCount = {};
 
     this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear console log."), "clear-status-bar-item");
     this._clearConsoleButton.addEventListener("click", this._requestClearMessages, this);
@@ -381,39 +383,46 @@ WebInspector.ConsoleView.prototype = {
      */
     _consoleMessageAdded: function(event)
     {
-        this._appendConsoleMessage(event.data);
+        var message = /** @type {WebInspector.ConsoleMessage} */ (event.data);
+        if (this._urlToMessageCount[message.url])
+            this._urlToMessageCount[message.url]++;
+        else
+            this._urlToMessageCount[message.url] = 1;
+
+        if (this._shouldBeVisible(message))
+            this._appendConsoleMessage(message);
     },
 
-    _appendConsoleMessage: function(msg)
+    _appendConsoleMessage: function(message)
     {
         // this.messagesElement.isScrolledToBottom() is forcing style recalculation.
         // We just skip it if the scroll action has been scheduled.
-        if (!this._isScrollIntoViewScheduled() && ((msg instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom()))
+        if (!this._isScrollIntoViewScheduled() && ((message instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom()))
             this._scheduleScrollIntoView();
 
-        this.messages.push(msg);
+        this._visibleMessages.push(message);
 
-        if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
+        if (message.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
             var parentGroup = this.currentGroup.parentGroup
             if (parentGroup)
                 this.currentGroup = parentGroup;
         } else {
-            if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
+            if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
                 var group = new WebInspector.ConsoleGroup(this.currentGroup);
                 this.currentGroup.messagesElement.appendChild(group.element);
                 this.currentGroup = group;
             }
 
-            this.currentGroup.addMessage(msg);
+            this.currentGroup.addMessage(message);
         }
 
-        this.dispatchEventToListeners(WebInspector.ConsoleView.Events.EntryAdded, msg);
+        this.dispatchEventToListeners(WebInspector.ConsoleView.Events.EntryAdded, message);
     },
 
     _consoleCleared: function()
     {
         this._scrolledToBottom = true;
-        this.messages = [];
+        this._visibleMessages = [];
 
         this.currentGroup = this.topGroup;
         this.topGroup.messagesElement.removeChildren();
@@ -448,6 +457,28 @@ WebInspector.ConsoleView.prototype = {
         }
         contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Preserve log upon navigation" : "Preserve Log upon Navigation"), preserveLogItemAction.bind(this), WebInspector.settings.preserveConsoleLog.get());
 
+        var sourceElement = event.target.enclosingNodeOrSelfWithClass("console-message");
+
+        var filterSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Filter"));
+
+        if (sourceElement && sourceElement.message.url)
+            filterSubMenu.appendItem(WebInspector.UIString("Hide messages from %s", new WebInspector.ParsedURL(sourceElement.message.url).displayName), this._addMessageURLFilter.bind(this, sourceElement.message.url));
+
+        filterSubMenu.appendSeparator();
+        var unhideAll = filterSubMenu.appendItem(WebInspector.UIString("Unhide all"), this._removeMessageURLFilter.bind(this));
+        filterSubMenu.appendSeparator();
+
+        var hasFilters = false;
+        for (var url in this._messageURLFilters) {
+            if (this._messageURLFilters.hasOwnProperty(url)) {
+                filterSubMenu.appendCheckboxItem(String.sprintf("%s (%d)", new WebInspector.ParsedURL(url).displayName, this._urlToMessageCount[url]), this._removeMessageURLFilter.bind(this, url), true);
+                hasFilters = true;
+            }
+        }
+
+        filterSubMenu.setEnabled(hasFilters || (sourceElement && sourceElement.message.url));
+        unhideAll.setEnabled(hasFilters);
+
         contextMenu.appendSeparator();
         contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear console" : "Clear Console"), this._requestClearMessages.bind(this));
 
@@ -461,6 +492,72 @@ WebInspector.ConsoleView.prototype = {
         contextMenu.show();
     },
 
+    /**
+     * @param {string} url
+     * @private
+     */
+    _addMessageURLFilter: function(url)
+    {
+        this._messageURLFilters[url] = true;
+        WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
+        this._updateMessageList();
+    },
+
+    /**
+     * @param {string} url
+     * @private
+     */
+    _removeMessageURLFilter: function(url)
+    {
+        if (!url)
+            this._messageURLFilters = {};
+        else
+            delete this._messageURLFilters[url];
+
+        WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
+
+        this._updateMessageList();
+    },
+
+    /**
+     * @param {WebInspector.ConsoleMessage} message
+     * @return {boolean}
+     * @private
+     */
+    _shouldBeVisible: function(message)
+    {
+        return !message.url || !this._messageURLFilters[message.url];
+    },
+
+    /**
+     * @private
+     */
+    _updateMessageList: function()
+    {
+        var sourceMessages = WebInspector.console.messages;
+        var visibleMessageIndex = 0;
+        var newVisibleMessages = [];
+        for (var i = 0; i < sourceMessages.length; i++) {
+            var sourceMessage = sourceMessages[i];
+            var visibleMessage = this._visibleMessages[visibleMessageIndex];
+
+            if (visibleMessage === sourceMessage) {
+                visibleMessageIndex++;
+                if (this._shouldBeVisible(visibleMessage))
+                    newVisibleMessages.push(visibleMessage);
+                else
+                    visibleMessage.toMessageElement().removeSelf();
+            } else {
+                if (this._shouldBeVisible(sourceMessage)) {
+                    this.currentGroup.addMessage(sourceMessage, visibleMessage ? visibleMessage.toMessageElement() : null);
+                    newVisibleMessages.push(sourceMessage);
+                }
+            }
+        }
+
+        this._visibleMessages = newVisibleMessages;
+    },
+
     _monitoringXHREnabledSettingChanged: function(event)
     {
         ConsoleAgent.setMonitoringXHREnabled(event.data);
@@ -708,20 +805,24 @@ WebInspector.ConsoleGroup = function(parentGroup)
 }
 
 WebInspector.ConsoleGroup.prototype = {
-    addMessage: function(msg)
+    /**
+     * @param {WebInspector.ConsoleMessage} message
+     * @param {Node=} node
+     */
+    addMessage: function(message, node)
     {
-        var element = msg.toMessageElement();
+        var element = message.toMessageElement();
 
-        if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
+        if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
             this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
             element.addEventListener("click", this._titleClicked.bind(this), false);
             var groupElement = element.enclosingNodeOrSelfWithClass("console-group");
-            if (groupElement && msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
+            if (groupElement && message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
                 groupElement.addStyleClass("collapsed");
         } else
-            this.messagesElement.appendChild(element);
+            this.messagesElement.insertBefore(element, node);
 
-        if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand)
+        if (element.previousSibling && message.originatingCommand && element.previousSibling.command === message.originatingCommand)
             element.previousSibling.addStyleClass("console-adjacent-user-command-result");
     },
 
index 98e1f44..1f04771 100644 (file)
@@ -58,6 +58,22 @@ WebInspector.ContextMenuItem.prototype = {
         return this._type;
     },
 
+    /**
+     * @return {boolean}
+     */
+    isEnabled: function()
+    {
+        return !this._disabled;
+    },
+
+    /**
+     * @param {boolean} enabled
+     */
+    setEnabled: function(enabled)
+    {
+        this._disabled = !enabled;
+    },
+
     _buildDescriptor: function()
     {
         switch (this._type) {
@@ -86,7 +102,10 @@ WebInspector.ContextSubMenuItem = function(topLevelMenu, label, disabled)
 
 WebInspector.ContextSubMenuItem.prototype = {
     /**
+     * @param {string} label
+     * @param {function} handler
      * @param {boolean=} disabled
+     * @return {WebInspector.ContextMenuItem}
      */
     appendItem: function(label, handler, disabled)
     {
@@ -96,6 +115,11 @@ WebInspector.ContextSubMenuItem.prototype = {
         return item;
     },
 
+    /**
+     * @param {string} label
+     * @param {boolean=} disabled
+     * @return {WebInspector.ContextMenuItem}
+     */
     appendSubMenuItem: function(label, disabled)
     {
         var item = new WebInspector.ContextSubMenuItem(this._contextMenu, label, disabled);
index a7d5685..cebd99a 100644 (file)
@@ -121,6 +121,7 @@ WebInspector.Settings = function()
     this.showToolbarIcons = this.createSetting("showToolbarIcons", false);
     this.workerInspectorWidth = this.createSetting("workerInspectorWidth", 600);
     this.workerInspectorHeight = this.createSetting("workerInspectorHeight", 600);
+    this.messageURLFilters = this.createSetting("messageURLFilters", {});
 
     // If there are too many breakpoints in a storage, it is likely due to a recent bug that caused
     // periodical breakpoints duplication leading to inspector slowness.