Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / audits / AuditsPanel.js
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.PanelWithSidebarTree}
34  */
35 WebInspector.AuditsPanel = function()
36 {
37     WebInspector.PanelWithSidebarTree.call(this, "audits");
38     this.registerRequiredCSS("panelEnablerView.css");
39     this.registerRequiredCSS("auditsPanel.css");
40
41     this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
42     this.sidebarTree.appendChild(this.auditsTreeElement);
43     this.auditsTreeElement.listItemElement.classList.add("hidden");
44
45     this.auditsItemTreeElement = new WebInspector.AuditsSidebarTreeElement(this);
46     this.auditsTreeElement.appendChild(this.auditsItemTreeElement);
47
48     this.auditResultsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RESULTS"), {}, true);
49     this.sidebarTree.appendChild(this.auditResultsTreeElement);
50     this.auditResultsTreeElement.expand();
51
52     this._constructCategories();
53
54     this._auditController = new WebInspector.AuditController(this);
55     this._launcherView = new WebInspector.AuditLauncherView(this._auditController);
56     for (var id in this.categoriesById)
57         this._launcherView.addCategory(this.categoriesById[id]);
58 }
59
60 WebInspector.AuditsPanel.prototype = {
61     /**
62      * @return {boolean}
63      */
64     canSearch: function()
65     {
66         return false;
67     },
68
69     /**
70      * @return {!Object.<string, !WebInspector.AuditCategory>}
71      */
72     get categoriesById()
73     {
74         return this._auditCategoriesById;
75     },
76
77     /**
78      * @param {!WebInspector.AuditCategory} category
79      */
80     addCategory: function(category)
81     {
82         this.categoriesById[category.id] = category;
83         this._launcherView.addCategory(category);
84     },
85
86     /**
87      * @param {string} id
88      * @return {!WebInspector.AuditCategory}
89      */
90     getCategory: function(id)
91     {
92         return this.categoriesById[id];
93     },
94
95     _constructCategories: function()
96     {
97         this._auditCategoriesById = {};
98         for (var categoryCtorID in WebInspector.AuditCategories) {
99             var auditCategory = new WebInspector.AuditCategories[categoryCtorID]();
100             auditCategory._id = categoryCtorID;
101             this.categoriesById[categoryCtorID] = auditCategory;
102         }
103     },
104
105     /**
106      * @param {string} mainResourceURL
107      * @param {!Array.<!WebInspector.AuditCategoryResult>} results
108      */
109     auditFinishedCallback: function(mainResourceURL, results)
110     {
111         var children = this.auditResultsTreeElement.children;
112         var ordinal = 1;
113         for (var i = 0; i < children.length; ++i) {
114             if (children[i].mainResourceURL === mainResourceURL)
115                 ordinal++;
116         }
117
118         var resultTreeElement = new WebInspector.AuditResultSidebarTreeElement(this, results, mainResourceURL, ordinal);
119         this.auditResultsTreeElement.appendChild(resultTreeElement);
120         resultTreeElement.revealAndSelect();
121     },
122
123     /**
124      * @param {!Array.<!WebInspector.AuditCategoryResult>} categoryResults
125      */
126     showResults: function(categoryResults)
127     {
128         if (!categoryResults._resultView)
129             categoryResults._resultView = new WebInspector.AuditResultView(categoryResults);
130
131         this.visibleView = categoryResults._resultView;
132     },
133
134     showLauncherView: function()
135     {
136         this.visibleView = this._launcherView;
137     },
138
139     get visibleView()
140     {
141         return this._visibleView;
142     },
143
144     set visibleView(x)
145     {
146         if (this._visibleView === x)
147             return;
148
149         if (this._visibleView)
150             this._visibleView.detach();
151
152         this._visibleView = x;
153
154         if (x)
155             x.show(this.mainElement());
156     },
157
158     wasShown: function()
159     {
160         WebInspector.Panel.prototype.wasShown.call(this);
161         if (!this._visibleView)
162             this.auditsItemTreeElement.select();
163     },
164
165     clearResults: function()
166     {
167         this.auditsItemTreeElement.revealAndSelect();
168         this.auditResultsTreeElement.removeChildren();
169     },
170
171     __proto__: WebInspector.PanelWithSidebarTree.prototype
172 }
173
174 /**
175  * @constructor
176  * @implements {WebInspector.AuditCategory}
177  * @param {string} displayName
178  */
179 WebInspector.AuditCategoryImpl = function(displayName)
180 {
181     this._displayName = displayName;
182     this._rules = [];
183 }
184
185 WebInspector.AuditCategoryImpl.prototype = {
186     /**
187      * @override
188      * @return {string}
189      */
190     get id()
191     {
192         // this._id value is injected at construction time.
193         return this._id;
194     },
195
196     /**
197      * @override
198      * @return {string}
199      */
200     get displayName()
201     {
202         return this._displayName;
203     },
204
205     /**
206      * @param {!WebInspector.AuditRule} rule
207      * @param {!WebInspector.AuditRule.Severity} severity
208      */
209     addRule: function(rule, severity)
210     {
211         rule.severity = severity;
212         this._rules.push(rule);
213     },
214
215     /**
216      * @override
217      * @param {!WebInspector.Target} target
218      * @param {!Array.<!WebInspector.NetworkRequest>} requests
219      * @param {function(!WebInspector.AuditRuleResult)} ruleResultCallback
220      * @param {function()} categoryDoneCallback
221      * @param {!WebInspector.Progress} progress
222      */
223     run: function(target, requests, ruleResultCallback, categoryDoneCallback, progress)
224     {
225         this._ensureInitialized();
226         var remainingRulesCount = this._rules.length;
227         progress.setTotalWork(remainingRulesCount);
228         function callbackWrapper(result)
229         {
230             ruleResultCallback(result);
231             progress.worked();
232             if (!--remainingRulesCount)
233                 categoryDoneCallback();
234         }
235         for (var i = 0; i < this._rules.length; ++i)
236             this._rules[i].run(target, requests, callbackWrapper, progress);
237     },
238
239     _ensureInitialized: function()
240     {
241         if (!this._initialized) {
242             if ("initialize" in this)
243                 this.initialize();
244             this._initialized = true;
245         }
246     }
247 }
248
249 /**
250  * @constructor
251  * @param {string} id
252  * @param {string} displayName
253  */
254 WebInspector.AuditRule = function(id, displayName)
255 {
256     this._id = id;
257     this._displayName = displayName;
258 }
259
260 /**
261  * @enum {string}
262  */
263 WebInspector.AuditRule.Severity = {
264     Info: "info",
265     Warning: "warning",
266     Severe: "severe"
267 }
268
269 WebInspector.AuditRule.SeverityOrder = {
270     "info": 3,
271     "warning": 2,
272     "severe": 1
273 }
274
275 WebInspector.AuditRule.prototype = {
276     get id()
277     {
278         return this._id;
279     },
280
281     get displayName()
282     {
283         return this._displayName;
284     },
285
286     /**
287      * @param {!WebInspector.AuditRule.Severity} severity
288      */
289     set severity(severity)
290     {
291         this._severity = severity;
292     },
293
294     /**
295      * @param {!WebInspector.Target} target
296      * @param {!Array.<!WebInspector.NetworkRequest>} requests
297      * @param {function(!WebInspector.AuditRuleResult)} callback
298      * @param {!WebInspector.Progress} progress
299      */
300     run: function(target, requests, callback, progress)
301     {
302         if (progress.isCanceled())
303             return;
304
305         var result = new WebInspector.AuditRuleResult(this.displayName);
306         result.severity = this._severity;
307         this.doRun(target, requests, result, callback, progress);
308     },
309
310     /**
311      * @param {!WebInspector.Target} target
312      * @param {!Array.<!WebInspector.NetworkRequest>} requests
313      * @param {!WebInspector.AuditRuleResult} result
314      * @param {function(!WebInspector.AuditRuleResult)} callback
315      * @param {!WebInspector.Progress} progress
316      */
317     doRun: function(target, requests, result, callback, progress)
318     {
319         throw new Error("doRun() not implemented");
320     }
321 }
322
323 /**
324  * @constructor
325  * @param {!WebInspector.AuditCategory} category
326  */
327 WebInspector.AuditCategoryResult = function(category)
328 {
329     this.title = category.displayName;
330     this.ruleResults = [];
331 }
332
333 WebInspector.AuditCategoryResult.prototype = {
334     /**
335      * @param {!WebInspector.AuditRuleResult} ruleResult
336      */
337     addRuleResult: function(ruleResult)
338     {
339         this.ruleResults.push(ruleResult);
340     }
341 }
342
343 /**
344  * @constructor
345  * @param {(string|boolean|number|!Object)} value
346  * @param {boolean=} expanded
347  * @param {string=} className
348  */
349 WebInspector.AuditRuleResult = function(value, expanded, className)
350 {
351     this.value = value;
352     this.className = className;
353     this.expanded = expanded;
354     this.violationCount = 0;
355     this._formatters = {
356         r: WebInspector.AuditRuleResult.linkifyDisplayName
357     };
358     var standardFormatters = Object.keys(String.standardFormatters);
359     for (var i = 0; i < standardFormatters.length; ++i)
360         this._formatters[standardFormatters[i]] = String.standardFormatters[standardFormatters[i]];
361 }
362
363 /**
364  * @param {string} url
365  * @return {!Element}
366  */
367 WebInspector.AuditRuleResult.linkifyDisplayName = function(url)
368 {
369     return WebInspector.linkifyURLAsNode(url, WebInspector.displayNameForURL(url));
370 }
371
372 /**
373  * @param {string} domain
374  * @return {string}
375  */
376 WebInspector.AuditRuleResult.resourceDomain = function(domain)
377 {
378     return domain || WebInspector.UIString("[empty domain]");
379 }
380
381 WebInspector.AuditRuleResult.prototype = {
382     /**
383      * @param {(string|boolean|number|!Object)} value
384      * @param {boolean=} expanded
385      * @param {string=} className
386      * @return {!WebInspector.AuditRuleResult}
387      */
388     addChild: function(value, expanded, className)
389     {
390         if (!this.children)
391             this.children = [];
392         var entry = new WebInspector.AuditRuleResult(value, expanded, className);
393         this.children.push(entry);
394         return entry;
395     },
396
397     /**
398      * @param {string} url
399      */
400     addURL: function(url)
401     {
402         this.addChild(WebInspector.AuditRuleResult.linkifyDisplayName(url));
403     },
404
405     /**
406      * @param {!Array.<string>} urls
407      */
408     addURLs: function(urls)
409     {
410         for (var i = 0; i < urls.length; ++i)
411             this.addURL(urls[i]);
412     },
413
414     /**
415      * @param {string} snippet
416      */
417     addSnippet: function(snippet)
418     {
419         this.addChild(snippet, false, "source-code");
420     },
421
422     /**
423      * @param {string} format
424      * @param {...*} vararg
425      * @return {!WebInspector.AuditRuleResult}
426      */
427     addFormatted: function(format, vararg)
428     {
429         var substitutions = Array.prototype.slice.call(arguments, 1);
430         var fragment = document.createDocumentFragment();
431
432         function append(a, b)
433         {
434             if (!(b instanceof Node))
435                 b = document.createTextNode(b);
436             a.appendChild(b);
437             return a;
438         }
439
440         var formattedResult = String.format(format, substitutions, this._formatters, fragment, append).formattedResult;
441         if (formattedResult instanceof Node)
442             formattedResult.normalize();
443         return this.addChild(formattedResult);
444     }
445 }
446
447 /**
448  * @constructor
449  * @extends {WebInspector.SidebarTreeElement}
450  * @param {!WebInspector.AuditsPanel} panel
451  */
452 WebInspector.AuditsSidebarTreeElement = function(panel)
453 {
454     this._panel = panel;
455     this.small = false;
456     WebInspector.SidebarTreeElement.call(this, "audits-sidebar-tree-item", WebInspector.UIString("Audits"), "", null, false);
457 }
458
459 WebInspector.AuditsSidebarTreeElement.prototype = {
460     onattach: function()
461     {
462         WebInspector.SidebarTreeElement.prototype.onattach.call(this);
463     },
464
465     /**
466      * @return {boolean}
467      */
468     onselect: function()
469     {
470         this._panel.showLauncherView();
471         return true;
472     },
473
474     get selectable()
475     {
476         return true;
477     },
478
479     refresh: function()
480     {
481         this.refreshTitles();
482     },
483
484     __proto__: WebInspector.SidebarTreeElement.prototype
485 }
486
487 /**
488  * @constructor
489  * @extends {WebInspector.SidebarTreeElement}
490  * @param {!WebInspector.AuditsPanel} panel
491  * @param {!Array.<!WebInspector.AuditCategoryResult>} results
492  * @param {string} mainResourceURL
493  * @param {number} ordinal
494  */
495 WebInspector.AuditResultSidebarTreeElement = function(panel, results, mainResourceURL, ordinal)
496 {
497     this._panel = panel;
498     this.results = results;
499     this.mainResourceURL = mainResourceURL;
500     WebInspector.SidebarTreeElement.call(this, "audit-result-sidebar-tree-item", String.sprintf("%s (%d)", mainResourceURL, ordinal), "", {}, false);
501 }
502
503 WebInspector.AuditResultSidebarTreeElement.prototype = {
504     /**
505      * @return {boolean}
506      */
507     onselect: function()
508     {
509         this._panel.showResults(this.results);
510         return true;
511     },
512
513     get selectable()
514     {
515         return true;
516     },
517
518     __proto__: WebInspector.SidebarTreeElement.prototype
519 }
520
521 // Contributed audit rules should go into this namespace.
522 WebInspector.AuditRules = {};
523
524 /**
525  * Contributed audit categories should go into this namespace.
526  * @type {!Object.<string, function(new:WebInspector.AuditCategory)>}
527  */
528 WebInspector.AuditCategories = {};