Changeset 242080 in webkit


Ignore:
Timestamp:
Feb 26, 2019 12:14:57 AM (5 years ago)
Author:
Devin Rousso
Message:

Web Inspector: navigation sidebar says "No Search Results" when a slow search is in progress
https://bugs.webkit.org/show_bug.cgi?id=170631
<rdar://problem/29473874>

Reviewed by Joseph Pecoraro.

Keep a count of all the backend commands (increment when firing, decrement when a result is
sent back to the frontend). Once the count comes back to 0, attempt to show the "No Results"
placeholder, since we will have finished searching at that point. Since commands can be called
as a result of other commands, using Promise.all isn't possible.

  • UserInterface/Views/SearchSidebarPanel.js:

(WI.SearchSidebarPanel.prototype.performSearch):
(WI.SearchSidebarPanel.prototype.performSearch.updateEmptyContentPlaceholderSoon): Deleted.
(WI.SearchSidebarPanel.prototype.performSearch.updateEmptyContentPlaceholder): Deleted.
Drive-by: replace bind calls with arrow functions, and use for-of loops.

  • Localizations/en.lproj/localizedStrings.js:
Location:
trunk/Source/WebInspectorUI
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r242079 r242080  
     12019-02-26  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: navigation sidebar says "No Search Results" when a slow search is in progress
     4        https://bugs.webkit.org/show_bug.cgi?id=170631
     5        <rdar://problem/29473874>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Keep a count of all the backend commands (increment when firing, decrement when a result is
     10        sent back to the frontend). Once the count comes back to `0`, attempt to show the "No Results"
     11        placeholder, since we will have finished searching at that point. Since commands can be called
     12        as a result of other commands, using `Promise.all` isn't possible.
     13
     14        * UserInterface/Views/SearchSidebarPanel.js:
     15        (WI.SearchSidebarPanel.prototype.performSearch):
     16        (WI.SearchSidebarPanel.prototype.performSearch.updateEmptyContentPlaceholderSoon): Deleted.
     17        (WI.SearchSidebarPanel.prototype.performSearch.updateEmptyContentPlaceholder): Deleted.
     18        Drive-by: replace `bind` calls with arrow functions, and use for-of loops.
     19
     20        * Localizations/en.lproj/localizedStrings.js:
     21
    1222019-02-26  Devin Rousso  <drousso@apple.com>
    223
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r242073 r242080  
    850850/* Settings tab label for search related settings */
    851851localizedStrings["Search: @ Settings"] = "Search:";
     852localizedStrings["Searching %s"] = "Searching %s";
    852853localizedStrings["Secure"] = "Secure";
    853854localizedStrings["Security"] = "Security";
  • trunk/Source/WebInspectorUI/UserInterface/Views/SearchSidebarPanel.js

    r242018 r242080  
    101101            return;
    102102
     103        let promiseCount = 0;
     104        let countPromise = async (promise, callback) => {
     105            ++promiseCount;
     106            if (promiseCount === 1) {
     107                let searchingPlaceholder = WI.createMessageTextView("");
     108                String.format(WI.UIString("Searching %s"), [(new WI.IndeterminateProgressSpinner).element], String.standardFormatters, searchingPlaceholder, (a, b) => {
     109                    a.append(b);
     110                    return a;
     111                });
     112                this.updateEmptyContentPlaceholder(searchingPlaceholder);
     113            }
     114
     115            let value = await promise;
     116
     117            if (callback)
     118                callback(value);
     119
     120            --promiseCount;
     121            console.assert(promiseCount >= 0);
     122            if (promiseCount === 0)
     123                this.updateEmptyContentPlaceholder(WI.UIString("No Search Results"));
     124        };
     125
    103126        let isCaseSensitive = !!this._searchInputSettings.caseSensitive.value;
    104127        let isRegex = !!this._searchInputSettings.regularExpression.value;
    105 
    106         var updateEmptyContentPlaceholderTimeout = null;
    107128
    108129        function createTreeElementForMatchObject(matchObject, parentTreeElement)
     
    115136            if (!this.contentTreeOutline.selectedTreeElement)
    116137                matchTreeElement.revealAndSelect(false, true);
    117         }
    118 
    119         function updateEmptyContentPlaceholderSoon()
    120         {
    121             if (updateEmptyContentPlaceholderTimeout)
    122                 return;
    123             updateEmptyContentPlaceholderTimeout = setTimeout(updateEmptyContentPlaceholder.bind(this), 100);
    124         }
    125 
    126         function updateEmptyContentPlaceholder()
    127         {
    128             if (updateEmptyContentPlaceholderTimeout) {
    129                 clearTimeout(updateEmptyContentPlaceholderTimeout);
    130                 updateEmptyContentPlaceholderTimeout = null;
    131             }
    132 
    133             this.updateEmptyContentPlaceholder(WI.UIString("No Search Results"));
    134138        }
    135139
     
    145149        }
    146150
    147         function resourcesCallback(error, result)
    148         {
    149             updateEmptyContentPlaceholderSoon.call(this);
    150 
    151             if (error)
    152                 return;
    153 
    154             function resourceCallback(frameId, url, error, resourceMatches)
    155             {
    156                 updateEmptyContentPlaceholderSoon.call(this);
    157 
    158                 if (error || !resourceMatches || !resourceMatches.length)
    159                     return;
    160 
    161                 var frame = WI.networkManager.frameForIdentifier(frameId);
    162                 if (!frame)
    163                     return;
    164 
    165                 var resource = frame.url === url ? frame.mainResource : frame.resourceForURL(url);
    166                 if (!resource)
    167                     return;
    168 
    169                 var resourceTreeElement = this._searchTreeElementForResource(resource);
    170 
    171                 for (var i = 0; i < resourceMatches.length; ++i) {
    172                     var match = resourceMatches[i];
    173                     forEachMatch(searchQuery, match.lineContent, (lineMatch, lastIndex) => {
    174                         var matchObject = new WI.SourceCodeSearchMatchObject(resource, match.lineContent, searchQuery, new WI.TextRange(match.lineNumber, lineMatch.index, match.lineNumber, lastIndex));
    175                         createTreeElementForMatchObject.call(this, matchObject, resourceTreeElement);
    176                     });
    177                 }
    178 
    179                 if (!resourceTreeElement.children.length)
    180                     this.contentTreeOutline.removeChild(resourceTreeElement);
    181 
    182                 updateEmptyContentPlaceholder.call(this);
     151        let resourceCallback = (frameId, url, {result}) => {
     152            if (!result || !result.length)
     153                return;
     154
     155            var frame = WI.networkManager.frameForIdentifier(frameId);
     156            if (!frame)
     157                return;
     158
     159            var resource = frame.url === url ? frame.mainResource : frame.resourceForURL(url);
     160            if (!resource)
     161                return;
     162
     163            var resourceTreeElement = this._searchTreeElementForResource(resource);
     164
     165            for (var i = 0; i < result.length; ++i) {
     166                var match = result[i];
     167                forEachMatch(searchQuery, match.lineContent, (lineMatch, lastIndex) => {
     168                    var matchObject = new WI.SourceCodeSearchMatchObject(resource, match.lineContent, searchQuery, new WI.TextRange(match.lineNumber, lineMatch.index, match.lineNumber, lastIndex));
     169                    createTreeElementForMatchObject.call(this, matchObject, resourceTreeElement);
     170                });
    183171            }
    184172
     173            if (!resourceTreeElement.children.length)
     174                this.contentTreeOutline.removeChild(resourceTreeElement);
     175        };
     176
     177        let resourcesCallback = ({result}) => {
    185178            let preventDuplicates = new Set;
    186179
    187             for (let i = 0; i < result.length; ++i) {
    188                 let searchResult = result[i];
     180            for (let searchResult of result) {
    189181                if (!searchResult.url || !searchResult.frameId)
    190182                    continue;
     
    199191
    200192                // COMPATIBILITY (iOS 9): Page.searchInResources did not have the optional requestId parameter.
    201                 PageAgent.searchInResource(searchResult.frameId, searchResult.url, searchQuery, isCaseSensitive, isRegex, searchResult.requestId, resourceCallback.bind(this, searchResult.frameId, searchResult.url));
     193                countPromise(PageAgent.searchInResource(searchResult.frameId, searchResult.url, searchQuery, isCaseSensitive, isRegex, searchResult.requestId), resourceCallback.bind(this, searchResult.frameId, searchResult.url));
    202194            }
    203195
     
    207199            ];
    208200            Promise.race(promises).then(this._contentChanged.bind(this));
    209         }
    210 
    211         function searchScripts(scriptsToSearch)
    212         {
    213             updateEmptyContentPlaceholderSoon.call(this);
    214 
     201        };
     202
     203        let scriptCallback = (script, {result}) => {
     204            if (!result || !result.length)
     205                return;
     206
     207            var scriptTreeElement = this._searchTreeElementForScript(script);
     208
     209            for (let match of result) {
     210                forEachMatch(searchQuery, match.lineContent, (lineMatch, lastIndex) => {
     211                    var matchObject = new WI.SourceCodeSearchMatchObject(script, match.lineContent, searchQuery, new WI.TextRange(match.lineNumber, lineMatch.index, match.lineNumber, lastIndex));
     212                    createTreeElementForMatchObject.call(this, matchObject, scriptTreeElement);
     213                });
     214            }
     215
     216            if (!scriptTreeElement.children.length)
     217                this.contentTreeOutline.removeChild(scriptTreeElement);
     218        };
     219
     220        let searchScripts = (scriptsToSearch) => {
    215221            if (!scriptsToSearch.length)
    216222                return;
    217223
    218             function scriptCallback(script, error, scriptMatches)
    219             {
    220                 updateEmptyContentPlaceholderSoon.call(this);
    221 
    222                 if (error || !scriptMatches || !scriptMatches.length)
     224            for (let script of scriptsToSearch)
     225                countPromise(script.target.DebuggerAgent.searchInContent(script.id, searchQuery, isCaseSensitive, isRegex), scriptCallback.bind(this, script));
     226        };
     227
     228        let domCallback = ({searchId, resultCount}) => {
     229            if (!resultCount)
     230                return;
     231
     232            console.assert(searchId);
     233
     234            this._domSearchIdentifier = searchId;
     235
     236            let domSearchResults = ({nodeIds}) => {
     237                // If someone started a new search, then return early and stop showing seach results from the old query.
     238                if (this._domSearchIdentifier !== searchId)
    223239                    return;
    224240
    225                 var scriptTreeElement = this._searchTreeElementForScript(script);
    226 
    227                 for (var i = 0; i < scriptMatches.length; ++i) {
    228                     var match = scriptMatches[i];
    229                     forEachMatch(searchQuery, match.lineContent, (lineMatch, lastIndex) => {
    230                         var matchObject = new WI.SourceCodeSearchMatchObject(script, match.lineContent, searchQuery, new WI.TextRange(match.lineNumber, lineMatch.index, match.lineNumber, lastIndex));
    231                         createTreeElementForMatchObject.call(this, matchObject, scriptTreeElement);
    232                     });
    233                 }
    234 
    235                 if (!scriptTreeElement.children.length)
    236                     this.contentTreeOutline.removeChild(scriptTreeElement);
    237 
    238                 updateEmptyContentPlaceholder.call(this);
    239             }
    240 
    241             for (let script of scriptsToSearch)
    242                 script.target.DebuggerAgent.searchInContent(script.id, searchQuery, isCaseSensitive, isRegex, scriptCallback.bind(this, script));
    243         }
    244 
    245         function domCallback(error, searchId, resultsCount)
    246         {
    247             updateEmptyContentPlaceholderSoon.call(this);
    248 
    249             if (error || !resultsCount)
    250                 return;
    251 
    252             console.assert(searchId);
    253 
    254             this._domSearchIdentifier = searchId;
    255 
    256             function domSearchResults(error, nodeIds)
    257             {
    258                 updateEmptyContentPlaceholderSoon.call(this);
    259 
    260                 if (error)
    261                     return;
    262 
    263                 for (var i = 0; i < nodeIds.length; ++i) {
    264                     // If someone started a new search, then return early and stop showing seach results from the old query.
    265                     if (this._domSearchIdentifier !== searchId)
    266                         return;
    267 
    268                     var domNode = WI.domManager.nodeForId(nodeIds[i]);
     241                for (let nodeId of nodeIds) {
     242                    let domNode = WI.domManager.nodeForId(nodeId);
    269243                    if (!domNode || !domNode.ownerDocument)
    270244                        continue;
     
    299273                        this.contentTreeOutline.removeChild(resourceTreeElement);
    300274
    301                     updateEmptyContentPlaceholder.call(this);
    302275                }
    303             }
    304 
    305             DOMAgent.getSearchResults(searchId, 0, resultsCount, domSearchResults.bind(this));
    306         }
     276            };
     277
     278            countPromise(DOMAgent.getSearchResults(searchId, 0, resultCount), domSearchResults);
     279        };
    307280
    308281        if (window.DOMAgent)
     
    310283
    311284        if (window.PageAgent)
    312             PageAgent.searchInResources(searchQuery, isCaseSensitive, isRegex, resourcesCallback.bind(this));
     285            countPromise(PageAgent.searchInResources(searchQuery, isCaseSensitive, isRegex), resourcesCallback);
    313286
    314287        setTimeout(searchScripts.bind(this, WI.debuggerManager.searchableScripts), 0);
     
    320293            }
    321294
    322             DOMAgent.performSearch(searchQuery, domCallback.bind(this));
     295            countPromise(DOMAgent.performSearch(searchQuery), domCallback);
    323296        }
    324297
    325298        // FIXME: Resource search should work in JSContext inspection.
    326299        // <https://webkit.org/b/131252> Web Inspector: JSContext inspection Resource search does not work
    327         if (!window.DOMAgent && !window.PageAgent)
    328             updateEmptyContentPlaceholderSoon.call(this);
    329300    }
    330301
Note: See TracChangeset for help on using the changeset viewer.