Title: [223065] trunk/Source/WebInspectorUI
Revision
223065
Author
[email protected]
Date
2017-10-09 13:38:09 -0700 (Mon, 09 Oct 2017)

Log Message

Web Inspector: Network Tab - Filter resources based on URL / Text Content
https://bugs.webkit.org/show_bug.cgi?id=178071
<rdar://problem/34071562>

Reviewed by Brian Burg.

* Localizations/en.lproj/localizedStrings.js:
New strings.

* UserInterface/Views/FilterBar.css:
(.filter-bar.active > input[type="search"]::-webkit-search-decoration):
(.filter-bar.indicating-progress > input[type="search"]::-webkit-search-decoration):
New icon for progress / active states.

* UserInterface/Views/FilterBar.js:
(WI.FilterBar.prototype.get inputField):
(WI.FilterBar.prototype.get placeholder):
(WI.FilterBar.prototype.set placeholder):
(WI.FilterBar.prototype.get incremental):
(WI.FilterBar.prototype.set incremental):
(WI.FilterBar.prototype.get indicatingProgress):
(WI.FilterBar.prototype.set indicatingProgress):
(WI.FilterBar.prototype.get indicatingActive):
(WI.FilterBar.prototype.set indicatingActive):
(WI.FilterBar.prototype._handleFilterInputEvent):
When incremental is set to false on the FilterBar still dispatch an
event when the textfield clears.

* UserInterface/Images/FilterFieldActiveGlyph.svg: Added.
* UserInterface/Images/gtk/FilterFieldActiveGlyph.svg: Added.
New blue icon for active state.

* UserInterface/Controllers/FrameResourceManager.js:
(WI.FrameResourceManager.prototype.resourceForIdentifier):
Accessor for arbitrary resource.

* UserInterface/Views/NetworkTableContentView.css:
(.content-view.network .navigation-bar .filter-bar):
(.content-view.network .warning-banner):
(body[dir=ltr] .content-view.network .warning-banner):
(body[dir=rtl] .content-view.network .warning-banner):
(.content-view.network .warning-banner > a):
Warning banner when the filter produces no results. This matches the
warning in the Debugger tab when breakpoints are disabled.

* UserInterface/Views/ScopeBar.js:
(WI.ScopeBar.prototype.resetToDefault):
Provide a way to easily reset a scope bar to the default item.

* UserInterface/Views/RadioButtonNavigationItem.css:
(.navigation-bar .item.radio.button.text-only:active):
* UserInterface/Views/ScopeBar.css:
(.scope-bar > li:active):
Cleanup some styles that should be using a variable.

* UserInterface/Views/NetworkTableContentView.js:
(WI.NetworkTableContentView):
(WI.NetworkTableContentView.prototype.get filterNavigationItems):
(WI.NetworkTableContentView.prototype.layout):
(WI.NetworkTableContentView.prototype._processPendingEntries):
(WI.NetworkTableContentView.prototype._checkTextFilterAgainstFinishedResource):
(WI.NetworkTableContentView.prototype._checkTextFilterAgainstFailedResource):
(WI.NetworkTableContentView.prototype._updateTextFilterActiveIndicator):
(WI.NetworkTableContentView.prototype._updateEmptyFilterResultsWarning):
(WI.NetworkTableContentView.prototype._showEmptyFilterResultsWarning):
(WI.NetworkTableContentView.prototype._hideEmptyFilterResultsWarning):
(WI.NetworkTableContentView.prototype._positionEmptyFilterMessage):
(WI.NetworkTableContentView.prototype._resourceLoadingDidFinish):
(WI.NetworkTableContentView.prototype._resourceLoadingDidFail):
(WI.NetworkTableContentView.prototype._networkTimelineRecordAdded):
(WI.NetworkTableContentView.prototype._insertResourceAndReloadTable):
(WI.NetworkTableContentView.prototype._hasTypeFilter):
(WI.NetworkTableContentView.prototype._hasTextFilter):
(WI.NetworkTableContentView.prototype._hasActiveFilter):
(WI.NetworkTableContentView.prototype._passTypeFilter):
(WI.NetworkTableContentView.prototype._passTextFilter):
(WI.NetworkTableContentView.prototype._passFilter):
(WI.NetworkTableContentView.prototype._updateFilteredEntries):
(WI.NetworkTableContentView.prototype._resetFilters):
(WI.NetworkTableContentView.prototype._textFilterDidChange):
(WI.NetworkTableContentView.prototype._tableNameColumnDidChangeWidth):
There are now two filters.

  - FilterBar - Filters URL and Full Text Content
  - ScopeBar  - Filters Resource Type

