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.
33 * @param {!WebInspector.AuditController} auditController
34 * @extends {WebInspector.VBox}
36 WebInspector.AuditLauncherView = function(auditController)
38 WebInspector.VBox.call(this);
39 this.setMinimumSize(100, 25);
41 this._auditController = auditController;
43 this._categoryIdPrefix = "audit-category-item-";
44 this._auditRunning = false;
46 this.element.classList.add("audit-launcher-view");
47 this.element.classList.add("panel-enabler-view");
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);
54 this._resetResourceCount();
56 this._sortedCategories = [];
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);
63 WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
64 WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
65 WebInspector.profilingLock().addEventListener(WebInspector.Lock.Events.StateChanged, this._updateButton, this);
67 var defaultSelectedAuditCategory = {};
68 defaultSelectedAuditCategory[WebInspector.AuditLauncherView.AllCategoriesKey] = true;
69 this._selectedCategoriesSetting = WebInspector.settings.createSetting("selectedAuditCategories", defaultSelectedAuditCategory);
72 WebInspector.AuditLauncherView.AllCategoriesKey = "__AllCategories";
74 WebInspector.AuditLauncherView.prototype = {
75 _resetResourceCount: function()
77 this._loadedResources = 0;
78 this._totalResources = 0;
81 _onRequestStarted: function(event)
83 var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
84 // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway.
85 if (request.type === WebInspector.resourceTypes.WebSocket)
87 ++this._totalResources;
88 this._updateResourceProgress();
91 _onRequestFinished: function(event)
93 var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
94 // See resorceStarted for details.
95 if (request.type === WebInspector.resourceTypes.WebSocket)
97 ++this._loadedResources;
98 this._updateResourceProgress();
102 * @param {!WebInspector.AuditCategory} category
104 addCategory: function(category)
106 if (!this._sortedCategories.length)
107 this._createLauncherUI();
109 var selectedCategories = this._selectedCategoriesSetting.get();
110 var categoryElement = this._createCategoryElement(category.displayName, category.id);
111 category._checkboxElement = categoryElement.firstChild;
112 if (this._selectAllCheckboxElement.checked || selectedCategories[category.displayName]) {
113 category._checkboxElement.checked = true;
114 ++this._currentCategoriesCount;
118 * @param {!WebInspector.AuditCategory} a
119 * @param {!WebInspector.AuditCategory} b
122 function compareCategories(a, b)
124 var aTitle = a.displayName || "";
125 var bTitle = b.displayName || "";
126 return aTitle.localeCompare(bTitle);
128 var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories);
129 this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
130 this._sortedCategories.splice(insertBefore, 0, category);
131 this._selectedCategoriesUpdated();
135 * @param {boolean} auditRunning
137 _setAuditRunning: function(auditRunning)
139 if (this._auditRunning === auditRunning)
141 this._auditRunning = auditRunning;
142 this._updateButton();
143 this._toggleUIComponents(this._auditRunning);
144 if (this._auditRunning) {
145 WebInspector.profilingLock().acquire();
149 WebInspector.profilingLock().release();
153 _startAudit: function()
156 for (var category = 0; category < this._sortedCategories.length; ++category) {
157 if (this._sortedCategories[category]._checkboxElement.checked)
158 catIds.push(this._sortedCategories[category].id);
161 this._resetResourceCount();
162 this._progressIndicator = new WebInspector.ProgressIndicator();
163 this._buttonContainerElement.appendChild(this._progressIndicator.element);
164 this._displayResourceLoadingProgress = true;
167 * @this {WebInspector.AuditLauncherView}
169 function onAuditStarted()
171 this._displayResourceLoadingProgress = false;
173 this._auditController.initiateAudit(catIds, this._progressIndicator, this._auditPresentStateElement.checked, onAuditStarted.bind(this), this._setAuditRunning.bind(this, false));
176 _stopAudit: function()
178 this._displayResourceLoadingProgress = false;
179 this._progressIndicator.cancel();
180 this._progressIndicator.done();
181 delete this._progressIndicator;
185 * @param {boolean} disable
187 _toggleUIComponents: function(disable)
189 this._selectAllCheckboxElement.disabled = disable;
190 this._categoriesElement.disabled = disable;
191 this._auditPresentStateElement.disabled = disable;
192 this._auditReloadedStateElement.disabled = disable;
195 _launchButtonClicked: function(event)
197 this._setAuditRunning(!this._auditRunning);
200 _clearButtonClicked: function()
202 this._auditController.clearResults();
206 * @param {boolean} checkCategories
207 * @param {boolean=} userGesture
209 _selectAllClicked: function(checkCategories, userGesture)
211 var childNodes = this._categoriesElement.childNodes;
212 for (var i = 0, length = childNodes.length; i < length; ++i)
213 childNodes[i].firstChild.checked = checkCategories;
214 this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
215 this._selectedCategoriesUpdated(userGesture);
218 _categoryClicked: function(event)
220 this._currentCategoriesCount += event.target.checked ? 1 : -1;
221 this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
222 this._selectedCategoriesUpdated(true);
226 * @param {string} title
229 _createCategoryElement: function(title, id)
231 var labelElement = document.createElement("label");
232 labelElement.id = this._categoryIdPrefix + id;
234 var element = document.createElement("input");
235 element.type = "checkbox";
237 element.addEventListener("click", this._boundCategoryClickListener, false);
238 labelElement.appendChild(element);
239 labelElement.createTextChild(title);
240 labelElement.__displayName = title;
245 _createLauncherUI: function()
247 this._headerElement = document.createElement("h1");
248 this._headerElement.textContent = WebInspector.UIString("Select audits to run");
250 for (var child = 0; child < this._contentElement.children.length; ++child)
251 this._contentElement.removeChild(this._contentElement.children[child]);
253 this._contentElement.appendChild(this._headerElement);
256 * @param {!Event} event
257 * @this {WebInspector.AuditLauncherView}
259 function handleSelectAllClick(event)
261 this._selectAllClicked(event.target.checked, true);
263 var categoryElement = this._createCategoryElement(WebInspector.UIString("Select All"), "");
264 categoryElement.id = "audit-launcher-selectall";
265 this._selectAllCheckboxElement = categoryElement.firstChild;
266 this._selectAllCheckboxElement.checked = this._selectedCategoriesSetting.get()[WebInspector.AuditLauncherView.AllCategoriesKey];
267 this._selectAllCheckboxElement.addEventListener("click", handleSelectAllClick.bind(this), false);
268 this._contentElement.appendChild(categoryElement);
270 this._categoriesElement = this._contentElement.createChild("fieldset", "audit-categories-container");
271 this._currentCategoriesCount = 0;
273 this._contentElement.createChild("div", "flexible-space");
275 this._buttonContainerElement = this._contentElement.createChild("div", "button-container");
277 var labelElement = this._buttonContainerElement.createChild("label");
278 this._auditPresentStateElement = labelElement.createChild("input");
279 this._auditPresentStateElement.name = "audit-mode";
280 this._auditPresentStateElement.type = "radio";
281 this._auditPresentStateElement.checked = true;
282 this._auditPresentStateLabelElement = document.createTextNode(WebInspector.UIString("Audit Present State"));
283 labelElement.appendChild(this._auditPresentStateLabelElement);
285 labelElement = this._buttonContainerElement.createChild("label");
286 this._auditReloadedStateElement = labelElement.createChild("input");
287 this._auditReloadedStateElement.name = "audit-mode";
288 this._auditReloadedStateElement.type = "radio";
289 labelElement.createTextChild("Reload Page and Audit on Load");
291 this._launchButton = this._buttonContainerElement.createChild("button", "text-button");
292 this._launchButton.textContent = WebInspector.UIString("Run");
293 this._launchButton.addEventListener("click", this._launchButtonClicked.bind(this), false);
295 this._clearButton = this._buttonContainerElement.createChild("button", "text-button");
296 this._clearButton.textContent = WebInspector.UIString("Clear");
297 this._clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
299 this._selectAllClicked(this._selectAllCheckboxElement.checked);
302 _updateResourceProgress: function()
304 if (this._displayResourceLoadingProgress)
305 this._progressIndicator.setTitle(WebInspector.UIString("Loading (%d of %d)", this._loadedResources, this._totalResources));
309 * @param {boolean=} userGesture
311 _selectedCategoriesUpdated: function(userGesture)
313 // Save present categories only upon user gesture to clean up junk from past versions and removed extensions.
314 // Do not remove old categories if not handling a user gesture, as there's chance categories will be added
315 // later during start-up.
316 var selectedCategories = userGesture ? {} : this._selectedCategoriesSetting.get();
317 var childNodes = this._categoriesElement.childNodes;
318 for (var i = 0, length = childNodes.length; i < length; ++i)
319 selectedCategories[childNodes[i].__displayName] = childNodes[i].firstChild.checked;
320 selectedCategories[WebInspector.AuditLauncherView.AllCategoriesKey] = this._selectAllCheckboxElement.checked;
321 this._selectedCategoriesSetting.set(selectedCategories);
322 this._updateButton();
325 _updateButton: function()
327 var enable = this._auditRunning || (this._currentCategoriesCount && !WebInspector.profilingLock().isAcquired());
328 this._launchButton.textContent = this._auditRunning ? WebInspector.UIString("Stop") : WebInspector.UIString("Run");
329 this._launchButton.disabled = !enable;
330 this._launchButton.title = enable ? "" : WebInspector.anotherProfilerActiveLabel();
333 __proto__: WebInspector.VBox.prototype