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