The text content filter is asynchronous. We reuse the existing Search
functionality when filtering on text. We need to defer text content
filtering until the resource finishes loading.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (223064 => 223065)


--- trunk/Source/WebInspectorUI/ChangeLog	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/ChangeLog	2017-10-09 20:38:09 UTC (rev 223065)
@@ -1,5 +1,97 @@
 2017-10-09  Joseph Pecoraro  <[email protected]>
 
+        Web Inspector: Network Tab - Filter resources based on URL / Text Content
+        https://bugs.webkit.org/show_bug.cgi?id=178071
+        <rdar://problem/34071562>
+
+        Reviewed by Brian Burg.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        New strings.
+
+        * UserInterface/Views/FilterBar.css:
+        (.filter-bar.active > input[type="search"]::-webkit-search-decoration):
+        (.filter-bar.indicating-progress > input[type="search"]::-webkit-search-decoration):
+        New icon for progress / active states.
+
+        * UserInterface/Views/FilterBar.js:
+        (WI.FilterBar.prototype.get inputField):
+        (WI.FilterBar.prototype.get placeholder):
+        (WI.FilterBar.prototype.set placeholder):
+        (WI.FilterBar.prototype.get incremental):
+        (WI.FilterBar.prototype.set incremental):
+        (WI.FilterBar.prototype.get indicatingProgress):
+        (WI.FilterBar.prototype.set indicatingProgress):
+        (WI.FilterBar.prototype.get indicatingActive):
+        (WI.FilterBar.prototype.set indicatingActive):
+        (WI.FilterBar.prototype._handleFilterInputEvent):
+        When incremental is set to false on the FilterBar still dispatch an
+        event when the textfield clears.
+
+        * UserInterface/Images/FilterFieldActiveGlyph.svg: Added.
+        * UserInterface/Images/gtk/FilterFieldActiveGlyph.svg: Added.
+        New blue icon for active state.
+
+        * UserInterface/Controllers/FrameResourceManager.js:
+        (WI.FrameResourceManager.prototype.resourceForIdentifier):
+        Accessor for arbitrary resource.
+
+        * UserInterface/Views/NetworkTableContentView.css:
+        (.content-view.network .navigation-bar .filter-bar):
+        (.content-view.network .warning-banner):
+        (body[dir=ltr] .content-view.network .warning-banner):
+        (body[dir=rtl] .content-view.network .warning-banner):
+        (.content-view.network .warning-banner > a):
+        Warning banner when the filter produces no results. This matches the
+        warning in the Debugger tab when breakpoints are disabled.
+
+        * UserInterface/Views/ScopeBar.js:
+        (WI.ScopeBar.prototype.resetToDefault):
+        Provide a way to easily reset a scope bar to the default item.
+
+        * UserInterface/Views/RadioButtonNavigationItem.css:
+        (.navigation-bar .item.radio.button.text-only:active):
+        * UserInterface/Views/ScopeBar.css:
+        (.scope-bar > li:active):
+        Cleanup some styles that should be using a variable.
+
+        * UserInterface/Views/NetworkTableContentView.js:
+        (WI.NetworkTableContentView):
+        (WI.NetworkTableContentView.prototype.get filterNavigationItems):
+        (WI.NetworkTableContentView.prototype.layout):
+        (WI.NetworkTableContentView.prototype._processPendingEntries):
+        (WI.NetworkTableContentView.prototype._checkTextFilterAgainstFinishedResource):
+        (WI.NetworkTableContentView.prototype._checkTextFilterAgainstFailedResource):
+        (WI.NetworkTableContentView.prototype._updateTextFilterActiveIndicator):
+        (WI.NetworkTableContentView.prototype._updateEmptyFilterResultsWarning):
+        (WI.NetworkTableContentView.prototype._showEmptyFilterResultsWarning):
+        (WI.NetworkTableContentView.prototype._hideEmptyFilterResultsWarning):
+        (WI.NetworkTableContentView.prototype._positionEmptyFilterMessage):
+        (WI.NetworkTableContentView.prototype._resourceLoadingDidFinish):
+        (WI.NetworkTableContentView.prototype._resourceLoadingDidFail):
+        (WI.NetworkTableContentView.prototype._networkTimelineRecordAdded):
+        (WI.NetworkTableContentView.prototype._insertResourceAndReloadTable):
+        (WI.NetworkTableContentView.prototype._hasTypeFilter):
+        (WI.NetworkTableContentView.prototype._hasTextFilter):
+        (WI.NetworkTableContentView.prototype._hasActiveFilter):
+        (WI.NetworkTableContentView.prototype._passTypeFilter):
+        (WI.NetworkTableContentView.prototype._passTextFilter):
+        (WI.NetworkTableContentView.prototype._passFilter):
+        (WI.NetworkTableContentView.prototype._updateFilteredEntries):
+        (WI.NetworkTableContentView.prototype._resetFilters):
+        (WI.NetworkTableContentView.prototype._textFilterDidChange):
+        (WI.NetworkTableContentView.prototype._tableNameColumnDidChangeWidth):
+        There are now two filters.
+
+          - FilterBar - Filters URL and Full Text Content
+          - ScopeBar  - Filters Resource Type
+
+        The text content filter is asynchronous. We reuse the existing Search
+        functionality when filtering on text. We need to defer text content
+        filtering until the resource finishes loading.
+
+2017-10-09  Joseph Pecoraro  <[email protected]>
+
         Web Inspector: Network Tab: Row wrapping (waterfall displaying behind next row's name)
         https://bugs.webkit.org/show_bug.cgi?id=178015
         <rdar://problem/34858720>

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (223064 => 223065)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2017-10-09 20:38:09 UTC (rev 223065)
@@ -181,6 +181,7 @@
 localizedStrings["Clear Log"] = "Clear Log";
 localizedStrings["Clear Network Items (%s)"] = "Clear Network Items (%s)";
 localizedStrings["Clear Timeline (%s)"] = "Clear Timeline (%s)";
+localizedStrings["Clear filters"] = "Clear filters";
 localizedStrings["Clear focus"] = "Clear focus";
 localizedStrings["Clear log (%s or %s)"] = "Clear log (%s or %s)";
 localizedStrings["Clear modified properties"] = "Clear modified properties";
@@ -403,6 +404,7 @@
 localizedStrings["Fill"] = "Fill";
 localizedStrings["Fill Mode"] = "Fill Mode";
 localizedStrings["Filter"] = "Filter";
+localizedStrings["Filter Full URL and Text"] = "Filter Full URL and Text";
 localizedStrings["Flexbox"] = "Flexbox";
 localizedStrings["Float"] = "Float";
 localizedStrings["Float and Clear"] = "Float and Clear";

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js	2017-10-09 20:38:09 UTC (rev 223065)
@@ -65,6 +65,11 @@
         return this._frameIdentifierMap.get(frameId) || null;
     }
 
