Changeset 55727 in webkit


Ignore:
Timestamp:
Mar 9, 2010 9:34:16 AM (14 years ago)
Author:
pfeldman@chromium.org
Message:

2010-03-09 Yury Semikhatsky <yurys@chromium.org>

Reviewed by Pavel Feldman.


When enable resource tracking state changes use the same method as
location.reload for reloading inspected page.

https://bugs.webkit.org/show_bug.cgi?id=35923

  • inspector/InspectorBackend.cpp: (WebCore::InspectorBackend::reloadPage):
  • inspector/InspectorController.cpp: (WebCore::InspectorController::enableResourceTracking):
Location:
trunk/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r55726 r55727  
    1212        * inspector/InspectorController.cpp:
    1313        (WebCore::InspectorController::enableResourceTracking):
     14
     152010-03-09  Pavel Feldman  <pfeldman@chromium.org>
     16
     17        Reviewed by Timothy Hatcher.
     18
     19        Web Inspector: Refactor Audits panel presentation layer.
     20        This change removes unnecessary complexity:
     21          - Audit scores were not used
     22          - Audit rule parameters are passed as rule constructor arguments
     23          - View management aligned with the rest of the front-end
     24          - Single TreeOutline is used for category results (no need to create sections for those)
     25          - Rules code beautified and simplified where possible
     26          - Some UI improvements applied (see attached screenshot)
     27
     28        https://bugs.webkit.org/show_bug.cgi?id=35860
     29
     30        * inspector/front-end/AuditCategories.js:
     31        (WebInspector.AuditCategories.PagePerformance.prototype.initialize):
     32        (WebInspector.AuditCategories.NetworkUtilization.prototype.initialize):
     33        * inspector/front-end/AuditResultView.js:
     34        (WebInspector.AuditResultView):
     35        (WebInspector.AuditCategoryResultPane):
     36        (WebInspector.AuditCategoryResultPane.prototype._appendResult):
     37        * inspector/front-end/AuditRules.js:
     38        (WebInspector.AuditRules.GzipRule.prototype.doRun):
     39        (WebInspector.AuditRules.CombineExternalResourcesRule):
     40        (WebInspector.AuditRules.CombineExternalResourcesRule.prototype.doRun):
     41        (WebInspector.AuditRules.CombineJsResourcesRule):
     42        (WebInspector.AuditRules.CombineCssResourcesRule):
     43        (WebInspector.AuditRules.MinimizeDnsLookupsRule):
     44        (WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype.doRun):
     45        (WebInspector.AuditRules.ParallelizeDownloadRule):
     46        (WebInspector.AuditRules.ParallelizeDownloadRule.prototype.doRun):
     47        (WebInspector.AuditRules.UnusedCssRule):
     48        (WebInspector.AuditRules.UnusedCssRule.prototype.doRun.evalCallback):
     49        (WebInspector.AuditRules.UnusedCssRule.prototype.doRun.routine):
     50        (WebInspector.AuditRules.UnusedCssRule.prototype.doRun):
     51        (WebInspector.AuditRules.CacheControlRule):
     52        (WebInspector.AuditRules.CacheControlRule.prototype.doRun):
     53        (WebInspector.AuditRules.CacheControlRule.prototype.execCheck):
     54        (WebInspector.AuditRules.BrowserCacheControlRule):
     55        (WebInspector.AuditRules.BrowserCacheControlRule.prototype.handleNonCacheableResources):
     56        (WebInspector.AuditRules.BrowserCacheControlRule.prototype.runChecks):
     57        (WebInspector.AuditRules.ProxyCacheControlRule):
     58        (WebInspector.AuditRules.ProxyCacheControlRule.prototype.runChecks):
     59        (WebInspector.AuditRules.ImageDimensionsRule):
     60        (WebInspector.AuditRules.ImageDimensionsRule.prototype.doRun):
     61        (WebInspector.AuditRules.CssInHeadRule):
     62        (WebInspector.AuditRules.CssInHeadRule.prototype.doRun):
     63        (WebInspector.AuditRules.CssInHeadRule.prototype.doRun.routine):
     64        (WebInspector.AuditRules.StylesScriptsOrderRule):
     65        (WebInspector.AuditRules.StylesScriptsOrderRule.prototype.doRun):
     66        (WebInspector.AuditRules.StylesScriptsOrderRule.prototype.doRun.routine):
     67        (WebInspector.AuditRules.CookieRuleBase):
     68        (WebInspector.AuditRules.CookieRuleBase.prototype.doRun.resultCallback):
     69        (WebInspector.AuditRules.CookieRuleBase.prototype.doRun):
     70        (WebInspector.AuditRules.CookieSizeRule):
     71        (WebInspector.AuditRules.CookieSizeRule.prototype.processCookies):
     72        (WebInspector.AuditRules.StaticCookielessRule):
     73        (WebInspector.AuditRules.StaticCookielessRule.prototype.processCookies):
     74        * inspector/front-end/AuditsPanel.js:
     75        (WebInspector.AuditsPanel):
     76        (WebInspector.AuditsPanel.prototype._executeAudit.ruleResultReadyCallback):
     77        (WebInspector.AuditsPanel.prototype._executeAudit):
     78        (WebInspector.AuditsPanel.prototype._reloadResources):
     79        (WebInspector.AuditsPanel.prototype._didMainResourceLoad):
     80        (WebInspector.AuditsPanel.prototype.showResults):
     81        (WebInspector.AuditsPanel.prototype.showLauncherView):
     82        (WebInspector.AuditsPanel.prototype.get visibleView):
     83        (WebInspector.AuditsPanel.prototype.set visibleView):
     84        (WebInspector.AuditsPanel.prototype.show):
     85        (WebInspector.AuditsPanel.prototype._clearButtonClicked):
     86        (WebInspector.AuditCategory.prototype.addRule):
     87        (WebInspector.AuditRule):
     88        (WebInspector.AuditRule.prototype.set severity):
     89        (WebInspector.AuditRule.prototype.run):
     90        (WebInspector.AuditRule.prototype.doRun):
     91        (WebInspector.AuditCategoryResult):
     92        (WebInspector.AuditCategoryResult.prototype.addRuleResult):
     93        (WebInspector.AuditRuleResult):
     94        (WebInspector.AuditRuleResult.prototype.addChild):
     95        (WebInspector.AuditRuleResult.prototype.addURL):
     96        (WebInspector.AuditRuleResult.prototype.addURLs):
     97        (WebInspector.AuditRuleResult.prototype.addSnippet):
     98        * inspector/front-end/Settings.js:
     99        * inspector/front-end/audits.css:
     100        * inspector/front-end/inspector.js:
     101        (WebInspector._createPanels):
     102        (WebInspector.documentKeyDown):
    14103
    151042010-03-09  Pavel Feldman  <pfeldman@chromium.org>
  • trunk/WebCore/inspector/front-end/AuditCategories.js

    r54591 r55727  
    3838    initialize: function()
    3939    {
    40         this.addRule(new WebInspector.AuditRules.UnusedCssRule());
    41         this.addRule(new WebInspector.AuditRules.CssInHeadRule({InlineURLScore: 6, InlineStylesheetScore: 21}));
    42         this.addRule(new WebInspector.AuditRules.StylesScriptsOrderRule({CSSAfterJSURLScore: 11, InlineBetweenResourcesScore: 21}));
     40        this.addRule(new WebInspector.AuditRules.UnusedCssRule(), WebInspector.AuditRule.Severity.Warning);
     41        this.addRule(new WebInspector.AuditRules.CssInHeadRule(), WebInspector.AuditRule.Severity.Severe);
     42        this.addRule(new WebInspector.AuditRules.StylesScriptsOrderRule(), WebInspector.AuditRule.Severity.Severe);
    4343    }
    4444}
     
    5555    initialize: function()
    5656    {
    57         this.addRule(new WebInspector.AuditRules.GzipRule());
    58         this.addRule(new WebInspector.AuditRules.ImageDimensionsRule({ScorePerImageUse: 5}));
    59         this.addRule(new WebInspector.AuditRules.CookieSizeRule({MinBytesThreshold: 400, MaxBytesThreshold: 1000}));
    60         this.addRule(new WebInspector.AuditRules.StaticCookielessRule({MinResources: 5}));
    61         this.addRule(new WebInspector.AuditRules.CombineJsResourcesRule({AllowedPerDomain: 2, ScorePerResource: 11}));
    62         this.addRule(new WebInspector.AuditRules.CombineCssResourcesRule({AllowedPerDomain: 2, ScorePerResource: 11}));
    63         this.addRule(new WebInspector.AuditRules.MinimizeDnsLookupsRule({HostCountThreshold: 4, ViolationDomainScore: 6}));
    64         this.addRule(new WebInspector.AuditRules.ParallelizeDownloadRule({OptimalHostnameCount: 4, MinRequestThreshold: 10, MinBalanceThreshold: 0.5}));
    65         this.addRule(new WebInspector.AuditRules.BrowserCacheControlRule());
    66         this.addRule(new WebInspector.AuditRules.ProxyCacheControlRule());
     57        this.addRule(new WebInspector.AuditRules.GzipRule(), WebInspector.AuditRule.Severity.Severe);
     58        this.addRule(new WebInspector.AuditRules.ImageDimensionsRule(), WebInspector.AuditRule.Severity.Warning);
     59        this.addRule(new WebInspector.AuditRules.CookieSizeRule(400), WebInspector.AuditRule.Severity.Warning);
     60        this.addRule(new WebInspector.AuditRules.StaticCookielessRule(5), WebInspector.AuditRule.Severity.Warning);
     61        this.addRule(new WebInspector.AuditRules.CombineJsResourcesRule(2), WebInspector.AuditRule.Severity.Severe);
     62        this.addRule(new WebInspector.AuditRules.CombineCssResourcesRule(2), WebInspector.AuditRule.Severity.Severe);
     63        this.addRule(new WebInspector.AuditRules.MinimizeDnsLookupsRule(4), WebInspector.AuditRule.Severity.Warning);
     64        this.addRule(new WebInspector.AuditRules.ParallelizeDownloadRule(4, 10, 0.5), WebInspector.AuditRule.Severity.Warning);
     65        this.addRule(new WebInspector.AuditRules.BrowserCacheControlRule(), WebInspector.AuditRule.Severity.Severe);
     66        this.addRule(new WebInspector.AuditRules.ProxyCacheControlRule(), WebInspector.AuditRule.Severity.Warning);
    6767    }
    6868}
  • trunk/WebCore/inspector/front-end/AuditResultView.js

    r52629 r55727  
    3232{
    3333    WebInspector.View.call(this);
     34    this.element.className = "audit-result-view";
    3435
    35     this.element.id = "audit-result-view";
    36 
    37     function entrySortFunction(a, b)
    38     {
    39         var result = b.type - a.type;
    40         if (!result)
    41             result = (a.value || "").localeCompare(b.value || "");
    42         return result;
    43     }
    44 
    45     for (var i = 0; i < categoryResults.length; ++i) {
    46         var entries = categoryResults[i].entries;
    47         if (entries) {
    48             entries.sort(entrySortFunction);
    49             this.element.appendChild(new WebInspector.AuditCategoryResultPane(categoryResults[i]).element);
    50         }
    51     }
     36    for (var i = 0; i < categoryResults.length; ++i)
     37        this.element.appendChild(new WebInspector.AuditCategoryResultPane(categoryResults[i]).element);
    5238}
    5339
     
    5844{
    5945    WebInspector.SidebarPane.call(this, categoryResult.title);
     46    var treeOutlineElement = document.createElement("ol");
     47    this.bodyElement.addStyleClass("audit-result-tree");
     48    this.bodyElement.appendChild(treeOutlineElement);
     49
     50    this._treeOutline = new TreeOutline(treeOutlineElement);
     51    this._treeOutline.expandTreeElementsWhenArrowing = true;
     52    for (var i = 0; i < categoryResult.ruleResults.length; ++i) {
     53        var ruleResult = categoryResult.ruleResults[i];
     54        var treeElement = this._appendResult(this._treeOutline, ruleResult);
     55        treeElement.listItemElement.addStyleClass("audit-result");
     56
     57        if (ruleResult.severity) {
     58            var severityElement = document.createElement("img");
     59            severityElement.className = "severity-" + ruleResult.severity;
     60            treeElement.listItemElement.appendChild(severityElement);
     61        }
     62    }
    6063    this.expand();
    61     for (var i = 0; i < categoryResult.entries.length; ++i)
    62         this.bodyElement.appendChild(new WebInspector.AuditRuleResultPane(categoryResult.entries[i]).element);
     64}
     65
     66WebInspector.AuditCategoryResultPane.prototype = {
     67    _appendResult: function(parentTreeElement, result)
     68    {
     69        var title = result.value;
     70        if (result.violationCount)
     71            title = String.sprintf("%s (%d)", title, result.violationCount);
     72
     73        var treeElement = new TreeElement(title, null, !!result.children);
     74        parentTreeElement.appendChild(treeElement);
     75
     76        if (result.className)
     77            treeElement.listItemElement.addStyleClass(result.className);
     78        if (result.children) {
     79            for (var i = 0; i < result.children.length; ++i)
     80                this._appendResult(treeElement, result.children[i]);
     81        }
     82        if (result.expanded) {
     83            treeElement.listItemElement.removeStyleClass("parent");
     84            treeElement.listItemElement.addStyleClass("parent-expanded");
     85            treeElement.expand();
     86        }
     87        return treeElement;
     88    }
    6389}
    6490
    6591WebInspector.AuditCategoryResultPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    66 
    67 
    68 WebInspector.AuditRuleResultPane = function(ruleResult)
    69 {
    70     WebInspector.SidebarPane.call(this, ruleResult.value);
    71     if (!ruleResult.children)
    72         return;
    73 
    74     this._decorateRuleResult(ruleResult);
    75 
    76     for (var i = 0; i < ruleResult.children.length; ++i) {
    77         var section = new WebInspector.AuditRuleResultChildSection(ruleResult.children[i]);
    78         this.bodyElement.appendChild(section.element);
    79     }
    80 }
    81 
    82 WebInspector.AuditRuleResultPane.prototype = {
    83     _decorateRuleResult: function(ruleResult)
    84     {
    85         if (ruleResult.type == WebInspector.AuditRuleResult.Type.NA)
    86             return;
    87 
    88         var scoreElement = document.createElement("img");
    89         scoreElement.className = "score";
    90         var className = (ruleResult.type == WebInspector.AuditRuleResult.Type.Violation) ? "red" : "green";
    91         scoreElement.addStyleClass(className);
    92         this.element.insertBefore(scoreElement, this.element.firstChild);
    93     }
    94 }
    95 
    96 WebInspector.AuditRuleResultPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
    97 
    98 
    99 WebInspector.AuditRuleResultChildSection = function(entry)
    100 {
    101     WebInspector.Section.call(this, entry.value);
    102     var children = entry.children;
    103     this._hasChildren = !!children && children.length;
    104     if (!this._hasChildren)
    105         this.element.addStyleClass("blank-section");
    106     else {
    107         this.contentElement = document.createElement("div");
    108         this.contentElement.addStyleClass("section-content");
    109         for (var i = 0; i < children.length; ++i) {
    110             var paraElement = document.createElement("p");
    111             paraElement.innerHTML = children[i].value;
    112             this.contentElement.appendChild(paraElement);
    113         }
    114         this.contentElement.appendChild(paraElement);
    115         this.element.appendChild(this.contentElement);
    116     }
    117 }
    118 
    119 WebInspector.AuditRuleResultChildSection.prototype = {
    120 
    121     // title is considered pure HTML
    122     set title(x)
    123     {
    124         if (this._title === x)
    125             return;
    126         this._title = x;
    127 
    128         this.titleElement.innerHTML = x;
    129     },
    130 
    131     expand: function()
    132     {
    133         if (this._hasChildren)
    134             WebInspector.Section.prototype.expand.call(this);
    135     }
    136 }
    137 
    138 WebInspector.AuditRuleResultChildSection.prototype.__proto__ = WebInspector.Section.prototype;
  • trunk/WebCore/inspector/front-end/AuditRules.js

    r55466 r55727  
    4343}
    4444
    45 /**
    46  * @param {Array} array Array of Elements (outerHTML is used) or strings (plain value is used as innerHTML)
    47  */
    48 WebInspector.AuditRules.arrayAsUL = function(array, shouldLinkify)
    49 {
    50     if (!array.length)
    51         return "";
    52     var ulElement = document.createElement("ul");
    53     for (var i = 0; i < array.length; ++i) {
    54         var liElement = document.createElement("li");
    55         if (array[i] instanceof Element)
    56             liElement.appendChild(array[i]);
    57         else if (shouldLinkify)
    58             liElement.appendChild(WebInspector.linkifyURLAsNode(array[i]));
    59         else
    60             liElement.innerHTML = array[i];
    61         ulElement.appendChild(liElement);
    62     }
    63     return ulElement.outerHTML;
    64 }
    65 
    6645WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, regexp, needFullResources)
    6746{
     
    9978    doRun: function(resources, result, callback)
    10079    {
    101         try {
    102             var commonMessage = undefined;
    103             var totalSavings = 0;
    104             var compressedSize = 0
    105             var candidateSize = 0
    106             var outputResources = [];
    107             for (var i = 0, length = resources.length; i < length; ++i) {
    108                 var resource = resources[i];
    109                 if (this._shouldCompress(resource)) {
    110                     var size = resource.resourceSize;
    111                     candidateSize += size;
    112                     if (this._isCompressed(resource)) {
    113                         compressedSize += size;
    114                         continue;
    115                     }
    116                     if (!commonMessage)
    117                         commonMessage = result.appendChild("");
    118                     var savings = 2 * size / 3;
    119                     totalSavings += savings;
    120                     outputResources.push(
    121                         String.sprintf("Compressing %s could save ~%s",
    122                         WebInspector.linkifyURL(resource.url), Number.bytesToString(savings)));
     80        var totalSavings = 0;
     81        var compressedSize = 0;
     82        var candidateSize = 0;
     83        var summary = result.addChild("", true);
     84        for (var i = 0, length = resources.length; i < length; ++i) {
     85            var resource = resources[i];
     86            if (this._shouldCompress(resource)) {
     87                var size = resource.resourceSize;
     88                candidateSize += size;
     89                if (this._isCompressed(resource)) {
     90                    compressedSize += size;
     91                    continue;
    12392                }
    124             }
    125             if (commonMessage) {
    126               commonMessage.value =
    127                   String.sprintf("Compressing the following resources with gzip could reduce their " +
    128                       "transfer size by about two thirds (~%s):", Number.bytesToString(totalSavings));
    129               commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources));
    130               result.score = 100 * compressedSize / candidateSize;
    131               result.type = WebInspector.AuditRuleResult.Type.Violation;
    132             }
    133         } catch(e) {
    134             console.log(e);
    135         } finally {
    136             callback(result);
    137         }
     93                var savings = 2 * size / 3;
     94                totalSavings += savings;
     95                summary.addChild(String.sprintf("%s could save ~%s", WebInspector.linkifyURL(resource.url), Number.bytesToString(savings)));
     96                result.violationCount++;
     97            }
     98        }
     99        if (!totalSavings)
     100            return callback(null);
     101        summary.value = String.sprintf("Compressing the following resources with gzip could reduce their transfer size by about two thirds (~%s):", Number.bytesToString(totalSavings));
     102        callback(result);
    138103    },
    139104
     
    153118
    154119
    155 WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, resourceTypeName, parametersObject)
    156 {
    157     WebInspector.AuditRule.call(this, id, name, parametersObject);
     120WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, resourceTypeName, allowedPerDomain)
     121{
     122    WebInspector.AuditRule.call(this, id, name);
    158123    this._type = type;
    159124    this._resourceTypeName = resourceTypeName;
     125    this._allowedPerDomain = allowedPerDomain;
    160126}
    161127
     
    163129    doRun: function(resources, result, callback)
    164130    {
    165         try {
    166             var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [this._type], WebInspector.URLRegExp);
    167             var penalizedResourceCount = 0;
    168             // TODO: refactor according to the chosen i18n approach
    169             for (var domain in domainToResourcesMap) {
    170                 var domainResources = domainToResourcesMap[domain];
    171                 var extraResourceCount = domainResources.length - this.getValue("AllowedPerDomain");
    172                 if (extraResourceCount <= 0)
    173                     continue;
    174                 penalizedResourceCount += extraResourceCount - 1;
    175                 result.appendChild(
    176                     String.sprintf("There are %d %s files served from %s. Consider combining them into as few files as possible.",
    177                     domainResources.length, this._resourceTypeName, domain));
    178             }
    179             result.score = 100 - (penalizedResourceCount * this.getValue("ScorePerResource"));
    180             result.type = WebInspector.AuditRuleResult.Type.Hint;
    181         } catch(e) {
    182             console.log(e);
    183         } finally {
    184             callback(result);
    185         }
    186     }
    187 };
     131        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [this._type], WebInspector.URLRegExp);
     132        var penalizedResourceCount = 0;
     133        // TODO: refactor according to the chosen i18n approach
     134        var summary = result.addChild("", true);
     135        for (var domain in domainToResourcesMap) {
     136            var domainResources = domainToResourcesMap[domain];
     137            var extraResourceCount = domainResources.length - this._allowedPerDomain;
     138            if (extraResourceCount <= 0)
     139                continue;
     140            penalizedResourceCount += extraResourceCount - 1;
     141            summary.addChild(String.sprintf("%d %s resources served from %s.", domainResources.length, this._resourceTypeName, domain));
     142            result.violationCount += domainResources.length;
     143        }
     144        if (!penalizedResourceCount)
     145            return callback(null);
     146
     147        summary.value = "There are multiple resources served from same domain. Consider combining them into as few files as possible.";
     148        callback(result);
     149    }
     150}
    188151
    189152WebInspector.AuditRules.CombineExternalResourcesRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
    190153
    191154
    192 WebInspector.AuditRules.CombineJsResourcesRule = function(parametersObject) {
    193     WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externaljs", "Combine external JavaScript", WebInspector.Resource.Type.Script, "JS", parametersObject);
     155WebInspector.AuditRules.CombineJsResourcesRule = function(allowedPerDomain) {
     156    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externaljs", "Combine external JavaScript", WebInspector.Resource.Type.Script, "JavaScript", allowedPerDomain);
    194157}
    195158
     
    197160
    198161
    199 WebInspector.AuditRules.CombineCssResourcesRule = function(parametersObject) {
    200     WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externalcss", "Combine external CSS", WebInspector.Resource.Type.Stylesheet, "CSS", parametersObject);
     162WebInspector.AuditRules.CombineCssResourcesRule = function(allowedPerDomain) {
     163    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externalcss", "Combine external CSS", WebInspector.Resource.Type.Stylesheet, "CSS", allowedPerDomain);
    201164}
    202165
     
    204167
    205168
    206 WebInspector.AuditRules.MinimizeDnsLookupsRule = function(parametersObject) {
    207     WebInspector.AuditRule.call(this, "network-minimizelookups", "Minimize DNS lookups", parametersObject);
     169WebInspector.AuditRules.MinimizeDnsLookupsRule = function(hostCountThreshold) {
     170    WebInspector.AuditRule.call(this, "network-minimizelookups", "Minimize DNS lookups");
     171    this._hostCountThreshold = hostCountThreshold;
    208172}
    209173
     
    211175    doRun: function(resources, result, callback)
    212176    {
    213         try {
    214             var violationDomains = [];
    215             var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, undefined, WebInspector.URLRegExp);
    216             for (var domain in domainToResourcesMap) {
    217                 if (domainToResourcesMap[domain].length > 1)
    218                     continue;
    219                 var match = domain.match(WebInspector.URLRegExp);
    220                 if (!match)
    221                     continue;
    222                 if (!match[2].search(WebInspector.AuditRules.IPAddressRegexp))
    223                     continue; // an IP address
    224                 violationDomains.push(match[2]);
    225             }
    226             if (violationDomains.length <= this.getValue("HostCountThreshold"))
    227                 return;
    228             var commonMessage = result.appendChild(
    229                 "The following domains only serve one resource each. If possible, avoid the extra DNS " +
    230                 "lookups by serving these resources from existing domains.");
    231             commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(violationDomains));
    232             result.score = 100 - violationDomains.length * this.getValue("ViolationDomainScore");
    233         } catch(e) {
    234             console.log(e);
    235         } finally {
    236             callback(result);
    237         }
     177        var summary = result.addChild("");
     178        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, undefined, WebInspector.URLRegExp);
     179        for (var domain in domainToResourcesMap) {
     180            if (domainToResourcesMap[domain].length > 1)
     181                continue;
     182            var match = domain.match(WebInspector.URLRegExp);
     183            if (!match)
     184                continue;
     185            if (!match[2].search(WebInspector.AuditRules.IPAddressRegexp))
     186                continue; // an IP address
     187            summary.addSnippet(match[2]);
     188            result.violationCount++;
     189        }
     190        if (!summary.children || summary.children.length <= this._hostCountThreshold)
     191            return callback(null);
     192
     193        summary.value = "The following domains only serve one resource each. If possible, avoid the extra DNS lookups by serving these resources from existing domains.";
     194        callback(result);
    238195    }
    239196}
     
    242199
    243200
    244 WebInspector.AuditRules.ParallelizeDownloadRule = function(parametersObject)
    245 {
    246     WebInspector.AuditRule.call(this, "network-parallelizehosts", "Parallelize downloads across hostnames", parametersObject);
     201WebInspector.AuditRules.ParallelizeDownloadRule = function(optimalHostnameCount, minRequestThreshold, minBalanceThreshold)
     202{
     203    WebInspector.AuditRule.call(this, "network-parallelizehosts", "Parallelize downloads across hostnames");
     204    this._optimalHostnameCount = optimalHostnameCount;
     205    this._minRequestThreshold = minRequestThreshold;
     206    this._minBalanceThreshold = minBalanceThreshold;
    247207}
    248208
     
    258218        }
    259219
    260         try {
    261             var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(
    262                 resources,
    263                 [WebInspector.Resource.Type.Stylesheet, WebInspector.Resource.Type.Image],
    264                 WebInspector.URLRegExp,
    265                 true);
    266 
    267             var hosts = [];
    268             for (var url in domainToResourcesMap)
    269                 hosts.push(url);
    270 
    271             if (!hosts.length)
    272                 return; // no hosts (local file or something)
    273 
    274             hosts.sort(hostSorter);
    275 
    276             var optimalHostnameCount = this.getValue("OptimalHostnameCount");
    277             if (hosts.length > optimalHostnameCount)
    278                 hosts.splice(optimalHostnameCount);
    279 
    280             var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
    281             var resourceCountAboveThreshold = busiestHostResourceCount - this.getValue("MinRequestThreshold");
    282             if (resourceCountAboveThreshold <= 0)
    283                 return;
    284 
    285             var avgResourcesPerHost = 0;
    286             for (var i = 0, size = hosts.length; i < size; ++i)
    287                 avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
    288 
    289             // Assume optimal parallelization.
    290             avgResourcesPerHost /= optimalHostnameCount;
    291 
    292             avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
    293 
    294             var pctAboveAvg = (resourceCountAboveThreshold / avgResourcesPerHost) - 1.0;
    295 
    296             var minBalanceThreshold = this.getValue("MinBalanceThreshold");
    297             if (pctAboveAvg < minBalanceThreshold) {
    298                 result.score = 100;
    299                 return;
    300             }
    301 
    302             result.score = (1 - (pctAboveAvg - minBalanceThreshold)) * 100;
    303             result.type = WebInspector.AuditRuleResult.Type.Hint;
    304 
    305             var resourcesOnBusiestHost = domainToResourcesMap[hosts[0]];
    306             var commonMessage = result.appendChild(
    307                 String.sprintf("This page makes %d parallelizable requests to %s" +
    308                 ". Increase download parallelization by distributing the following" +
    309                 " requests across multiple hostnames.", busiestHostResourceCount, hosts[0]));
    310             var outputResources = [];
    311             for (var i = 0, size = resourcesOnBusiestHost.length; i < size; ++i)
    312                 outputResources.push(resourcesOnBusiestHost[i].url);
    313             commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources, true));
    314         } catch(e) {
    315             console.log(e);
    316         } finally {
    317             callback(result);
    318         }
     220        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(
     221            resources,
     222            [WebInspector.Resource.Type.Stylesheet, WebInspector.Resource.Type.Image],
     223            WebInspector.URLRegExp,
     224            true);
     225
     226        var hosts = [];
     227        for (var url in domainToResourcesMap)
     228            hosts.push(url);
     229
     230        if (!hosts.length)
     231            return callback(null); // no hosts (local file or something)
     232
     233        hosts.sort(hostSorter);
     234
     235        var optimalHostnameCount = this._optimalHostnameCount;
     236        if (hosts.length > optimalHostnameCount)
     237            hosts.splice(optimalHostnameCount);
     238
     239        var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
     240        var resourceCountAboveThreshold = busiestHostResourceCount - this._minRequestThreshold;
     241        if (resourceCountAboveThreshold <= 0)
     242            return callback(null);
     243
     244        var avgResourcesPerHost = 0;
     245        for (var i = 0, size = hosts.length; i < size; ++i)
     246            avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
     247
     248        // Assume optimal parallelization.
     249        avgResourcesPerHost /= optimalHostnameCount;
     250        avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
     251
     252        var pctAboveAvg = (resourceCountAboveThreshold / avgResourcesPerHost) - 1.0;
     253        var minBalanceThreshold = this._minBalanceThreshold;
     254        if (pctAboveAvg < minBalanceThreshold)
     255            return callback(null);
     256
     257        var resourcesOnBusiestHost = domainToResourcesMap[hosts[0]];
     258        var entry = result.addChild(String.sprintf("This page makes %d parallelizable requests to %s. Increase download parallelization by distributing the following requests across multiple hostnames.", busiestHostResourceCount, hosts[0]), true);
     259        for (var i = 0; i < resourcesOnBusiestHost.length; ++i)
     260            entry.addURL(resourcesOnBusiestHost[i].url);
     261
     262        result.violationCount = resourcesOnBusiestHost.length;
     263        callback(result);
    319264    }
    320265}
     
    325270// The reported CSS rule size is incorrect (parsed != original in WebKit),
    326271// so use percentages instead, which gives a better approximation.
    327 WebInspector.AuditRules.UnusedCssRule = function(parametersObject)
    328 {
    329     WebInspector.AuditRule.call(this, "page-unusedcss", "Remove unused CSS", parametersObject);
     272WebInspector.AuditRules.UnusedCssRule = function()
     273{
     274    WebInspector.AuditRule.call(this, "page-unusedcss", "Remove unused CSS rules");
    330275}
    331276
    332277WebInspector.AuditRules.UnusedCssRule.prototype = {
    333     _getUnusedStylesheetRatioMessage: function(unusedLength, type, location, styleSheetLength)
    334     {
    335         var url = type === "href"
    336             ? WebInspector.linkifyURL(location)
    337             : String.sprintf("Inline block #%s", location);
    338         var pctUnused = Math.round(unusedLength / styleSheetLength * 100);
    339         return String.sprintf("%s: %f%% (estimated) is not used by the current page.", url, pctUnused);
    340     },
    341 
    342     _getUnusedTotalRatioMessage: function(unusedLength, totalLength)
    343     {
    344         var pctUnused = Math.round(unusedLength / totalLength * 100);
    345         return String.sprintf("%d%% of CSS (estimated) is not used by the current page.", pctUnused);
    346     },
    347 
    348278    doRun: function(resources, result, callback)
    349279    {
    350280        var self = this;
    351         function evalCallback(evalResult, isException) {
    352             try {
    353               if (isException)
    354                   return;
    355 
    356               var totalLength = 0;
    357               var totalUnusedLength = 0;
    358               var topMessage;
    359               var styleSheetMessage;
    360               for (var i = 0; i < evalResult.length; ) {
    361                   var type = evalResult[i++];
    362                   if (type === "totalLength") {
    363                       totalLength = evalResult[i++];
    364                       continue;
    365                   }
    366 
    367                   var styleSheetLength = evalResult[i++];
    368                   var location = evalResult[i++];
    369                   var unusedRules = evalResult[i++];
    370                   styleSheetMessage = undefined;
    371                   if (!topMessage)
    372                       topMessage = result.appendChild("");
    373 
    374                   var totalUnusedRuleLength = 0;
    375                   var ruleSelectors = [];
    376                   for (var j = 0; j < unusedRules.length; ++j) {
    377                       var rule = unusedRules[j];
    378                       totalUnusedRuleLength += parseInt(rule[1]);
    379                       if (!styleSheetMessage)
    380                           styleSheetMessage = result.appendChild("");
    381                       ruleSelectors.push(rule[0]);
    382                   }
    383                   styleSheetMessage.appendChild(WebInspector.AuditRules.arrayAsUL(ruleSelectors));
    384 
    385                   styleSheetMessage.value = self._getUnusedStylesheetRatioMessage(totalUnusedRuleLength, type, location, styleSheetLength);
    386                   totalUnusedLength += totalUnusedRuleLength;
    387               }
    388               if (totalUnusedLength) {
    389                   var totalUnusedPercent = totalUnusedLength / totalLength;
    390                   topMessage.value = self._getUnusedTotalRatioMessage(totalUnusedLength, totalLength);
    391                   var pctMultiplier = Math.log(Math.max(200, totalUnusedLength - 800)) / 7 - 0.6;
    392                   result.score = (1 - totalUnusedPercent * pctMultiplier) * 100;
    393                   result.type = WebInspector.AuditRuleResult.Type.Hint;
    394               } else
    395                   result.score = 100;
    396             } catch(e) {
    397                 console.log(e);
    398             } finally {
    399                 callback(result);
    400             }
     281        function evalCallback(routineResult, isException) {
     282            if (isException || !routineResult || !routineResult.styleSheets.length)
     283                return callback(null);
     284
     285            var totalUnusedPercent = Math.round(100 * routineResult.unusedSize / routineResult.totalSize);
     286            var summary = result.addChild(String.sprintf("%d%% of CSS (estimated) is not used by the current page.", totalUnusedPercent), true);
     287
     288            for (var i = 0; i < routineResult.styleSheets.length; ++i) {
     289                var stylesheet = routineResult.styleSheets[i];
     290
     291                var url = stylesheet.type === "href" ? WebInspector.linkifyURL(stylesheet.location) : String.sprintf("Inline block #%s", stylesheet.location);
     292                var pctUnused = Math.round(100 * stylesheet.unusedSize / stylesheet.totalSize);
     293                var entry = summary.addChild(String.sprintf("%s: %d%% (estimated) is not used by the current page.", url, pctUnused));
     294
     295                for (var j = 0; j < stylesheet.unusedRules.length; ++j)
     296                    entry.addSnippet(stylesheet.unusedRules[j]);
     297
     298                result.violationCount += stylesheet.unusedRules.length;
     299            }
     300
     301            callback(result);
    401302        }
    402303
     
    405306            var styleSheets = document.styleSheets;
    406307            if (!styleSheets)
    407                 return {};
    408             var styleSheetToUnusedRules = [];
     308                return false;
     309            var routineResult = { styleSheets: [] };
    409310            var inlineBlockOrdinal = 0;
    410             var totalCSSLength = 0;
     311            var totalStylesheetSize = 0;
     312            var totalUnusedStylesheetSize = 0;
    411313            var pseudoSelectorRegexp = /:hover|:link|:active|:visited|:focus/;
    412314            for (var i = 0; i < styleSheets.length; ++i) {
     
    414316                if (!styleSheet.cssRules)
    415317                    continue;
    416                 var currentStyleSheetSize = 0;
     318                var stylesheetSize = 0;
     319                var unusedStylesheetSize = 0;
    417320                var unusedRules = [];
    418321                for (var curRule = 0; curRule < styleSheet.cssRules.length; ++curRule) {
    419322                    var rule = styleSheet.cssRules[curRule];
    420323                    var textLength = rule.cssText ? rule.cssText.length : 0;
    421                     currentStyleSheetSize += textLength;
    422                     totalCSSLength += textLength;
     324                    stylesheetSize += textLength;
    423325                    if (rule.type !== 1 || rule.selectorText.match(pseudoSelectorRegexp))
    424326                        continue;
     
    426328                    if (nodes && nodes.length)
    427329                        continue;
    428                     unusedRules.push([rule.selectorText, textLength]);
     330                    unusedStylesheetSize += textLength;
     331                    unusedRules.push(rule.selectorText);
    429332                }
     333                totalStylesheetSize += stylesheetSize;
     334                totalUnusedStylesheetSize += unusedStylesheetSize;
     335
    430336                if (unusedRules.length) {
    431                     styleSheetToUnusedRules.push(styleSheet.href ? "href" : "inline");
    432                     styleSheetToUnusedRules.push(currentStyleSheetSize);
    433                     styleSheetToUnusedRules.push(styleSheet.href ? styleSheet.href : ++inlineBlockOrdinal);
    434                     styleSheetToUnusedRules.push(unusedRules);
     337                    var entry = { type: styleSheet.href ? "href" : "inline",
     338                                  totalSize: stylesheetSize,
     339                                  unusedSize: unusedStylesheetSize,
     340                                  location: styleSheet.href ? styleSheet.href : ++inlineBlockOrdinal,
     341                                  unusedRules: unusedRules };
     342                    routineResult.styleSheets.push(entry);
    435343                }
    436344            }
    437             styleSheetToUnusedRules.push("totalLength");
    438             styleSheetToUnusedRules.push(totalCSSLength);
    439             return styleSheetToUnusedRules;
     345            routineResult.totalSize = totalStylesheetSize;
     346            routineResult.unusedSize = totalUnusedStylesheetSize;
     347            return routineResult;
    440348        }
    441349
     
    447355
    448356
    449 WebInspector.AuditRules.CacheControlRule = function(id, name, parametersObject)
    450 {
    451     WebInspector.AuditRule.call(this, id, name, parametersObject);
     357WebInspector.AuditRules.CacheControlRule = function(id, name)
     358{
     359    WebInspector.AuditRule.call(this, id, name);
    452360}
    453361
     
    456364WebInspector.AuditRules.CacheControlRule.prototype = {
    457365
    458     InfoCheck: -1,
    459     FailCheck: 0,
    460     WarningCheck: 1,
    461     SevereCheck: 2,
    462 
    463366    doRun: function(resources, result, callback)
    464367    {
    465         try {
    466             var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(resources);
    467             if (cacheableAndNonCacheableResources[0].length) {
    468                 result.score = 100;
    469                 this.runChecks(cacheableAndNonCacheableResources[0], result);
    470             }
    471             this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
    472         } catch(e) {
    473             console.log(e);
    474         } finally {
    475             callback(result);
    476         }
     368        var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(resources);
     369        if (cacheableAndNonCacheableResources[0].length)
     370            this.runChecks(cacheableAndNonCacheableResources[0], result);
     371        this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
     372
     373        callback(result);
    477374    },
    478375
     
    496393    },
    497394
    498     execCheck: function(messageText, resourceCheckFunction, resources, severity, result)
    499     {
    500         var topMessage;
    501         var failingResources = 0;
     395    execCheck: function(messageText, resourceCheckFunction, resources, result)
     396    {
    502397        var resourceCount = resources.length;
    503         var outputResources = [];
     398        var urls = [];
    504399        for (var i = 0; i < resourceCount; ++i) {
    505             if (resourceCheckFunction.call(this, resources[i])) {
    506                 ++failingResources;
    507                 if (!topMessage)
    508                     topMessage = result.appendChild(messageText);
    509                 outputResources.push(resources[i].url);
    510             }
    511         }
    512         if (topMessage)
    513             topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources, true));
    514         if (failingResources) {
    515             switch (severity) {
    516                 case this.FailCheck:
    517                     result.score = 0;
    518                     result.type = WebInspector.AuditRuleResult.Type.Violation;
    519                     break;
    520                 case this.SevereCheck:
    521                 case this.WarningCheck:
    522                     result.score -= 50 * severity * failingResources / resourceCount;
    523                     result.type = WebInspector.AuditRuleResult.Type.Hint;
    524                     break;
    525             }
    526         }
    527         return topMessage;
     400            if (resourceCheckFunction.call(this, resources[i]))
     401                urls.push(resources[i].url);
     402        }
     403        if (urls.length) {
     404            var entry = result.addChild(messageText, true);
     405            entry.addURLs(urls);
     406            result.violationCount += urls.length;
     407        }
    528408    },
    529409
     
    613493
    614494
    615 WebInspector.AuditRules.BrowserCacheControlRule = function(parametersObject)
    616 {
    617     WebInspector.AuditRules.CacheControlRule.call(this, "http-browsercache", "Leverage browser caching", parametersObject);
     495WebInspector.AuditRules.BrowserCacheControlRule = function()
     496{
     497    WebInspector.AuditRules.CacheControlRule.call(this, "http-browsercache", "Leverage browser caching");
    618498}
    619499
     
    622502    {
    623503        if (resources.length) {
    624             var message = result.appendChild(
    625                 "The following resources are explicitly non-cacheable. Consider making them cacheable if possible:");
    626             var resourceOutput = [];
     504            var entry = result.addChild("The following resources are explicitly non-cacheable. Consider making them cacheable if possible:", true);
     505            result.violationCount += resources.length;
    627506            for (var i = 0; i < resources.length; ++i)
    628                 resourceOutput.push(resources[i].url);
    629             message.appendChild(WebInspector.AuditRules.arrayAsUL(resourceOutput, true));
     507                entry.addURL(resources[i].url);
    630508        }
    631509    },
     
    633511    runChecks: function(resources, result, callback)
    634512    {
    635         this.execCheck(
    636             "The following resources are missing a cache expiration." +
    637             " Resources that do not specify an expiration may not be" +
    638             " cached by browsers:",
    639             this._missingExpirationCheck, resources, this.SevereCheck, result);
    640         this.execCheck(
    641             "The following resources specify a \"Vary\" header that" +
    642             " disables caching in most versions of Internet Explorer:",
    643             this._varyCheck, resources, this.SevereCheck, result);
    644         this.execCheck(
    645             "The following cacheable resources have a short" +
    646             " freshness lifetime:",
    647             this._oneMonthExpirationCheck, resources, this.WarningCheck, result);
     513        this.execCheck("The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:",
     514            this._missingExpirationCheck, resources, result);
     515        this.execCheck("The following resources specify a \"Vary\" header that disables caching in most versions of Internet Explorer:",
     516            this._varyCheck, resources, result);
     517        this.execCheck("The following cacheable resources have a short freshness lifetime:",
     518            this._oneMonthExpirationCheck, resources, result);
    648519
    649520        // Unable to implement the favicon check due to the WebKit limitations.
    650 
    651         this.execCheck(
    652             "To further improve cache hit rate, specify an expiration" +
    653             " one year in the future for the following cacheable" +
    654             " resources:",
    655             this._oneYearExpirationCheck, resources, this.InfoCheck, result);
     521        this.execCheck("To further improve cache hit rate, specify an expiration one year in the future for the following cacheable resources:",
     522            this._oneYearExpirationCheck, resources, result);
    656523    },
    657524
     
    692559
    693560
    694 WebInspector.AuditRules.ProxyCacheControlRule = function(parametersObject) {
    695     WebInspector.AuditRules.CacheControlRule.call(this, "http-proxycache", "Leverage proxy caching", parametersObject);
     561WebInspector.AuditRules.ProxyCacheControlRule = function() {
     562    WebInspector.AuditRules.CacheControlRule.call(this, "http-proxycache", "Leverage proxy caching");
    696563}
    697564
     
    699566    runChecks: function(resources, result, callback)
    700567    {
    701         this.execCheck(
    702             "Resources with a \"?\" in the URL are not cached by most" +
    703             " proxy caching servers:",
    704             this._questionMarkCheck, resources, this.WarningCheck, result);
    705         this.execCheck(
    706             "Consider adding a \"Cache-Control: public\" header to the" +
    707             " following resources:",
    708             this._publicCachingCheck, resources, this.InfoCheck, result);
    709         this.execCheck(
    710             "The following publicly cacheable resources contain" +
    711             " a Set-Cookie header. This security vulnerability" +
    712             " can cause cookies to be shared by multiple users.",
    713             this._setCookieCacheableCheck, resources, this.FailCheck, result);
     568        this.execCheck("Resources with a \"?\" in the URL are not cached by most proxy caching servers:",
     569            this._questionMarkCheck, resources, result);
     570        this.execCheck("Consider adding a \"Cache-Control: public\" header to the following resources:",
     571            this._publicCachingCheck, resources, result);
     572        this.execCheck("The following publicly cacheable resources contain a Set-Cookie header. This security vulnerability can cause cookies to be shared by multiple users.",
     573            this._setCookieCacheableCheck, resources, result);
    714574    },
    715575
     
    736596
    737597
    738 WebInspector.AuditRules.ImageDimensionsRule = function(parametersObject)
    739 {
    740     WebInspector.AuditRule.call(this, "page-imagedims", "Specify image dimensions", parametersObject);
     598WebInspector.AuditRules.ImageDimensionsRule = function()
     599{
     600    WebInspector.AuditRule.call(this, "page-imagedims", "Specify image dimensions");
    741601}
    742602
     
    746606        function evalCallback(evalResult, isException)
    747607        {
    748             try {
    749                 if (isException)
    750                     return;
    751                 if (!evalResult || !evalResult.totalImages)
    752                     return;
    753                 result.score = 100;
    754                 var topMessage = result.appendChild(
    755                     "A width and height should be specified for all images in order to " +
    756                     "speed up page display. The following image(s) are missing a width and/or height:");
    757                 var map = evalResult.map;
    758                 var outputResources = [];
    759                 for (var url in map) {
    760                     var value = WebInspector.linkifyURL(url);
    761                     if (map[url] > 1)
    762                         value += " (" + map[url] + " uses)";
    763                     outputResources.push(value);
    764                     result.score -= this.getValue("ScorePerImageUse") * map[url];
    765                     result.type = WebInspector.AuditRuleResult.Type.Hint;
    766                 }
    767                 topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources));
    768             } catch(e) {
    769                 console.log(e);
    770             } finally {
    771                 callback(result);
    772             }
     608            if (isException || !evalResult || !evalResult.totalImages)
     609                return callback(null);
     610
     611            var entry = result.addChild("A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:", true);
     612            var map = evalResult.map;
     613            for (var url in map) {
     614                var value = WebInspector.linkifyURL(url);
     615                if (map[url] > 1)
     616                    value += " (" + map[url] + " uses)";
     617                entry.addChild(value);
     618                result.violationCount++;
     619            }
     620            callback(result);
    773621        }
    774622
     
    829677
    830678
    831 WebInspector.AuditRules.CssInHeadRule = function(parametersObject)
    832 {
    833     WebInspector.AuditRule.call(this, "page-cssinhead", "Put CSS in the document head", parametersObject);
     679WebInspector.AuditRules.CssInHeadRule = function()
     680{
     681    WebInspector.AuditRule.call(this, "page-cssinhead", "Put CSS in the document head");
    834682}
    835683
     
    839687        function evalCallback(evalResult, isException)
    840688        {
    841             try {
    842                 if (isException)
    843                     return;
    844                 if (!evalResult)
    845                     return;
    846                 result.score = 100;
    847                 var outputMessages = [];
    848                 for (var url in evalResult) {
    849                     var urlViolations = evalResult[url];
    850                     var topMessage = result.appendChild(
    851                         String.sprintf("CSS in the %s document body adversely impacts rendering performance.",
    852                         WebInspector.linkifyURL(url)));
    853                     if (urlViolations[0]) {
    854                         outputMessages.push(
    855                             String.sprintf("%s style block(s) in the body should be moved to the document head.", urlViolations[0]));
    856                         result.score -= this.getValue("InlineURLScore") * urlViolations[0];
    857                     }
    858                     for (var i = 0; i < urlViolations[1].length; ++i) {
    859                         outputMessages.push(
    860                             String.sprintf("Link node %s should be moved to the document head", WebInspector.linkifyURL(urlViolations[1])));
    861                     }
    862                     result.score -= this.getValue("InlineStylesheetScore") * urlViolations[1];
    863                     result.type = WebInspector.AuditRuleResult.Type.Hint;
    864                 }
    865                 topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputMessages));
    866             } catch(e) {
    867                 console.log(e);
    868             } finally {
    869                 callback(result);
    870             }
     689            if (isException || !evalResult)
     690                return callback(null);
     691
     692            var summary = result.addChild("");
     693
     694            var outputMessages = [];
     695            for (var url in evalResult) {
     696                var urlViolations = evalResult[url];
     697                if (urlViolations[0])
     698                    result.addChild(String.sprintf("%s style block(s) in the %s body should be moved to the document head.", urlViolations[0], WebInspector.linkifyURL(url)));
     699                for (var i = 0; i < urlViolations[1].length; ++i)
     700                    result.addChild(String.sprintf("Link node %s should be moved to the document head in %s", WebInspector.linkifyURL(urlViolations[1])), WebInspector.linkifyURL(url));
     701                result.violationCount += urlViolations.length;
     702            }
     703            summary.value = String.sprintf("CSS in the document body adversely impacts rendering performance.");
     704            callback(result);
    871705        }
    872706
     
    892726            var found = false;
    893727            for (var i = 0; i < views.length; ++i) {
    894               var view = views[i];
    895               if (!view.document)
    896                   continue;
    897 
    898               var inlineStyles = view.document.querySelectorAll("body style");
    899               var inlineStylesheets = view.document.querySelectorAll(
    900                   "body link[rel~='stylesheet'][href]");
    901               if (!inlineStyles.length && !inlineStylesheets.length)
    902                   continue;
    903 
    904               found = true;
    905               var inlineStylesheetHrefs = [];
    906               for (var j = 0; j < inlineStylesheets.length; ++j)
    907                   inlineStylesheetHrefs.push(inlineStylesheets[j].href);
    908 
    909               urlToViolationsArray[view.location.href] =
    910                   [inlineStyles.length, inlineStylesheetHrefs];
     728                var view = views[i];
     729                if (!view.document)
     730                    continue;
     731
     732                var inlineStyles = view.document.querySelectorAll("body style");
     733                var inlineStylesheets = view.document.querySelectorAll("body link[rel~='stylesheet'][href]");
     734                if (!inlineStyles.length && !inlineStylesheets.length)
     735                    continue;
     736
     737                found = true;
     738                var inlineStylesheetHrefs = [];
     739                for (var j = 0; j < inlineStylesheets.length; ++j)
     740                    inlineStylesheetHrefs.push(inlineStylesheets[j].href);
     741                urlToViolationsArray[view.location.href] = [inlineStyles.length, inlineStylesheetHrefs];
    911742            }
    912743            return found ? urlToViolationsArray : null;
     
    920751
    921752
    922 WebInspector.AuditRules.StylesScriptsOrderRule = function(parametersObject)
    923 {
    924     WebInspector.AuditRule.call(this, "page-stylescriptorder", "Optimize the order of styles and scripts", parametersObject);
     753WebInspector.AuditRules.StylesScriptsOrderRule = function()
     754{
     755    WebInspector.AuditRule.call(this, "page-stylescriptorder", "Optimize the order of styles and scripts");
    925756}
    926757
     
    928759    doRun: function(resources, result, callback)
    929760    {
    930         function evalCallback(evalResult, isException)
    931         {
    932             try {
    933                 if (isException)
    934                     return;
    935                 if (!evalResult)
    936                     return;
    937 
    938                 result.score = 100;
    939                 var lateCssUrls = evalResult['late'];
    940                 if (lateCssUrls) {
    941                     var lateMessage = result.appendChild(
    942                         'The following external CSS files were included after ' +
    943                         'an external JavaScript file in the document head. To ' +
    944                         'ensure CSS files are downloaded in parallel, always ' +
    945                         'include external CSS before external JavaScript.');
    946                     lateMessage.appendChild(WebInspector.AuditRules.arrayAsUL(lateCssUrls, true));
    947                     result.score -= this.getValue("InlineBetweenResourcesScore") * lateCssUrls.length;
    948                     result.type = WebInspector.AuditRuleResult.Type.Violation;
    949                 }
    950                 if (evalResult['cssBeforeInlineCount']) {
    951                   var count = evalResult['cssBeforeInlineCount'];
    952                   result.appendChild(count + ' inline script block' +
    953                       (count > 1 ? 's were' : ' was') + ' found in the head between an ' +
    954                       'external CSS file and another resource. To allow parallel ' +
    955                       'downloading, move the inline script before the external CSS ' +
    956                       'file, or after the next resource.');
    957                   result.score -= this.getValue("CSSAfterJSURLScore") * count;
    958                   result.type = WebInspector.AuditRuleResult.Type.Violation;
    959                 }
    960             } catch(e) {
    961                 console.log(e);
    962             } finally {
    963                 callback(result);
    964             }
     761        function evalCallback(resultValue, isException)
     762        {
     763            if (isException || !resultValue)
     764                return callback(null);
     765
     766            var lateCssUrls = resultValue[0];
     767            var cssBeforeInlineCount = resultValue[1];
     768
     769            var entry = result.addChild("The following external CSS files were included after an external JavaScript file in the document head. To ensure CSS files are downloaded in parallel, always include external CSS before external JavaScript.", true);
     770            entry.addURLs(lateCssUrls);
     771            result.violationCount += lateCssUrls.length;
     772
     773            if (cssBeforeInlineCount) {
     774                result.addChild(String.sprintf(" %d inline script block%s found in the head between an external CSS file and another resource. To allow parallel downloading, move the inline script before the external CSS file, or after the next resource.", cssBeforeInlineCount, cssBeforeInlineCount > 1 ? "s were" : " was"));
     775                result.violationCount += cssBeforeInlineCount;
     776            }
     777            callback(result);
    965778        }
    966779
    967780        function routine()
    968781        {
    969             var lateStyles = document.querySelectorAll(
    970                 "head script[src] ~ link[rel~='stylesheet'][href]");
    971             var stylesBeforeInlineScript = document.querySelectorAll(
    972                 "head link[rel~='stylesheet'][href] ~ script:not([src])");
    973 
    974             var resultObject;
    975             if (!lateStyles.length && !stylesBeforeInlineScript.length)
    976                 resultObject = null;
    977             else {
    978                 resultObject = {};
    979                 if (lateStyles.length) {
    980                   lateStyleUrls = [];
    981                   for (var i = 0; i < lateStyles.length; ++i)
    982                       lateStyleUrls.push(lateStyles[i].href);
    983                   resultObject["late"] = lateStyleUrls;
    984                 }
    985                 resultObject["cssBeforeInlineCount"] = stylesBeforeInlineScript.length;
    986             }
    987             return resultObject;
     782            var lateStyles = document.querySelectorAll("head script[src] ~ link[rel~='stylesheet'][href]");
     783            var cssBeforeInlineCount = document.querySelectorAll("head link[rel~='stylesheet'][href] ~ script:not([src])").length;
     784            if (!lateStyles.length && !cssBeforeInlineCount)
     785                return null;
     786
     787            var lateStyleUrls = [];
     788            for (var i = 0; i < lateStyles.length; ++i)
     789                lateStyleUrls.push(lateStyles[i].href);
     790            return [ lateStyleUrls, cssBeforeInlineCount ];
    988791        }
    989792
     
    995798
    996799
    997 WebInspector.AuditRules.CookieRuleBase = function(id, name, parametersObject)
    998 {
    999     WebInspector.AuditRule.call(this, id, name, parametersObject);
     800WebInspector.AuditRules.CookieRuleBase = function(id, name)
     801{
     802    WebInspector.AuditRule.call(this, id, name);
    1000803}
    1001804
     
    1005808        var self = this;
    1006809        function resultCallback(receivedCookies, isAdvanced) {
    1007             try {
    1008                 self.processCookies(isAdvanced ? receivedCookies : [], resources, result);
    1009             } catch(e) {
    1010                 console.log(e);
    1011             } finally {
    1012                 callback(result);
    1013             }
     810            self.processCookies(isAdvanced ? receivedCookies : [], resources, result);
     811            callback(result);
    1014812        }
    1015813        WebInspector.Cookies.getCookiesAsync(resultCallback);
     
    1040838
    1041839
    1042 WebInspector.AuditRules.CookieSizeRule = function(parametersObject)
    1043 {
    1044     WebInspector.AuditRules.CookieRuleBase.call(this, "http-cookiesize", "Minimize cookie size", parametersObject);
     840WebInspector.AuditRules.CookieSizeRule = function(avgBytesThreshold)
     841{
     842    WebInspector.AuditRules.CookieRuleBase.call(this, "http-cookiesize", "Minimize cookie size");
     843    this._avgBytesThreshold = avgBytesThreshold;
     844    this._maxBytesThreshold = 1000;
    1045845}
    1046846
     
    1098898        this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback.bind(this));
    1099899
    1100         result.score = 100;
    1101900        for (var resourceDomain in cookiesPerResourceDomain) {
    1102901            var cookies = cookiesPerResourceDomain[resourceDomain];
     
    1112911        sortedCookieSizes.sort(maxSizeSorter);
    1113912
    1114         var maxBytesThreshold = this.getValue("MaxBytesThreshold");
    1115         var minBytesThreshold = this.getValue("MinBytesThreshold");
    1116 
    1117913        for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
    1118914            var maxCookieSize = sortedCookieSizes[i].maxCookieSize;
    1119             if (maxCookieSize > maxBytesThreshold)
     915            if (maxCookieSize > this._maxBytesThreshold)
    1120916                hugeCookieDomains.push(sortedCookieSizes[i].domain + ": " + Number.bytesToString(maxCookieSize));
    1121917        }
     
    1126922            var domain = sortedCookieSizes[i].domain;
    1127923            var avgCookieSize = sortedCookieSizes[i].avgCookieSize;
    1128             if (avgCookieSize > minBytesThreshold && avgCookieSize < maxBytesThreshold)
     924            if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBytesThreshold)
    1129925                bigAvgCookieDomains.push(domain + ": " + Number.bytesToString(avgCookieSize));
    1130926        }
    1131         result.appendChild("The average cookie size for all requests on this page is " + Number.bytesToString(avgAllCookiesSize));
     927        result.addChild(String.sprintf("The average cookie size for all requests on this page is %s", Number.bytesToString(avgAllCookiesSize)));
    1132928
    1133929        var message;
    1134930        if (hugeCookieDomains.length) {
    1135             result.score = 75;
    1136             result.type = WebInspector.AuditRuleResult.Type.Violation;
    1137             message = result.appendChild(
    1138                 String.sprintf("The following domains have a cookie size in excess of %d " +
    1139                 " bytes. This is harmful because requests with cookies larger than 1KB" +
    1140                 " typically cannot fit into a single network packet.", maxBytesThreshold));
    1141             message.appendChild(WebInspector.AuditRules.arrayAsUL(hugeCookieDomains));
     931            var entry = result.addChild("The following domains have a cookie size in excess of 1KB. This is harmful because requests with cookies larger than 1KB typically cannot fit into a single network packet.", true);
     932            entry.addURLs(hugeCookieDomains);
     933            result.violationCount += hugeCookieDomains.length;
    1142934        }
    1143935
    1144936        if (bigAvgCookieDomains.length) {
    1145             this.score -= Math.max(0, avgAllCookiesSize - minBytesThreshold) /
    1146                 (minBytesThreshold - minBytesThreshold) / this.getValue("TotalPoints");
    1147             if (!result.type)
    1148                 result.type = WebInspector.AuditRuleResult.Type.Hint;
    1149             message = result.appendChild(
    1150                 String.sprintf("The following domains have an average cookie size in excess of %d" +
    1151                  " bytes. Reducing the size of cookies" +
    1152                  " for these domains can reduce the time it takes to send requests.", minBytesThreshold));
    1153             message.appendChild(WebInspector.AuditRules.arrayAsUL(bigAvgCookieDomains));
    1154         }
    1155 
    1156         if (!bigAvgCookieDomains.length && !hugeCookieDomains.length)
    1157             result.score = WebInspector.AuditCategoryResult.ScoreNA;
     937            var entry = result.addChild(String.sprintf("The following domains have an average cookie size in excess of %d bytes. Reducing the size of cookies for these domains can reduce the time it takes to send requests.", this._avgBytesThreshold), true);
     938            entry.addURLs(bigAvgCookieDomains.length);
     939            result.violationCount += bigAvgCookieDomains.length;
     940        }
    1158941    }
    1159942}
     
    1162945
    1163946
    1164 WebInspector.AuditRules.StaticCookielessRule = function(parametersObject)
    1165 {
    1166     WebInspector.AuditRules.CookieRuleBase.call(this, "http-staticcookieless", "Serve static content from a cookieless domain", parametersObject);
     947WebInspector.AuditRules.StaticCookielessRule = function(minResources)
     948{
     949    WebInspector.AuditRules.CookieRuleBase.call(this, "http-staticcookieless", "Serve static content from a cookieless domain");
     950    this._minResources = minResources;
    1167951}
    1168952
     
    1176960                true);
    1177961        var totalStaticResources = 0;
    1178         var minResources = this.getValue("MinResources");
    1179962        for (var domain in domainToResourcesMap)
    1180963            totalStaticResources += domainToResourcesMap[domain].length;
    1181         if (totalStaticResources < minResources)
     964        if (totalStaticResources < this._minResources)
    1182965            return;
    1183966        var matchingResourceData = {};
     
    1190973            cookieBytes += matchingResourceData[url]
    1191974        }
    1192         if (badUrls.length < minResources)
     975        if (badUrls.length < this._minResources)
    1193976            return;
    1194977
    1195         result.score = 100;
    1196         var badPoints = cookieBytes / 75;
    1197         var violationPct = Math.max(badUrls.length / totalStaticResources, 0.6);
    1198         badPoints *= violationPct;
    1199         result.score -= badPoints;
    1200         result.score = Math.max(result.score, 0);
    1201         result.type = WebInspector.AuditRuleResult.Type.Violation;
    1202         result.appendChild(String.sprintf("%s of cookies were sent with the following static resources.", Number.bytesToString(cookieBytes)));
    1203         var message = result.appendChild("Serve these static resources from a domain that does not set cookies:");
    1204         message.appendChild(WebInspector.AuditRules.arrayAsUL(badUrls, true));
     978        var entry = result.addChild(String.sprintf("%s of cookies were sent with the following static resources. Serve these static resources from a domain that does not set cookies:", Number.bytesToString(cookieBytes)), true);
     979        entry.addURLs(badUrls);
     980        result.violationCount = badUrls.length;
    1205981    },
    1206982
  • trunk/WebCore/inspector/front-end/AuditsPanel.js

    r55535 r55727  
    3838    this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
    3939    this.sidebarTree.appendChild(this.auditsTreeElement);
     40    this.auditsTreeElement.listItemElement.addStyleClass("hidden");
    4041    this.auditsTreeElement.expand();
    4142
     
    5556    this.viewsContainerElement.id = "audit-views";
    5657    this.element.appendChild(this.viewsContainerElement);
     58
     59    this._launcherView = new WebInspector.AuditLauncherView(this.categoriesById, this.initiateAudit.bind(this));
    5760}
    5861
     
    9497    {
    9598        return this._auditCategoriesById;
    96     },
    97 
    98     get visibleView()
    99     {
    100         return this._visibleView;
    10199    },
    102100
     
    126124        function ruleResultReadyCallback(categoryResult, ruleResult)
    127125        {
    128             if (ruleResult.children)
    129                 categoryResult.entries.push(ruleResult);
     126            if (ruleResult && ruleResult.children)
     127                categoryResult.addRuleResult(ruleResult);
    130128
    131129            --rulesRemaining;
     
    193191            this._updateLauncherViewControls(true);
    194192        } else
    195             InjectedScriptAccess.getDefault().evaluate("window.location.reload()", switchCallback);
     193            InspectorBackend.reloadPage();
    196194    },
    197195
     
    200198        if (this._resourceTrackingCallback) {
    201199            var callback = this._resourceTrackingCallback;
    202             this._resourceTrackingCallback = null;
     200            delete this._resourceTrackingCallback;
    203201            callback();
    204202        }
     
    210208            categoryResults._resultView = new WebInspector.AuditResultView(categoryResults);
    211209
    212         this.showView(categoryResults._resultView);
     210        this.visibleView = categoryResults._resultView;
    213211    },
    214212
    215213    showLauncherView: function()
    216214    {
    217         if (!this._launcherView)
    218             this._launcherView = new WebInspector.AuditLauncherView(this.categoriesById, this.initiateAudit.bind(this));
    219 
    220         this.showView(this._launcherView);
    221     },
    222 
    223     showView: function(view)
    224     {
    225         if (view) {
    226             if (this._visibleView === view)
    227                 return;
    228             this._closeVisibleView();
    229             this._visibleView = view;
    230         }
    231         var visibleView = this.visibleView;
    232         if (visibleView)
    233             visibleView.show(this.viewsContainerElement);
     215        this.visibleView = this._launcherView;
     216    },
     217   
     218    get visibleView()
     219    {
     220        return this._visibleView;
     221    },
     222
     223    set visibleView(x)
     224    {
     225        if (this._visibleView === x)
     226            return;
     227
     228        if (this._visibleView)
     229            this._visibleView.hide();
     230
     231        this._visibleView = x;
     232
     233        if (x)
     234            x.show(this.viewsContainerElement);
    234235    },
    235236
     
    237238    {
    238239        WebInspector.Panel.prototype.show.call(this);
    239 
    240         this.showView();
    241240        this._updateLauncherViewControls(WebInspector.panels.resources.resourceTrackingEnabled);
    242241    },
     
    265264        this.auditsItemTreeElement.select();
    266265        this.auditResultsTreeElement.removeChildren();
    267     },
    268 
    269     _closeVisibleView: function()
    270     {
    271         if (this.visibleView)
    272             this.visibleView.hide();
    273266    }
    274267}
     
    302295    },
    303296
    304     addRule: function(rule)
    305     {
     297    addRule: function(rule, severity)
     298    {
     299        rule.severity = severity;
    306300        this._rules.push(rule);
    307301    },
     
    325319
    326320
    327 WebInspector.AuditRule = function(id, displayName, parametersObject)
     321WebInspector.AuditRule = function(id, displayName)
    328322{
    329323    this._id = id;
    330324    this._displayName = displayName;
    331     this._parametersObject = parametersObject;
     325}
     326
     327WebInspector.AuditRule.Severity = {
     328    Info: "info",
     329    Warning: "warning",
     330    Severe: "severe"
    332331}
    333332
     
    343342    },
    344343
     344    set severity(severity)
     345    {
     346        this._severity = severity;
     347    },
     348
    345349    run: function(resources, callback)
    346350    {
    347         this.doRun(resources, new WebInspector.AuditRuleResult(this.displayName), callback);
     351        var result = new WebInspector.AuditRuleResult(this.displayName);
     352        result.severity = this._severity;
     353        this.doRun(resources, result, callback);
    348354    },
    349355
     
    351357    {
    352358        throw new Error("doRun() not implemented");
    353     },
    354 
    355     getValue: function(key)
    356     {
    357         if (key in this._parametersObject)
    358             return this._parametersObject[key];
    359         else
    360             throw new Error(key + " not found in rule parameters");
    361     }
    362 }
    363 
     359    }
     360}
    364361
    365362WebInspector.AuditCategoryResult = function(category)
    366363{
    367364    this.title = category.displayName;
    368     this.entries = [];
     365    this.ruleResults = [];
    369366}
    370367
    371368WebInspector.AuditCategoryResult.prototype = {
    372     addEntry: function(value)
    373     {
    374         var entry = new WebInspector.AuditRuleResult(value);
    375         this.entries.push(entry);
    376         return entry;
    377     }
    378 }
    379 
    380 /**
    381  * @param {string} value The result message HTML contents.
    382  */
    383 WebInspector.AuditRuleResult = function(value)
     369    addRuleResult: function(ruleResult)
     370    {
     371        this.ruleResults.push(ruleResult);
     372    }
     373}
     374
     375WebInspector.AuditRuleResult = function(value, expanded, className)
    384376{
    385377    this.value = value;
    386     this.type = WebInspector.AuditRuleResult.Type.NA;
    387 }
    388 
    389 WebInspector.AuditRuleResult.Type = {
    390     // Does not denote a discovered flaw but rather represents an informational message.
    391     NA: 0,
    392 
    393     // Denotes a minor impact on the checked metric.
    394     Hint: 1,
    395 
    396     // Denotes a major impact on the checked metric.
    397     Violation: 2
     378    this.className = className;
     379    this.expanded = expanded;
     380    this.violationCount = 0;
    398381}
    399382
    400383WebInspector.AuditRuleResult.prototype = {
    401     appendChild: function(value)
     384    addChild: function(value, expanded, className)
    402385    {
    403386        if (!this.children)
    404387            this.children = [];
    405         var entry = new WebInspector.AuditRuleResult(value);
     388        var entry = new WebInspector.AuditRuleResult(value, expanded, className);
    406389        this.children.push(entry);
    407390        return entry;
    408391    },
    409392
    410     set type(x)
    411     {
    412         this._type = x;
    413     },
    414 
    415     get type()
    416     {
    417         return this._type;
    418     }
    419 }
    420 
     393    addURL: function(url)
     394    {
     395        return this.addChild(WebInspector.linkifyURL(url));
     396    },
     397
     398    addURLs: function(urls)
     399    {
     400        for (var i = 0; i < urls.length; ++i)
     401            this.addURL(urls[i]);
     402    },
     403
     404    addSnippet: function(snippet)
     405    {
     406        return this.addChild(snippet, false, "source-code");
     407    }
     408}
    421409
    422410WebInspector.AuditsSidebarTreeElement = function()
  • trunk/WebCore/inspector/front-end/Settings.js

    r55464 r55727  
    4141    showColorNicknames: true,
    4242    debuggerAlwaysEnabled: false,
    43     profilerAlwaysEnabled: false
     43    profilerAlwaysEnabled: false,
     44    auditsPanelEnabled: false
    4445}
    4546
  • trunk/WebCore/inspector/front-end/audits.css

    r54591 r55727  
    5151}
    5252
    53 #audit-result-view {
    54     display: none;
    55     overflow: auto;
    56     position: absolute;
    57     top: 0;
    58     left: 0;
    59     right: 0;
    60     bottom: 0;
    61     background-color: rgb(245, 245, 245);
    62     cursor: default;
    63     overflow: auto;
    64 }
    65 
    66 #audit-result-view.visible {
    67     display: block;
    68 }
    69 
    70 #audit-result-view > .pane img.score {
    71     float: left;
    72     margin-top: 2px;
    73     position: relative;
    74     height: 16px;
    75     width: 16px;
    76     z-index: 100;
    77 }
    78 
    79 #audit-result-view > .pane img.score.red {
    80     content: url(Images/errorRedDot.png);
    81 }
    82 
    83 #audit-result-view > .pane img.score.green {
    84     content: url(Images/successGreenDot.png);
    85 }
    86 
    87 #audit-result-view > .pane.expanded:nth-last-of-type(1) {
    88     border-bottom: 1px solid rgb(189, 189, 189) !important;
    89 }
    90 
    91 #audit-result-view .pane.expanded:nth-last-of-type(1) {
    92     border-bottom: 0px transparent none;
    93 }
    94 
    95 #audit-result-view > .pane > .body > .pane > .title {
    96     padding-left: 16px;
    97     background-image: none;
    98     border-bottom: none;
    99 }
    100 
    101 #audit-result-view > .pane > .body > .pane > .body {
    102     background-color: transparent;
    103 }
    104 
    105 #audit-result-view > .pane > .body > .pane .section {
    106     margin-left: 16px;
    107 }
    108 
    109 #audit-result-view .section .header {
    110     border: 0;
    111     background-image: none;
    112     background-color: transparent;
    113 }
    114 
    115 #audit-result-view .section .header > .title {
    116     color: rgb(0, 0, 0);
    117 }
    118 
    119 #audit-result-view .section .section-content {
    120     width: 100%;
    121     padding-left: 18px;
    122     display: none;
    123 }
    124 
    125 #audit-result-view .section.expanded .section-content {
    126     display: block;
    127 }
    128 
    129 #audit-result-view .section.expanded .section-content > p:nth-of-type(1) {
    130     margin-top: 0;
    131 }
    132 
    133 #audit-result-view .section.expanded .section-content > p:nth-of-type(1) > *:nth-child(1) {
    134     margin-top: 0;
    135 }
    136 
    137 #audit-result-view .section .header::before {
    138     content: url(Images/treeRightTriangleBlack.png);
    139 }
    140 
    141 #audit-result-view .section.expanded .header::before {
    142     content: url(Images/treeDownTriangleBlack.png);
    143 }
    144 
    145 div.panel.audits .sidebar > ol.sidebar-tree > li:nth-child(1) {
    146     height: 0px;
    147     padding-top: 0;
    148     padding-bottom: 0;
    149 }
    150 
    15153.audit-launcher-view {
    15254    z-index: 1000;
     
    271173                -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)));
    272174}
     175
     176.audit-result-view {
     177    overflow: auto;
     178    position: absolute;
     179    top: 0;
     180    left: 0;
     181    right: 0;
     182    bottom: 0;
     183    display: none;
     184}
     185
     186.audit-result-view.visible {
     187    display: block;
     188}
     189
     190.audit-result-view .severity-severe {
     191    content: url(Images/errorRedDot.png);
     192}
     193
     194.audit-result-view .severity-warning {
     195    content: url(Images/warningOrangeDot.png);
     196}
     197
     198.audit-result-view .severity-info {
     199    content: url(Images/successGreenDot.png);
     200}
     201
     202.audit-result-tree li.parent::before {
     203    content: url(Images/treeRightTriangleBlack.png);
     204    float: left;
     205    width: 8px;
     206    height: 8px;
     207    margin-top: 1px;
     208    padding-right: 2px;
     209}
     210
     211.audit-result-tree {
     212    font-size: 11px;
     213    line-height: 14px;
     214}
     215
     216.audit-result-tree > ol {
     217    position: relative;
     218    padding: 2px 6px !important;
     219    margin: 0;
     220    color: rgb(84, 84, 84);
     221    cursor: default;
     222    min-width: 100%;
     223}
     224
     225.audit-result-tree, .audit-result-tree ol {
     226    list-style-type: none;
     227    -webkit-padding-start: 12px;
     228    margin: 0;
     229}
     230
     231.audit-result-tree li {
     232    padding: 0 0 0 14px;
     233    margin-top: 1px;
     234    margin-bottom: 1px;
     235    word-wrap: break-word;
     236    text-indent: -2px;
     237}
     238
     239.audit-result-tree li.parent {
     240    text-indent: -12px
     241}
     242
     243.audit-result-tree li.parent::before {
     244    content: url(Images/treeRightTriangleBlack.png);
     245    float: left;
     246    width: 8px;
     247    height: 8px;
     248    margin-top: 0;
     249    padding-right: 2px;
     250}
     251
     252.audit-result-tree li.parent.expanded::before {
     253    content: url(Images/treeDownTriangleBlack.png);
     254}
     255
     256.audit-result-tree ol.children {
     257    display: none;
     258}
     259
     260.audit-result-tree ol.children.expanded {
     261    display: block;
     262}
     263
     264.audit-result {
     265    font-weight: bold;
     266    color: black;
     267}
     268
     269.audit-result img {
     270    float: left;
     271    margin-left: -40px;
     272    margin-top: -1px;
     273}
  • trunk/WebCore/inspector/front-end/inspector.js

    r55575 r55727  
    211211            this.panels.profiles.registerProfileType(new WebInspector.CPUProfileType());
    212212        }
    213 
    214213        if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("databases") === -1)
    215214            this.panels.storage = new WebInspector.StoragePanel();
    216 
    217         // FIXME: Uncomment when ready.
    218         // if (hiddenPanels.indexOf("audits") === -1)
    219         //    this.panels.audits = new WebInspector.AuditsPanel();
    220 
     215        if (Preferences.auditsPanelEnabled && hiddenPanels.indexOf("audits") === -1)
     216            this.panels.audits = new WebInspector.AuditsPanel();
    221217        if (hiddenPanels.indexOf("console") === -1)
    222218            this.panels.console = new WebInspector.ConsolePanel();
     
    783779            break;
    784780
    785         case "U+0041": // A key
    786             if (isMac)
    787                 var shouldShowAuditsPanel = event.metaKey && !event.shiftKey && !event.ctrlKey && event.altKey;
    788             else
    789                 var shouldShowAuditsPanel = event.ctrlKey && !event.shiftKey && !event.metaKey && event.altKey;
    790 
    791             if (shouldShowAuditsPanel) {
    792                 if (!this.panels.audits) {
    793                     this.panels.audits = new WebInspector.AuditsPanel();
    794                     var toolbarElement = document.getElementById("toolbar");
    795                     WebInspector.addPanelToolbarIcon(toolbarElement, this.panels.audits, this.panels.console.toolbarItem);
    796                 }
    797                 this.currentPanel = this.panels.audits;
    798             }
    799 
    800             break;
    801781        case "U+0052": // R key
    802782            if ((event.metaKey && isMac) || (event.ctrlKey && !isMac))
Note: See TracChangeset for help on using the changeset viewer.