2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 WebInspector.AuditsPanel = function()
33 WebInspector.Panel.call(this, "audits");
36 this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
37 this.sidebarTree.appendChild(this.auditsTreeElement);
38 this.auditsTreeElement.listItemElement.addStyleClass("hidden");
39 this.auditsTreeElement.expand();
41 this.auditsItemTreeElement = new WebInspector.AuditsSidebarTreeElement();
42 this.auditsTreeElement.appendChild(this.auditsItemTreeElement);
44 this.auditResultsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RESULTS"), {}, true);
45 this.sidebarTree.appendChild(this.auditResultsTreeElement);
46 this.auditResultsTreeElement.expand();
48 this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear audit results."), "clear-status-bar-item");
49 this.clearResultsButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
51 this.viewsContainerElement = document.createElement("div");
52 this.viewsContainerElement.id = "audit-views";
53 this.element.appendChild(this.viewsContainerElement);
55 this._constructCategories();
57 this._launcherView = new WebInspector.AuditLauncherView(this.initiateAudit.bind(this));
58 for (id in this.categoriesById)
59 this._launcherView.addCategory(this.categoriesById[id]);
62 WebInspector.AuditsPanel.prototype = {
63 get toolbarItemLabel()
65 return WebInspector.UIString("Audits");
70 return [this.clearResultsButton.element];
73 get mainResourceLoadTime()
75 return this._mainResourceLoadTime;
78 set mainResourceLoadTime(x)
80 this._mainResourceLoadTime = x;
81 this._didMainResourceLoad();
84 get mainResourceDOMContentTime()
86 return this._mainResourceDOMContentTime;
89 set mainResourceDOMContentTime(x)
91 this._mainResourceDOMContentTime = x;
96 return this._auditCategoriesById;
99 addCategory: function(category)
101 this.categoriesById[category.id] = category;
102 this._launcherView.addCategory(category);
105 getCategory: function(id)
107 return this.categoriesById[id];
110 _constructCategories: function()
112 this._auditCategoriesById = {};
113 for (var categoryCtorID in WebInspector.AuditCategories) {
114 var auditCategory = new WebInspector.AuditCategories[categoryCtorID]();
115 auditCategory._id = categoryCtorID;
116 this.categoriesById[categoryCtorID] = auditCategory;
120 _executeAudit: function(categories, resultCallback)
122 var resources = WebInspector.networkResources;
124 var rulesRemaining = 0;
125 for (var i = 0; i < categories.length; ++i)
126 rulesRemaining += categories[i].ruleCount;
129 var mainResourceURL = WebInspector.mainResource.url;
131 function ruleResultReadyCallback(categoryResult, ruleResult)
133 if (ruleResult && ruleResult.children)
134 categoryResult.addRuleResult(ruleResult);
138 if (!rulesRemaining && resultCallback)
139 resultCallback(mainResourceURL, results);
142 if (!rulesRemaining) {
143 resultCallback(mainResourceURL, results);
147 for (var i = 0; i < categories.length; ++i) {
148 var category = categories[i];
149 var result = new WebInspector.AuditCategoryResult(category);
150 results.push(result);
151 category.run(resources, ruleResultReadyCallback.bind(null, result));
155 _auditFinishedCallback: function(launcherCallback, mainResourceURL, results)
157 var children = this.auditResultsTreeElement.children;
159 for (var i = 0; i < children.length; ++i) {
160 if (children[i].mainResourceURL === mainResourceURL)
164 var resultTreeElement = new WebInspector.AuditResultSidebarTreeElement(results, mainResourceURL, ordinal);
165 this.auditResultsTreeElement.appendChild(resultTreeElement);
166 resultTreeElement.reveal();
167 resultTreeElement.select();
168 if (launcherCallback)
172 initiateAudit: function(categoryIds, runImmediately, launcherCallback)
174 if (!categoryIds || !categoryIds.length)
178 for (var i = 0; i < categoryIds.length; ++i)
179 categories.push(this.categoriesById[categoryIds[i]]);
181 function initiateAuditCallback(categories, launcherCallback)
183 this._executeAudit(categories, this._auditFinishedCallback.bind(this, launcherCallback));
187 initiateAuditCallback.call(this, categories, launcherCallback);
189 this._reloadResources(initiateAuditCallback.bind(this, categories, launcherCallback));
192 _reloadResources: function(callback)
194 this._pageReloadCallback = callback;
195 InspectorBackend.reloadPage(false);
198 _didMainResourceLoad: function()
200 if (this._pageReloadCallback) {
201 var callback = this._pageReloadCallback;
202 delete this._pageReloadCallback;
207 showResults: function(categoryResults)
209 if (!categoryResults._resultView)
210 categoryResults._resultView = new WebInspector.AuditResultView(categoryResults);
212 this.visibleView = categoryResults._resultView;
215 showLauncherView: function()
217 this.visibleView = this._launcherView;
222 return this._visibleView;
227 if (this._visibleView === x)
230 if (this._visibleView)
231 this._visibleView.hide();
233 this._visibleView = x;
236 x.show(this.viewsContainerElement);
241 WebInspector.Panel.prototype.attach.call(this);
243 this.auditsItemTreeElement.select();
246 updateMainViewWidth: function(width)
248 this.viewsContainerElement.style.left = width + "px";
251 _clearButtonClicked: function()
253 this.auditsItemTreeElement.reveal();
254 this.auditsItemTreeElement.select();
255 this.auditResultsTreeElement.removeChildren();
259 WebInspector.AuditsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
263 WebInspector.AuditCategory = function(displayName)
265 this._displayName = displayName;
269 WebInspector.AuditCategory.prototype = {
272 // this._id value is injected at construction time.
278 return this._displayName;
283 this._ensureInitialized();
284 return this._rules.length;
287 addRule: function(rule, severity)
289 rule.severity = severity;
290 this._rules.push(rule);
293 run: function(resources, callback)
295 this._ensureInitialized();
296 for (var i = 0; i < this._rules.length; ++i)
297 this._rules[i].run(resources, callback);
300 _ensureInitialized: function()
302 if (!this._initialized) {
303 if ("initialize" in this)
305 this._initialized = true;
311 WebInspector.AuditRule = function(id, displayName)
314 this._displayName = displayName;
317 WebInspector.AuditRule.Severity = {
323 WebInspector.AuditRule.SeverityOrder = {
329 WebInspector.AuditRule.prototype = {
337 return this._displayName;
340 set severity(severity)
342 this._severity = severity;
345 run: function(resources, callback)
347 var result = new WebInspector.AuditRuleResult(this.displayName);
348 result.severity = this._severity;
349 this.doRun(resources, result, callback);
352 doRun: function(resources, result, callback)
354 throw new Error("doRun() not implemented");
358 WebInspector.AuditCategoryResult = function(category)
360 this.title = category.displayName;
361 this.ruleResults = [];
364 WebInspector.AuditCategoryResult.prototype = {
365 addRuleResult: function(ruleResult)
367 this.ruleResults.push(ruleResult);
371 WebInspector.AuditRuleResult = function(value, expanded, className)
374 this.className = className;
375 this.expanded = expanded;
376 this.violationCount = 0;
379 WebInspector.AuditRuleResult.linkifyDisplayName = function(url)
381 return WebInspector.linkifyURL(url, WebInspector.displayNameForURL(url));
384 WebInspector.AuditRuleResult.resourceDomain = function(domain)
386 return domain || WebInspector.UIString("[empty domain]");
389 WebInspector.AuditRuleResult.prototype = {
390 addChild: function(value, expanded, className)
394 var entry = new WebInspector.AuditRuleResult(value, expanded, className);
395 this.children.push(entry);
399 addURL: function(url)
401 return this.addChild(WebInspector.AuditRuleResult.linkifyDisplayName(url));
404 addURLs: function(urls)
406 for (var i = 0; i < urls.length; ++i)
407 this.addURL(urls[i]);
410 addSnippet: function(snippet)
412 return this.addChild(snippet, false, "source-code");
416 WebInspector.AuditsSidebarTreeElement = function()
420 WebInspector.SidebarTreeElement.call(this, "audits-sidebar-tree-item", WebInspector.UIString("Audits"), "", null, false);
423 WebInspector.AuditsSidebarTreeElement.prototype = {
426 WebInspector.SidebarTreeElement.prototype.onattach.call(this);
431 WebInspector.panels.audits.showLauncherView();
441 this.refreshTitles();
445 WebInspector.AuditsSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
448 WebInspector.AuditResultSidebarTreeElement = function(results, mainResourceURL, ordinal)
450 this.results = results;
451 this.mainResourceURL = mainResourceURL;
453 WebInspector.SidebarTreeElement.call(this, "audit-result-sidebar-tree-item", String.sprintf("%s (%d)", mainResourceURL, ordinal), "", {}, false);
456 WebInspector.AuditResultSidebarTreeElement.prototype = {
459 WebInspector.panels.audits.showResults(this.results);
468 WebInspector.AuditResultSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
470 // Contributed audit rules should go into this namespace.
471 WebInspector.AuditRules = {};
473 // Contributed audit categories should go into this namespace.
474 WebInspector.AuditCategories = {};