+    resourceForRequestIdentifier(requestIdentifier)
+    {
+        return this._resourceRequestIdentifierMap.get(requestIdentifier) || null;
+    }
+
     frameDidNavigate(framePayload)
     {
         // Called from WI.PageObserver.

Added: trunk/Source/WebInspectorUI/UserInterface/Images/FilterFieldActiveGlyph.svg (0 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Images/FilterFieldActiveGlyph.svg	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Images/FilterFieldActiveGlyph.svg	2017-10-09 20:38:09 UTC (rev 223065)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2017 Apple Inc. All rights reserved. -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 13 13">
+    <g transform="translate(0.5, 0.5)" stroke="hsl(212, 92%, 54%)" stroke-width="1" fill="none">
+        <circle cx="6" cy="6" r="6"/>
+        <path d="M3 4 L 9 4" stroke-linecap="square"/>
+        <path d="M4 6 L 8 6" stroke-linecap="square"/>
+        <path d="M5 8 L 7 8" stroke-linecap="square"/>
+    </g>
+</svg>

Added: trunk/Source/WebInspectorUI/UserInterface/Images/gtk/FilterFieldActiveGlyph.svg (0 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Images/gtk/FilterFieldActiveGlyph.svg	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Images/gtk/FilterFieldActiveGlyph.svg	2017-10-09 20:38:09 UTC (rev 223065)
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Licensed under the Creative Commons Attribution-Share Alike 3.0 United States License (http://creativecommons.org/licenses/by-sa/3.0/) -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 13 13">
+ <path fill="hsl(212, 92%, 54%)" d="m1.5 1.3273v0.71875 0.0625c-0.001 0.13652 0.0388 0.2562 0.125 0.375l4 5.4687c0.062145 0.08767 0.14938 0.16242 0.25 0.21875v2.5016 1l1.25-1v-2.5016c0.1006-0.0563 0.1879-0.131 0.25-0.2187l4-5.4687c0.08625-0.1188 0.12631-0.23848 0.125-0.375v-0.0625-0.71875z"/>
+</svg>

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.css (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.css	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.css	2017-10-09 20:38:09 UTC (rev 223065)
@@ -90,3 +90,18 @@
 
     -webkit-appearance: none;
 }
+
+.filter-bar.active > input[type="search"]::-webkit-search-decoration {
+    background-image: url(../Images/FilterFieldActiveGlyph.svg);
+}
+
+.filter-bar.indicating-progress > input[type="search"]::-webkit-search-decoration {
+    background-image: url(../Images/IndeterminateProgressSpinner1.svg);
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+
+    animation-name: discrete-spinner;
+    animation-duration: 1s;
+    animation-iteration-count: infinite;
+    animation-timing-function: step-start;
+}

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.js (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.js	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/FilterBar.js	2017-10-09 20:38:09 UTC (rev 223065)
@@ -42,7 +42,8 @@
         this._inputField.placeholder = WI.UIString("Filter");
         this._inputField.spellcheck = false;
         this._inputField.incremental = true;
-        this._inputField.addEventListener("search", this._handleFilterChanged.bind(this), false);
+        this._inputField.addEventListener("search", this._handleFilterChanged.bind(this));
+        this._inputField.addEventListener("input", this._handleFilterInputEvent.bind(this));
         this._element.appendChild(this._inputField);
 
         this._lastFilterValue = this.filters;
@@ -55,21 +56,31 @@
         return this._element;
     }
 
+    get inputField()
+    {
+        return this._inputField;
+    }
+
     get placeholder()
     {
-        return this._inputField.getAttribute("placeholder");
+        return this._inputField.placeholder;
     }
 
     set placeholder(text)
     {
-        this._inputField.setAttribute("placeholder", text);
+        this._inputField.placeholder = text;
     }
 
-    get inputField()
+    get incremental()
     {
-        return this._inputField;
+        return this._inputField.incremental;
     }
 
+    set incremental(incremental)
+    {
+        this._inputField.incremental = incremental;
+    }
+
     get filters()
     {
         return {text: this._inputField.value, functions: [...this._filterFunctionsMap.values()]};
@@ -85,6 +96,33 @@
             this._handleFilterChanged();
     }
 
+    get indicatingProgress()
+    {
+        return this._element.classList.contains("indicating-progress");
+    }
+
+    set indicatingProgress(progress)
+    {
+        this._element.classList.toggle("indicating-progress", !!progress);
+    }
+
+    get indicatingActive()
+    {
+        return this._element.classList.contains("active");
+    }
+
+    set indicatingActive(active)
+    {
+        this._element.classList.toggle("active", !!active);
+    }
+
+    clear()
+    {
+        this._inputField.value = "";
+        this._inputField.value = null; // Get the placeholder to show again.
+        this._lastFilterValue = this.filters;
+    }
+
     addFilterBarButton(identifier, filterFunction, activatedByDefault, defaultToolTip, activatedToolTip, image, imageWidth, imageHeight)
     {
         var filterBarButton = new WI.FilterBarButton(identifier, filterFunction, activatedByDefault, defaultToolTip, activatedToolTip, image, imageWidth, imageHeight);
@@ -142,6 +180,17 @@
             this.dispatchEventToListeners(WI.FilterBar.Event.FilterDidChange);
         }
     }
+
+    _handleFilterInputEvent(event)
+    {
+        // When not incremental we still want to detect if the field becomes empty.
+
+        if (this.incremental)
+            return;
+
+        if (!this._inputField.value)
+            this._handleFilterChanged();
+    }
 };
 
 WI.FilterBar.Event = {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css	2017-10-09 20:38:09 UTC (rev 223065)
@@ -23,6 +23,10 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+.content-view.network .navigation-bar .filter-bar {
+    background: none;
+}
+
 .content-view.network .network-table .icon {
     position: relative;
     width: 16px;
@@ -71,3 +75,38 @@
 .network-table :not(.header) .cell:first-of-type {
     background: rgba(0, 0, 0, 0.07);
 }
+
+.content-view.network .empty-content-placeholder {
+    position: absolute;
+    top: var(--navigation-bar-height);
+    bottom: 0;
+    padding: 0;
+    padding-top: 15px;
+    padding-bottom: 15px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+    background: var(--odd-zebra-stripe-row-background-color);
+    --empty-content-placeholder-start: 0;
+}
+
+body[dir=ltr] .content-view.network .empty-content-placeholder {
+    left: var(--empty-content-placeholder-start);
+}
+
+body[dir=rtl] .content-view.network .empty-content-placeholder {
+    right: var(--empty-content-placeholder-start);
+}
+
+.content-view.network .empty-content-placeholder > .message {
+    display: inline-block;
+    white-space: nowrap;
+
+    font-size: var(--sidebar-no-results-message-font-size);
+    color: var(--text-color-gray-medium);
+
+    padding: 5px 15px 6px;
+    line-height: 25px;
+    text-align: center;
+}

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js	2017-10-09 20:38:09 UTC (rev 223065)
@@ -34,6 +34,7 @@
         this._filteredEntries = [];
         this._pendingInsertions = [];
         this._pendingUpdates = [];
+        this._pendingFilter = false;
 
         this._table = null;
         this._nameColumnWidthSetting = new WI.Setting("network-table-content-view-name-column-width", 250);
@@ -43,7 +44,6 @@
         this._resourceDetailViewMap = new Map;
 
         // FIXME: Network Timeline.
-        // FIXME: Filter text field.
         // FIXME: Throttling.
         // FIXME: HAR Export.
 
@@ -70,8 +70,20 @@
         this._typeFilterScopeBar = new WI.ScopeBar("network-type-filter-scope-bar", typeFilterScopeBarItems, typeFilterScopeBarItems[0]);
         this._typeFilterScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._typeFilterScopeBarSelectionChanged, this);
 
+        this._textFilterSearchId = 0;
+        this._textFilterSearchText = null;
+        this._textFilterIsActive = false;
+
+        this._textFilterNavigationItem = new WI.FilterBarNavigationItem;
+        this._textFilterNavigationItem.filterBar.incremental = false;
+        this._textFilterNavigationItem.filterBar.addEventListener(WI.FilterBar.Event.FilterDidChange, this._textFilterDidChange, this);
+        this._textFilterNavigationItem.filterBar.placeholder = WI.UIString("Filter Full URL and Text");
+
         this._activeTypeFilters = this._generateTypeFilter();
+        this._activeTextFilterResources = new Set;
 
+        this._emptyFilterResultsMessageElement = null;
+
         // COMPATIBILITY (iOS 10.3): Network.setDisableResourceCaching did not exist.
         if (window.NetworkAgent && NetworkAgent.setResourceCachingDisabled) {
             let toolTipForDisableResourceCache = WI.UIString("Ignore the resource cache when loading resources");
@@ -142,7 +154,11 @@
 
     get filterNavigationItems()
     {
-        return [this._typeFilterScopeBar];
+        let items = [];
+        if (window.PageAgent)
+            items.push(this._textFilterNavigationItem);
+        items.push(this._typeFilterScopeBar);
+        return items;
     }
 
     shown()
@@ -581,6 +597,7 @@
     {
         this._processPendingEntries();
         this._positionDetailView();
+        this._positionEmptyFilterMessage();
     }
 
     handleClearShortcut(event)
@@ -593,9 +610,10 @@
     _processPendingEntries()
     {
         let needsSort = this._pendingUpdates.length > 0;
+        let needsFilter = this._pendingFilter;
 
-        // No global sort is needed, so just insert new records into their sorted position.
-        if (!needsSort) {
+        // No global sort or filter is needed, so just insert new records into their sorted position.
+        if (!needsSort && !needsFilter) {
             let originalLength = this._pendingInsertions.length;
             for (let resource of this._pendingInsertions)
                 this._insertResourceAndReloadTable(resource);
@@ -612,10 +630,49 @@
             this._updateEntryForResource(resource);
         this._pendingUpdates = [];
 
+        this._pendingFilter = false;
+
         this._updateSortAndFilteredEntries();
         this._table.reloadData();
     }
 
+    _checkTextFilterAgainstFinishedResource(resource)
+    {
+        let frame = resource.parentFrame;
+        if (!frame)
+            return;
+
+        let searchQuery = this._textFilterSearchText;
+        if (resource.url.includes(searchQuery)) {
+            this._activeTextFilterResources.add(resource);
+            return;
+        }
+
+        let searchId = this._textFilterSearchId;
+
+        const isCaseSensitive = true;
+        const isRegex = false;
+        PageAgent.searchInResource(frame.id, resource.url, searchQuery, isCaseSensitive, isRegex, resource.requestIdentifier, (error, searchResults) => {
+            if (searchId !== this._textFilterSearchId)
+                return;
+
+            if (error || !searchResults || !searchResults.length)
+                return;
+
+            this._activeTextFilterResources.add(resource);
+
+            this._pendingFilter = true;
+            this.needsLayout();
+        });
+    }
+
+    _checkTextFilterAgainstFailedResource(resource)
+    {
+        let searchQuery = this._textFilterSearchText;
+        if (resource.url.includes(searchQuery))
+            this._activeTextFilterResources.add(resource);
+    }
+
     _rowIndexForResource(resource)
     {
         return this._filteredEntries.findIndex((x) => x.resource === resource);
@@ -689,6 +746,56 @@
         this._table.scrollContainer.style.width = this._nameColumn.width + "px";
     }
 
+    _updateTextFilterActiveIndicator()
+    {
+        this._textFilterNavigationItem.filterBar.indicatingActive = this._hasTextFilter();
+    }
+
+    _updateEmptyFilterResultsMessage()
+    {
+        if (this._hasActiveFilter() && !this._filteredEntries.length)
+            this._showEmptyFilterResultsMessage();
+        else
+            this._hideEmptyFilterResultsMessage();
+    }
+
+    _showEmptyFilterResultsMessage()
+    {
+        if (!this._emptyFilterResultsMessageElement) {
+            let message = WI.UIString("No Filter Results");
+            let buttonElement = document.createElement("button");
+            buttonElement.textContent = WI.UIString("Clear filters");
+            buttonElement.addEventListener("click", () => { this._resetFilters(); });
+
+            this._emptyFilterResultsMessageElement = document.createElement("div");
+            this._emptyFilterResultsMessageElement.className = "empty-content-placeholder";
+
+            let messageElement = this._emptyFilterResultsMessageElement.appendChild(document.createElement("div"));
+            messageElement.className = "message";
+            messageElement.append(message, document.createElement("br"), buttonElement);
+        }
+
+        this.element.appendChild(this._emptyFilterResultsMessageElement);
+        this._positionEmptyFilterMessage();
+    }
+
+    _hideEmptyFilterResultsMessage()
+    {
+        if (!this._emptyFilterResultsMessageElement)
+            return;
+
+        this._emptyFilterResultsMessageElement.remove();
+    }
+
+    _positionEmptyFilterMessage()
+    {
+        if (!this._emptyFilterResultsMessageElement)
+            return;
+
+        let width = this._nameColumn.width - 1; // For the 1px border.
+        this._emptyFilterResultsMessageElement.style.width = width + "px";
+    }
+
     _resourceCachingDisabledSettingChanged()
     {
         this._disableResourceCacheNavigationItem.activated = WI.resourceCachingDisabledSetting.value;
@@ -714,6 +821,10 @@
     {
         let resource = event.target;
         this._pendingUpdates.push(resource);
+
+        if (this._hasTextFilter())
+            this._checkTextFilterAgainstFinishedResource(resource);
+
         this.needsLayout();
     }
 
@@ -721,6 +832,10 @@
     {
         let resource = event.target;
         this._pendingUpdates.push(resource);
+
+        if (this._hasTextFilter())
+            this._checkTextFilterAgainstFailedResource(resource);
+
         this.needsLayout();
     }
 
@@ -758,7 +873,7 @@
         console.assert(resourceTimelineRecord instanceof WI.ResourceTimelineRecord);
 
         let resource = resourceTimelineRecord.resource;
-        this._insertResourceAndReloadTable(resource)
+        this._insertResourceAndReloadTable(resource);
     }
 
     _isDefaultSort()
@@ -770,6 +885,7 @@
     {
         if (!(WI.tabBrowser.selectedTabContentView instanceof WI.NetworkTabContentView)) {
             this._pendingInsertions.push(resource);
+            this.needsLayout();
             return;
         }
 
@@ -845,14 +961,42 @@
         };
     }
 
-    _passFilter(entry)
+    _hasTypeFilter()
     {
-        if (!this._activeTypeFilters)
+        return !!this._activeTypeFilters;
+    }
+
+    _hasTextFilter()
+    {
+        return this._textFilterIsActive;
+    }
+
+    _hasActiveFilter()
+    {
+        return this._hasTypeFilter()
+            || this._hasTextFilter();
+    }
+
+    _passTypeFilter(entry)
+    {
+        if (!this._hasTypeFilter())
             return true;
-
         return this._activeTypeFilters.some((checker) => checker(entry.resource.type));
     }
 
+    _passTextFilter(entry)
+    {
+        if (!this._hasTextFilter())
+            return true;
+        return this._activeTextFilterResources.has(entry.resource);
+    }
+
+    _passFilter(entry)
+    {
+        return this._passTypeFilter(entry)
+            && this._passTextFilter(entry);
+    }
+
     _updateSortAndFilteredEntries()
     {
         this._entries = this._entries.sort(this._entriesSortComparator);
@@ -861,12 +1005,15 @@
 
     _updateFilteredEntries()
     {
-        if (this._activeTypeFilters)
+        if (this._hasActiveFilter())
             this._filteredEntries = this._entries.filter(this._passFilter, this);
         else
             this._filteredEntries = this._entries.slice();
 
         this._restoreSelectedRow();
+
+        this._updateTextFilterActiveIndicator();
+        this._updateEmptyFilterResultsMessage();
     }
 
     _generateTypeFilter()
@@ -878,6 +1025,29 @@
         return selectedItems.map((item) => item.__checker);
     }
 
+    _resetFilters()
+    {
+        console.assert(this._hasActiveFilter());
+
+        // Clear text filter.
+        this._textFilterSearchId++;
+        this._textFilterNavigationItem.filterBar.indicatingProgress = false;
+        this._textFilterSearchText = null;
+        this._textFilterIsActive = false;
+        this._activeTextFilterResources.clear();
+        this._textFilterNavigationItem.filterBar.clear();
+        console.assert(!this._hasTextFilter());
+
+        // Clear type filter.
+        this._typeFilterScopeBar.resetToDefault();
+        console.assert(!this._hasTypeFilter());
+
+        console.assert(!this._hasActiveFilter());
+
+        this._updateFilteredEntries();
+        this._table.reloadData();
+    }
+
     _areFilterListsIdentical(listA, listB)
     {
         if (listA && listB) {
@@ -912,6 +1082,89 @@
         this._table.reloadData();
     }
 
+    _textFilterDidChange(event)
+    {
+        let searchQuery = this._textFilterNavigationItem.filterBar.filters.text;
+        if (searchQuery === this._textFilterSearchText)
+            return;
+
+        // Even if the selected resource would still be visible, lets close the detail view if a filter changes.
+        this._hideResourceDetailView();
+
+        let searchId = ++this._textFilterSearchId;
+
+        // Search cleared.
+        if (!searchQuery) {
+            this._textFilterNavigationItem.filterBar.indicatingProgress = false;
+            this._textFilterSearchText = null;
+            this._textFilterIsActive = false;
+            this._activeTextFilterResources.clear();
+
+            this._updateFilteredEntries();
+            this._table.reloadData();
+            return;
+        }
+
+        this._textFilterSearchText = searchQuery;
+        this._textFilterNavigationItem.filterBar.indicatingProgress = true;
+
+        // NetworkTable text filter currently searches:
+        //   - Resource URL
+        //   - Resource Text Content
+        // It does not search all the content in the table (like mimeType, headers, etc).
+        // For those we should provide more custom filters.
+
+        const isCaseSensitive = true;
+        const isRegex = false;
+        PageAgent.searchInResources(searchQuery, isCaseSensitive, isRegex, (error, searchResults) => {
+            if (searchId !== this._textFilterSearchId)
+                return;
+
+            this._textFilterIsActive = true;
+            this._activeTextFilterResources.clear();
+            this._textFilterNavigationItem.filterBar.indicatingProgress = false;
+
+            // Add resources based on URL.
+            for (let entry of this._entries) {
+                let resource = entry.resource;
+                if (resource.url.includes(searchQuery))
+                    this._activeTextFilterResources.add(resource);
+            }
+
+            // Add resources based on content.
+            if (!error) {
+                for (let {url, frameId, requestId} of searchResults) {
+                    if (requestId) {
+                        let resource = WI.frameResourceManager.resourceForRequestIdentifier(requestId);
+                        if (resource) {
+                            this._activeTextFilterResources.add(resource);
+                            continue;
+                        }
+                    }
+
+                    if (frameId && url) {
+                        let frame = WI.frameResourceManager.frameForIdentifier(frameId);
+                        if (frame) {
+                            if (frame.mainResource.url ="" url) {
+                                this._activeTextFilterResources.add(frame.mainResource);
+                                continue;
+                            }
+                            let resource = frame.resourceForURL(url);
+                            if (resource) {
+                                this._activeTextFilterResources.add(resource);
+                                continue;
+                            }
+                        }
+                    }
+                }
+            }
+
+            // Apply.
+            this._updateFilteredEntries();
+            this._table.reloadData();
+        });
+    }
+
     _restoreSelectedRow()
     {
         if (!this._selectedResource)
@@ -932,5 +1185,6 @@
         this._nameColumnWidthSetting.value = event.target.width;
 
         this._positionDetailView();
+        this._positionEmptyFilterMessage();
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.css (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.css	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.css	2017-10-09 20:38:09 UTC (rev 223065)
@@ -43,7 +43,7 @@
 
 .navigation-bar .item.radio.button.text-only:active {
     color: var(--selected-foreground-color);
-    background-color: hsla(212, 92%, 54%, 0.55);
+    background-color: var(--selected-background-color-active);
 }
 
 .navigation-bar .item.radio.button.text-only.selected:active {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.css (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.css	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.css	2017-10-09 20:38:09 UTC (rev 223065)
@@ -109,7 +109,7 @@
 
 .scope-bar > li:active {
     color: var(--selected-foreground-color);
-    background-color: hsla(212, 92%, 54%, 0.55);
+    background-color: var(--selected-background-color-active);
 }
 
 .scope-bar > li.selected:active {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.js (223064 => 223065)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.js	2017-10-09 20:23:32 UTC (rev 223064)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScopeBar.js	2017-10-09 20:38:09 UTC (rev 223065)
@@ -89,6 +89,19 @@
         return this._items.some((item) => item.selected && item !== this._defaultItem);
     }
 
+    resetToDefault()
+    {
+        let selectedItems = this.selectedItems;
+        if (selectedItems.length === 1 && selectedItems[0] === this._defaultItem)
+            return;
+
+        for (let item of this._items)
+            item.selected = false;
+        this._defaultItem.selected = true;
+
+        this.dispatchEventToListeners(WI.ScopeBar.Event.SelectionChanged);
+    }
+
     // Private
 
     _populate()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to