OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * The ProfilingApp encapsulates the application's global state, | |
7 * and controls its subviews. | |
8 * | |
9 * @constructor | |
10 */ | |
11 function ProfilingApp() { | |
12 // Factories for each of the view types. | |
13 this.viewFactories_ = { | |
14 list: CreateListView, | |
15 stats: CreateStatsView, | |
16 }; | |
17 | |
18 // Views which have been created so far, keyed by their name. | |
19 this.liveViews_ = {}; | |
20 | |
21 // The last list of entries fetched from the server. | |
22 this.entries_ = null; | |
23 | |
24 // The last query filters that entries were fetched from the server for. | |
25 this.filters_ = null; | |
26 | |
27 this.pending_request_ = null; | |
28 this.filters_names_ = [ | |
29 "platform", "domain", "executable", "first_arg", "limit"]; | |
30 this.filters_titles_ = [ | |
31 "Platform", "Domain", "Executable", "First Arg", "Limit"]; | |
32 | |
33 window.addEventListener("load", this.OnPageLoaded.bind(this)); | |
34 } | |
35 | |
36 /** | |
37 * This is the main entry point to the application, when the page has | |
38 * finished loading. | |
39 */ | |
40 ProfilingApp.prototype.OnPageLoaded = function() { | |
41 this.CreateFilterTable(); | |
42 this.CreateViewSelectionTable(); | |
43 this.ApplyQueryParameters(); | |
44 this.OnQueryChanged(); | |
45 }; | |
46 | |
47 ProfilingApp.prototype.CreateFilterTable = function() { | |
48 var container = document.getElementById("filters_container"); | |
49 var form = DomUtil.AddNode(container, "form"); | |
50 form.method = "GET"; | |
51 // Create a table inside. | |
52 var table = DomUtil.AddNode(form, "table"); | |
53 for (var i in this.filters_names_) { | |
54 var tr = DomUtil.AddNode(table, "tr"); | |
55 var th = DomUtil.AddNode(tr, "th"); | |
56 DomUtil.AddText(th, this.filters_titles_[i]); | |
57 var td = DomUtil.AddNode(tr, "td"); | |
58 var input = DomUtil.AddNode(td, "input"); | |
59 input.type = "search"; | |
60 input.incremental = true; | |
61 input.id = this.filters_names_[i]; | |
62 input.addEventListener("search", this.OnQueryChanged.bind(this)); | |
63 } | |
64 }; | |
65 | |
66 ProfilingApp.prototype.CreateViewSelectionTable = function() { | |
67 var container = document.getElementById("view_selection_container"); | |
68 var first = true; | |
69 for (var i in this.viewFactories_) { | |
70 var span = DomUtil.AddNode(container, "span"); | |
71 span.id = i + "_badge"; | |
72 span.className = "viewBadge"; | |
73 if (first) { | |
74 span.className += " Selected"; | |
75 first = false; | |
76 } | |
77 var a = DomUtil.AddNode(span, "a"); | |
78 a.href = "javascript:void(0)"; | |
79 a.onclick = this.SwitchToView.bind(this, i); | |
80 DomUtil.AddText(a, this.viewFactories_[i].display_name); | |
81 } | |
82 }; | |
83 | |
84 /** | |
85 * This method is called whenever the query parameters changed and we need to | |
86 * fetch new data off the server to update the views. | |
87 */ | |
88 ProfilingApp.prototype.OnQueryChanged = function() { | |
89 if (this.pending_request_ != null) { | |
90 this.pending_request_.abort(); | |
91 this.pending_request_ = null; | |
92 } | |
93 var filters = this.GetFilters(); | |
94 | |
95 // Invalidate data derived from the previous filters. | |
96 this.filters_ = null; | |
97 this.entries_ = null; | |
98 | |
99 // Clear all views. | |
100 for (var i in this.liveViews_) { | |
101 this.ShowView(i, false); | |
102 } | |
103 this.liveViews_ = {}; | |
104 | |
105 // Use AJAX to fetch the tree status data for the new filters. | |
106 // On completion it will call OnDataAvailable() with the data. | |
107 this.SetLoadingIndicator("Fetching data..."); | |
108 var callback = this.OnDataAvailable.bind(this, filters); | |
109 this.pending_request_ = DataFetcher.GetEntries(filters, callback); | |
110 }; | |
111 | |
112 /** | |
113 * This method is called when new data has been received from the server. | |
114 */ | |
115 ProfilingApp.prototype.OnDataAvailable = function(filters, entries) { | |
116 this.SetLoadingIndicator(""); | |
117 | |
118 // Set the new data as current. | |
119 this.pending_request_ = null; | |
120 this.filters_ = filters; | |
121 this.entries_ = entries; | |
122 | |
123 if (this.entries_) { | |
124 // Force the view to redraw itself using the new data. | |
125 this.SwitchToView(this.GetCurrentViewName()); | |
126 } | |
127 }; | |
128 | |
129 /** | |
130 * Gets the filters the user is interested in. | |
131 * @return {Stuff} | |
132 */ | |
133 ProfilingApp.prototype.GetFilters = function() { | |
134 var filters = {}; | |
135 for (var i = 0; i < this.filters_names_.length; ++i) { | |
136 var name = this.filters_names_[i]; | |
137 var d = document.getElementById(name); | |
138 filters[name] = d.value; | |
139 } | |
140 return filters; | |
141 }; | |
142 | |
143 /** | |
144 * Gets the current window's URL's query parameters, as a | |
145 * dictionary of key/value pairs. | |
146 * | |
147 * @return {Object} Dictionary of name/value pairs. | |
148 */ | |
149 function GetQueryParameters() { | |
150 var values = {}; | |
151 if (window.location.search) { | |
152 params = window.location.search.substr(1).split("&"); | |
153 for (var i = 0; i < params.length; ++i) { | |
154 var parts = params[i].split("="); | |
155 if (parts.length == 2) { | |
156 values[parts[0]] = decodeURIComponent(parts[1]); | |
157 } | |
158 } | |
159 } | |
160 return values; | |
161 } | |
162 | |
163 /** | |
164 * Checks the URL for query parameters, and applies any with meaning to us. | |
165 */ | |
166 ProfilingApp.prototype.ApplyQueryParameters = function() { | |
167 var params = GetQueryParameters(); | |
168 for (var i = 0; i < this.filters_names_.length; ++i) { | |
169 var d = document.getElementById(this.filters_names_[i]); | |
170 if (this.filters_names_[i] in params) { | |
171 d.value = params[this.filters_names_[i]]; | |
172 } | |
173 } | |
174 }; | |
175 | |
176 /** | |
177 * Updates a part of the UI to show we are waiting for stuff to happen. | |
178 * @param {string} text The message to display. | |
179 */ | |
180 ProfilingApp.prototype.SetLoadingIndicator = function(text) { | |
181 var d = document.getElementById("loading"); | |
182 d.innerHTML = text; | |
183 DomUtil.DisplayNode(d, text != ""); | |
184 }; | |
185 | |
186 /** | |
187 * Gets the name of the currently active view. | |
188 * @return {string} | |
189 */ | |
190 ProfilingApp.prototype.GetCurrentViewName = function() { | |
191 var previous_view = ClassUtil.FindElementByClassName( | |
192 "viewBadge Selected").match("^(.+)_badge$")[1]; | |
193 if (!previous_view) { | |
194 throw "Previous view cannot be found"; | |
195 } | |
196 return previous_view; | |
197 }; | |
198 | |
199 /** | |
200 * Sets |viewName| as the active view. | |
201 * @param {string} viewName | |
202 */ | |
203 ProfilingApp.prototype.SetCurrentViewName = function(viewName) { | |
204 if (!viewName) { | |
205 throw "Can't switch to undefined"; | |
206 } | |
207 ClassUtil.ResetClass("viewBadge", viewName + "_badge", "Selected"); | |
208 }; | |
209 | |
210 /** | |
211 * Switches |viewName| to be the active view. | |
212 * @param {string} viewName | |
213 */ | |
214 ProfilingApp.prototype.SwitchToView = function(viewName) { | |
215 var prevViewName = this.GetCurrentViewName(); | |
216 this.SetCurrentViewName(viewName); | |
217 | |
218 // Hide the previously active view. | |
219 if (this.liveViews_[prevViewName]) { | |
220 this.ShowView(prevViewName, false); | |
221 } | |
222 | |
223 // If a view hasn't been created yet for |viewName|, do so. | |
224 if (!this.liveViews_[viewName]) { | |
225 this.liveViews_[viewName] = | |
226 this.viewFactories_[viewName](this.filters_, this.entries_); | |
227 } | |
228 | |
229 // Show the now active view. | |
230 this.ShowView(viewName, true); | |
231 }; | |
232 | |
233 /** | |
234 * Generic method to change the styling of the view's tab handle to indicate | |
235 * whether it is active, and to show/hide its content pane. | |
236 * This assumes we have given consistent IDs to the elements. | |
237 * | |
238 * @param {string} viewName | |
239 * @param {boolean} visible | |
240 */ | |
241 ProfilingApp.prototype.ShowView = function(viewName, visible) { | |
242 var element = document.getElementById(viewName + "_container"); | |
243 if (!element) { | |
244 throw "Couldn't find " + viewName; | |
245 } | |
246 DomUtil.DisplayNode(element, visible); | |
247 this.liveViews_[viewName].OnShow(visible); | |
248 }; | |
OLD | NEW |