Upstream version 9.38.198.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     var target = /** @type {!WebInspector.Target} */ (WebInspector.targetManager.mainTarget());
55     this._auditController = new WebInspector.AuditController(target, 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 {!WebInspector.Target} target
219      * @param {!Array.<!WebInspector.NetworkRequest>} requests
220      * @param {function(!WebInspector.AuditRuleResult)} ruleResultCallback
221      * @param {function()} categoryDoneCallback
222      * @param {!WebInspector.Progress} progress
223      */
224     run: function(target, requests, ruleResultCallback, categoryDoneCallback, progress)
225     {
226         this._ensureInitialized();
227         var remainingRulesCount = this._rules.length;
228         progress.setTotalWork(remainingRulesCount);
229         function callbackWrapper(result)
230         {
231             ruleResultCallback(result);
232             progress.worked();
233             if (!--remainingRulesCount)
234                 categoryDoneCallback();
235         }
236         for (var i = 0; i < this._rules.length; ++i)
237             this._rules[i].run(target, requests, callbackWrapper, progress);
238     },
239
240     _ensureInitialized: function()
241     {
242         if (!this._initialized) {
243             if ("initialize" in this)
244                 this.initialize();
245             this._initialized = true;
246         }
247     }
248 }
249
250 /**
251  * @constructor
252  * @param {string} id
253  * @param {string} displayName
254  */
255 WebInspector.AuditRule = function(id, displayName)
256 {
257     this._id = id;
258     this._displayName = displayName;
259 }
260
261 /**
262  * @enum {string}
263  */
264 WebInspector.AuditRule.Severity = {
265     Info: "info",
266     Warning: "warning",
267     Severe: "severe"
268 }
269
270 WebInspector.AuditRule.SeverityOrder = {
271     "info": 3,
272     "warning": 2,
273     "severe": 1
274 }
275
276 WebInspector.AuditRule.prototype = {
277     get id()
278     {
279         return this._id;
280     },
281
282     get displayName()
283     {
284         return this._displayName;
285     },
286
287     /**
288      * @param {!WebInspector.AuditRule.Severity} severity
289      */
290     set severity(severity)
291     {
292         this._severity = severity;
293     },
294
295     /**
296      * @param {!WebInspector.Target} target
297      * @param {!Array.<!WebInspector.NetworkRequest>} requests
298      * @param {function(!WebInspector.AuditRuleResult)} callback
299      * @param {!WebInspector.Progress} progress
300      */
301     run: function(target, requests, callback, progress)
302     {
303         if (progress.isCanceled())
304             return;
305
306         var result = new WebInspector.AuditRuleResult(this.displayName);
307         result.severity = this._severity;
308         this.doRun(target, requests, result, callback, progress);
309     },
310
311     /**
312      * @param {!WebInspector.Target} target
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(target, 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 /**
374  * @param {string} domain
375  * @return {string}
376  */
377 WebInspector.AuditRuleResult.resourceDomain = function(domain)
378 {
379     return domain || WebInspector.UIString("[empty domain]");
380 }
381
382 WebInspector.AuditRuleResult.prototype = {
383     /**
384      * @param {(string|boolean|number|!Object)} value
385      * @param {boolean=} expanded
386      * @param {string=} className
387      * @return {!WebInspector.AuditRuleResult}
388      */
389     addChild: function(value, expanded, className)
390     {
391         if (!this.children)
392             this.children = [];
393         var entry = new WebInspector.AuditRuleResult(value, expanded, className);
394         this.children.push(entry);
395         return entry;
396     },
397
398     /**
399      * @param {string} url
400      */
401     addURL: function(url)
402     {
403         this.addChild(WebInspector.AuditRuleResult.linkifyDisplayName(url));
404     },
405
406     /**
407      * @param {!Array.<string>} urls
408      */
409     addURLs: function(urls)
410     {
411         for (var i = 0; i < urls.length; ++i)
412             this.addURL(urls[i]);
413     },
414
415     /**
416      * @param {string} snippet
417      */
418     addSnippet: function(snippet)
419     {
420         this.addChild(snippet, false, "source-code");
421     },
422
423     /**
424      * @param {string} format
425      * @param {...*} vararg
426      * @return {!WebInspector.AuditRuleResult}
427      */
428     addFormatted: function(format, vararg)
429     {
430         var substitutions = Array.prototype.slice.call(arguments, 1);
431         var fragment = document.createDocumentFragment();
432
433         function append(a, b)
434         {
435             if (!(b instanceof Node))
436                 b = document.createTextNode(b);
437             a.appendChild(b);
438             return a;
439         }
440
441         var formattedResult = String.format(format, substitutions, this._formatters, fragment, append).formattedResult;
442         if (formattedResult instanceof Node)
443             formattedResult.normalize();
444         return this.addChild(formattedResult);
445     }
446 }
447
448 /**
449  * @constructor
450  * @extends {WebInspector.SidebarTreeElement}
451  * @param {!WebInspector.AuditsPanel} panel
452  */
453 WebInspector.AuditsSidebarTreeElement = function(panel)
454 {
455     this._panel = panel;
456     this.small = false;
457     WebInspector.SidebarTreeElement.call(this, "audits-sidebar-tree-item", WebInspector.UIString("Audits"), "", null, false);
458 }
459
460 WebInspector.AuditsSidebarTreeElement.prototype = {
461     onattach: function()
462     {
463         WebInspector.SidebarTreeElement.prototype.onattach.call(this);
464     },
465
466     onselect: function()
467     {
468         this._panel.showLauncherView();
469     },
470
471     get selectable()
472     {
473         return true;
474     },
475
476     refresh: function()
477     {
478         this.refreshTitles();
479     },
480
481     __proto__: WebInspector.SidebarTreeElement.prototype
482 }
483
484 /**
485  * @constructor
486  * @extends {WebInspector.SidebarTreeElement}
487  * @param {!WebInspector.AuditsPanel} panel
488  * @param {!Array.<!WebInspector.AuditCategoryResult>} results
489  * @param {string} mainResourceURL
490  * @param {number} ordinal
491  */
492 WebInspector.AuditResultSidebarTreeElement = function(panel, results, mainResourceURL, ordinal)
493 {
494     this._panel = panel;
495     this.results = results;
496     this.mainResourceURL = mainResourceURL;
497     WebInspector.SidebarTreeElement.call(this, "audit-result-sidebar-tree-item", String.sprintf("%s (%d)", mainResourceURL, ordinal), "", {}, false);
498 }
499
500 WebInspector.AuditResultSidebarTreeElement.prototype = {
501     onselect: function()
502     {
503         this._panel.showResults(this.results);
504     },
505
506     get selectable()
507     {
508         return true;
509     },
510
511     __proto__: WebInspector.SidebarTreeElement.prototype
512 }
513
514 // Contributed audit rules should go into this namespace.
515 WebInspector.AuditRules = {};
516
517 /**
518  * Contributed audit categories should go into this namespace.
519  * @type {!Object.<string, function(new:WebInspector.AuditCategory)>}
520  */
521 WebInspector.AuditCategories = {};