Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / audits / AuditLauncherView.js
1 /*
2  * Copyright (C) 2011 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  * @param {!WebInspector.AuditController} auditController
34  * @extends {WebInspector.VBox}
35  */
36 WebInspector.AuditLauncherView = function(auditController)
37 {
38     WebInspector.VBox.call(this);
39     this.setMinimumSize(100, 25);
40
41     this._auditController = auditController;
42
43     this._categoryIdPrefix = "audit-category-item-";
44     this._auditRunning = false;
45
46     this.element.classList.add("audit-launcher-view");
47     this.element.classList.add("panel-enabler-view");
48
49     this._contentElement = document.createElement("div");
50     this._contentElement.className = "audit-launcher-view-content";
51     this.element.appendChild(this._contentElement);
52     this._boundCategoryClickListener = this._categoryClicked.bind(this);
53
54     this._resetResourceCount();
55
56     this._sortedCategories = [];
57
58     this._headerElement = document.createElement("h1");
59     this._headerElement.className = "no-audits";
60     this._headerElement.textContent = WebInspector.UIString("No audits to run");
61     this._contentElement.appendChild(this._headerElement);
62
63     var target = this._auditController.target();
64     target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
65     target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
66     target.profilingLock.addEventListener(WebInspector.Lock.Events.StateChanged, this._updateButton, this);
67
68     var defaultSelectedAuditCategory = {};
69     defaultSelectedAuditCategory[WebInspector.AuditLauncherView.AllCategoriesKey] = true;
70     this._selectedCategoriesSetting = WebInspector.settings.createSetting("selectedAuditCategories", defaultSelectedAuditCategory);
71 }
72
73 WebInspector.AuditLauncherView.AllCategoriesKey = "__AllCategories";
74
75 WebInspector.AuditLauncherView.prototype = {
76     _resetResourceCount: function()
77     {
78         this._loadedResources = 0;
79         this._totalResources = 0;
80     },
81
82     _onRequestStarted: function(event)
83     {
84         var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
85         // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway.
86         if (request.type === WebInspector.resourceTypes.WebSocket)
87             return;
88         ++this._totalResources;
89         this._updateResourceProgress();
90     },
91
92     _onRequestFinished: function(event)
93     {
94         var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
95         // See resorceStarted for details.
96         if (request.type === WebInspector.resourceTypes.WebSocket)
97             return;
98         ++this._loadedResources;
99         this._updateResourceProgress();
100     },
101
102     /**
103      * @param {!WebInspector.AuditCategory} category
104      */
105     addCategory: function(category)
106     {
107         if (!this._sortedCategories.length)
108             this._createLauncherUI();
109
110         var selectedCategories = this._selectedCategoriesSetting.get();
111         var categoryElement = this._createCategoryElement(category.displayName, category.id);
112         category._checkboxElement = categoryElement.firstChild;
113         if (this._selectAllCheckboxElement.checked || selectedCategories[category.displayName]) {
114             category._checkboxElement.checked = true;
115             ++this._currentCategoriesCount;
116         }
117
118         /**
119          * @param {!WebInspector.AuditCategory} a
120          * @param {!WebInspector.AuditCategory} b
121          * @return {number}
122          */
123         function compareCategories(a, b)
124         {
125             var aTitle = a.displayName || "";
126             var bTitle = b.displayName || "";
127             return aTitle.localeCompare(bTitle);
128         }
129         var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories);
130         this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
131         this._sortedCategories.splice(insertBefore, 0, category);
132         this._selectedCategoriesUpdated();
133     },
134
135     /**
136      * @param {boolean} auditRunning
137      */
138     _setAuditRunning: function(auditRunning)
139     {
140         if (this._auditRunning === auditRunning)
141             return;
142         this._auditRunning = auditRunning;
143         this._updateButton();
144         this._toggleUIComponents(this._auditRunning);
145         var target = this._auditController.target();
146         if (this._auditRunning) {
147             target.profilingLock.acquire();
148             this._startAudit();
149         } else {
150             this._stopAudit();
151             target.profilingLock.release();
152         }
153     },
154
155     _startAudit: function()
156     {
157         var catIds = [];
158         for (var category = 0; category < this._sortedCategories.length; ++category) {
159             if (this._sortedCategories[category]._checkboxElement.checked)
160                 catIds.push(this._sortedCategories[category].id);
161         }
162
163         this._resetResourceCount();
164         this._progressIndicator = new WebInspector.ProgressIndicator();
165         this._buttonContainerElement.appendChild(this._progressIndicator.element);
166         this._displayResourceLoadingProgress = true;
167
168         /**
169          * @this {WebInspector.AuditLauncherView}
170          */
171         function onAuditStarted()
172         {
173             this._displayResourceLoadingProgress = false;
174         }
175         this._auditController.initiateAudit(catIds, this._progressIndicator, this._auditPresentStateElement.checked, onAuditStarted.bind(this), this._setAuditRunning.bind(this, false));
176     },
177
178     _stopAudit: function()
179     {
180         this._displayResourceLoadingProgress = false;
181         this._progressIndicator.cancel();
182         this._progressIndicator.done();
183         delete this._progressIndicator;
184     },
185
186     /**
187      * @param {boolean} disable
188      */
189     _toggleUIComponents: function(disable)
190     {
191         this._selectAllCheckboxElement.disabled = disable;
192         this._categoriesElement.disabled = disable;
193         this._auditPresentStateElement.disabled = disable;
194         this._auditReloadedStateElement.disabled = disable;
195     },
196
197     _launchButtonClicked: function(event)
198     {
199         this._setAuditRunning(!this._auditRunning);
200     },
201
202     _clearButtonClicked: function()
203     {
204         this._auditController.clearResults();
205     },
206
207     /**
208      * @param {boolean} checkCategories
209      * @param {boolean=} userGesture
210      */
211     _selectAllClicked: function(checkCategories, userGesture)
212     {
213         var childNodes = this._categoriesElement.childNodes;
214         for (var i = 0, length = childNodes.length; i < length; ++i)
215             childNodes[i].firstChild.checked = checkCategories;
216         this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
217         this._selectedCategoriesUpdated(userGesture);
218     },
219
220     _categoryClicked: function(event)
221     {
222         this._currentCategoriesCount += event.target.checked ? 1 : -1;
223         this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
224         this._selectedCategoriesUpdated(true);
225     },
226
227     /**
228      * @param {string} title
229      * @param {string} id
230      */
231     _createCategoryElement: function(title, id)
232     {
233         var labelElement = document.createElement("label");
234         labelElement.id = this._categoryIdPrefix + id;
235
236         var element = document.createElement("input");
237         element.type = "checkbox";
238         if (id !== "")
239             element.addEventListener("click", this._boundCategoryClickListener, false);
240         labelElement.appendChild(element);
241         labelElement.appendChild(document.createTextNode(title));
242         labelElement.__displayName = title;
243
244         return labelElement;
245     },
246
247     _createLauncherUI: function()
248     {
249         this._headerElement = document.createElement("h1");
250         this._headerElement.textContent = WebInspector.UIString("Select audits to run");
251
252         for (var child = 0; child < this._contentElement.children.length; ++child)
253             this._contentElement.removeChild(this._contentElement.children[child]);
254
255         this._contentElement.appendChild(this._headerElement);
256
257         /**
258          * @param {?Event} event
259          * @this {WebInspector.AuditLauncherView}
260          */
261         function handleSelectAllClick(event)
262         {
263             this._selectAllClicked(event.target.checked, true);
264         }
265         var categoryElement = this._createCategoryElement(WebInspector.UIString("Select All"), "");
266         categoryElement.id = "audit-launcher-selectall";
267         this._selectAllCheckboxElement = categoryElement.firstChild;
268         this._selectAllCheckboxElement.checked = this._selectedCategoriesSetting.get()[WebInspector.AuditLauncherView.AllCategoriesKey];
269         this._selectAllCheckboxElement.addEventListener("click", handleSelectAllClick.bind(this), false);
270         this._contentElement.appendChild(categoryElement);
271
272         this._categoriesElement = this._contentElement.createChild("fieldset", "audit-categories-container");
273         this._currentCategoriesCount = 0;
274
275         this._contentElement.createChild("div", "flexible-space");
276
277         this._buttonContainerElement = this._contentElement.createChild("div", "button-container");
278
279         var labelElement = this._buttonContainerElement.createChild("label");
280         this._auditPresentStateElement = labelElement.createChild("input");
281         this._auditPresentStateElement.name = "audit-mode";
282         this._auditPresentStateElement.type = "radio";
283         this._auditPresentStateElement.checked = true;
284         this._auditPresentStateLabelElement = document.createTextNode(WebInspector.UIString("Audit Present State"));
285         labelElement.appendChild(this._auditPresentStateLabelElement);
286
287         labelElement = this._buttonContainerElement.createChild("label");
288         this._auditReloadedStateElement = labelElement.createChild("input");
289         this._auditReloadedStateElement.name = "audit-mode";
290         this._auditReloadedStateElement.type = "radio";
291         labelElement.appendChild(document.createTextNode("Reload Page and Audit on Load"));
292
293         this._launchButton = this._buttonContainerElement.createChild("button");
294         this._launchButton.textContent = WebInspector.UIString("Run");
295         this._launchButton.addEventListener("click", this._launchButtonClicked.bind(this), false);
296
297         this._clearButton = this._buttonContainerElement.createChild("button");
298         this._clearButton.textContent = WebInspector.UIString("Clear");
299         this._clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
300
301         this._selectAllClicked(this._selectAllCheckboxElement.checked);
302     },
303
304     _updateResourceProgress: function()
305     {
306         if (this._displayResourceLoadingProgress)
307             this._progressIndicator.setTitle(WebInspector.UIString("Loading (%d of %d)", this._loadedResources, this._totalResources));
308     },
309
310     /**
311      * @param {boolean=} userGesture
312      */
313     _selectedCategoriesUpdated: function(userGesture)
314     {
315         // Save present categories only upon user gesture to clean up junk from past versions and removed extensions.
316         // Do not remove old categories if not handling a user gesture, as there's chance categories will be added
317         // later during start-up.
318         var selectedCategories = userGesture ? {} : this._selectedCategoriesSetting.get();
319         var childNodes = this._categoriesElement.childNodes;
320         for (var i = 0, length = childNodes.length; i < length; ++i)
321             selectedCategories[childNodes[i].__displayName] = childNodes[i].firstChild.checked;
322         selectedCategories[WebInspector.AuditLauncherView.AllCategoriesKey] = this._selectAllCheckboxElement.checked;
323         this._selectedCategoriesSetting.set(selectedCategories);
324         this._updateButton();
325     },
326
327     _updateButton: function()
328     {
329         var target = this._auditController.target();
330         var enable = this._auditRunning || (this._currentCategoriesCount && !target.profilingLock.isAcquired());
331         this._launchButton.textContent = this._auditRunning ? WebInspector.UIString("Stop") : WebInspector.UIString("Run");
332         this._launchButton.disabled = !enable;
333         this._launchButton.title = enable ? "" : WebInspector.UIString("Another profiler is already active");
334     },
335
336     __proto__: WebInspector.VBox.prototype
337 }