OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * This view displays options for importing/exporting the captured data. This | 6 * This view displays options for exporting the captured data. |
7 * view is responsible for the interface and file I/O. The BrowserBridge | |
8 * handles creation and loading of the data dumps. | |
9 * | |
10 * - Has a button to generate a JSON dump. | |
11 * | |
12 * - Has a button to import a JSON dump. | |
13 * | |
14 * - Shows how many events have been captured. | |
15 * @constructor | 7 * @constructor |
16 */ | 8 */ |
17 function DataView() { | 9 function ExportView() { |
18 const mainBoxId = 'dataTabContent'; | 10 const mainBoxId = 'exportTabContent'; |
19 const downloadIframeId = 'dataViewDownloadIframe'; | 11 const downloadIframeId = 'dataViewDownloadIframe'; |
20 const saveFileButtonId = 'dataViewSaveLogFile'; | 12 const saveFileButtonId = 'dataViewSaveLogFile'; |
21 const dataViewSaveStatusTextId = 'dataViewSaveStatusText'; | 13 const dataViewSaveStatusTextId = 'dataViewSaveStatusText'; |
22 const securityStrippingCheckboxId = 'securityStrippingCheckbox'; | 14 const securityStrippingCheckboxId = 'securityStrippingCheckbox'; |
23 const byteLoggingCheckboxId = 'byteLoggingCheckbox'; | |
24 const passivelyCapturedCountId = 'passivelyCapturedCount'; | |
25 const activelyCapturedCountId = 'activelyCapturedCount'; | |
26 const deleteAllId = 'dataViewDeleteAll'; | |
27 const dumpDataDivId = 'dataViewDumpDataDiv'; | 15 const dumpDataDivId = 'dataViewDumpDataDiv'; |
28 const loadedDivId = 'dataViewLoadedDiv'; | |
29 const loadedClientInfoTextId = 'dataViewLoadedClientInfoText'; | |
30 const loadLogFileDropTargetId = 'dataViewDropTarget'; | |
31 const loadLogFileId = 'dataViewLoadLogFile'; | |
32 const dataViewLoadStatusTextId = 'dataViewLoadStatusText'; | |
33 const capturingTextSpanId = 'dataViewCapturingTextSpan'; | |
34 const loggingTextSpanId = 'dataViewLoggingTextSpan'; | |
35 | 16 |
36 DivView.call(this, mainBoxId); | 17 DivView.call(this, mainBoxId); |
37 | 18 |
38 var securityStrippingCheckbox = $(securityStrippingCheckboxId); | 19 var securityStrippingCheckbox = $(securityStrippingCheckboxId); |
39 securityStrippingCheckbox.onclick = | 20 securityStrippingCheckbox.onclick = |
40 this.onSetSecurityStripping_.bind(this, securityStrippingCheckbox); | 21 this.onSetSecurityStripping_.bind(this, securityStrippingCheckbox); |
41 | 22 |
42 var byteLoggingCheckbox = $(byteLoggingCheckboxId); | |
43 byteLoggingCheckbox.onclick = | |
44 this.onSetByteLogging_.bind(this, byteLoggingCheckbox); | |
45 | |
46 this.downloadIframe_ = $(downloadIframeId); | 23 this.downloadIframe_ = $(downloadIframeId); |
47 | 24 |
48 this.saveFileButton_ = $(saveFileButtonId); | 25 this.saveFileButton_ = $(saveFileButtonId); |
49 this.saveFileButton_.onclick = this.onSaveFile_.bind(this); | 26 this.saveFileButton_.onclick = this.onSaveFile_.bind(this); |
50 this.saveStatusText_ = $(dataViewSaveStatusTextId); | 27 this.saveStatusText_ = $(dataViewSaveStatusTextId); |
51 | 28 |
52 this.activelyCapturedCountBox_ = $(activelyCapturedCountId); | |
53 this.passivelyCapturedCountBox_ = $(passivelyCapturedCountId); | |
54 $(deleteAllId).onclick = g_browser.sourceTracker.deleteAllSourceEntries.bind( | |
55 g_browser.sourceTracker); | |
56 | |
57 this.dumpDataDiv_ = $(dumpDataDivId); | 29 this.dumpDataDiv_ = $(dumpDataDivId); |
mmenke
2011/07/29 14:18:53
nit: Not used, so can delete, unless you think we
eroman
2011/07/29 15:15:08
Done.
| |
58 this.capturingTextSpan_ = $(capturingTextSpanId); | |
59 this.loggingTextSpan_ = $(loggingTextSpanId); | |
60 | |
61 this.loadedDiv_ = $(loadedDivId); | |
62 this.loadedClientInfoText_ = $(loadedClientInfoTextId); | |
63 | |
64 this.loadFileElement_ = $(loadLogFileId); | |
65 this.loadFileElement_.onchange = this.logFileChanged.bind(this); | |
66 this.loadStatusText_ = $(dataViewLoadStatusTextId); | |
67 | |
68 var dropTarget = $(loadLogFileDropTargetId); | |
69 dropTarget.ondragenter = this.onDrag.bind(this); | |
70 dropTarget.ondragover = this.onDrag.bind(this); | |
71 dropTarget.ondrop = this.onDrop.bind(this); | |
72 | |
73 this.updateEventCounts_(); | |
74 | 30 |
75 // Track blob for previous log dump so it can be revoked when a new dump is | 31 // Track blob for previous log dump so it can be revoked when a new dump is |
76 // saved. | 32 // saved. |
77 this.lastBlobURL_ = null; | 33 this.lastBlobURL_ = null; |
78 | |
79 g_browser.sourceTracker.addObserver(this); | |
80 } | 34 } |
81 | 35 |
82 inherits(DataView, DivView); | 36 inherits(ExportView, DivView); |
83 | |
84 /** | |
85 * Called whenever a new event is received. | |
86 */ | |
87 DataView.prototype.onSourceEntryUpdated = function(sourceEntry) { | |
88 this.updateEventCounts_(); | |
89 }; | |
90 | |
91 /** | |
92 * Called whenever some log events are deleted. |sourceIds| lists | |
93 * the source IDs of all deleted log entries. | |
94 */ | |
95 DataView.prototype.onSourceEntriesDeleted = function(sourceIds) { | |
96 this.updateEventCounts_(); | |
97 }; | |
98 | |
99 /** | |
100 * Called whenever all log events are deleted. | |
101 */ | |
102 DataView.prototype.onAllSourceEntriesDeleted = function() { | |
103 this.updateEventCounts_(); | |
104 }; | |
105 | |
106 /** | |
107 * Called when a log file is loaded, after clearing the old log entries and | |
108 * loading the new ones. Hides parts of the page related to saving data, and | |
109 * shows those related to loading. Returns true to indicate the view should | |
110 * still be visible. | |
111 */ | |
112 DataView.prototype.onLoadLogFinish = function(data) { | |
113 setNodeDisplay(this.dumpDataDiv_, false); | |
114 setNodeDisplay(this.capturingTextSpan_, false); | |
115 setNodeDisplay(this.loggingTextSpan_, true); | |
116 setNodeDisplay(this.loadedDiv_, true); | |
117 this.updateLoadedClientInfo(); | |
118 return true; | |
119 }; | |
120 | |
121 /** | |
122 * Updates the counters showing how many events have been captured. | |
123 */ | |
124 DataView.prototype.updateEventCounts_ = function() { | |
125 this.activelyCapturedCountBox_.textContent = | |
126 g_browser.sourceTracker.getNumActivelyCapturedEvents(); | |
127 this.passivelyCapturedCountBox_.textContent = | |
128 g_browser.sourceTracker.getNumPassivelyCapturedEvents(); | |
129 }; | |
130 | |
131 /** | |
132 * Depending on the value of the checkbox, enables or disables logging of | |
133 * actual bytes transferred. | |
134 */ | |
135 DataView.prototype.onSetByteLogging_ = function(byteLoggingCheckbox) { | |
136 if (byteLoggingCheckbox.checked) { | |
137 g_browser.setLogLevel(LogLevelType.LOG_ALL); | |
138 } else { | |
139 g_browser.setLogLevel(LogLevelType.LOG_ALL_BUT_BYTES); | |
140 } | |
141 }; | |
142 | 37 |
143 /** | 38 /** |
144 * Depending on the value of the checkbox, enables or disables stripping | 39 * Depending on the value of the checkbox, enables or disables stripping |
145 * cookies and passwords from log dumps and displayed events. | 40 * cookies and passwords from log dumps and displayed events. |
146 */ | 41 */ |
147 DataView.prototype.onSetSecurityStripping_ = | 42 ExportView.prototype.onSetSecurityStripping_ = |
148 function(securityStrippingCheckbox) { | 43 function(securityStrippingCheckbox) { |
149 g_browser.sourceTracker.setSecurityStripping( | 44 g_browser.sourceTracker.setSecurityStripping( |
150 securityStrippingCheckbox.checked); | 45 securityStrippingCheckbox.checked); |
151 }; | 46 }; |
152 | 47 |
153 DataView.prototype.onSecurityStrippingChanged = function() { | 48 ExportView.prototype.onSecurityStrippingChanged = function() { |
154 }; | 49 }; |
155 | 50 |
156 /** | 51 /** |
157 * Called when something is dragged over the drop target. | 52 * Called when a log file is loaded, after clearing the old log entries and |
158 * | 53 * loading the new ones. Returns true to indicate the view should still be |
159 * Returns false to cancel default browser behavior when a single file is being | 54 * visible. |
160 * dragged. When this happens, we may not receive a list of files for security | |
161 * reasons, which is why we allow the |files| array to be empty. | |
162 */ | 55 */ |
163 DataView.prototype.onDrag = function(event) { | 56 DataView.prototype.onLoadLogFinish = function(data) { |
164 return event.dataTransfer.types.indexOf('Files') == -1 || | 57 return true; |
mmenke
2011/07/29 14:18:53
Exporting a loaded log will not work. Currently,
eroman
2011/07/29 15:15:08
Oh weird!
So I actually did test that the export
| |
165 event.dataTransfer.files.length > 1; | |
166 }; | |
167 | |
168 /** | |
169 * Called when something is dropped onto the drop target. If it's a single | |
170 * file, tries to load it as a log file. | |
171 */ | |
172 DataView.prototype.onDrop = function(event) { | |
173 if (event.dataTransfer.types.indexOf('Files') == -1 || | |
174 event.dataTransfer.files.length != 1) { | |
175 return; | |
176 } | |
177 event.preventDefault(); | |
178 | |
179 // Loading a log file may hide the currently active tab. Switch to the data | |
180 // tab to prevent this. | |
181 document.location.hash = 'data'; | |
182 | |
183 this.loadLogFile(event.dataTransfer.files[0]); | |
184 }; | |
185 | |
186 /** | |
187 * Called when a log file is selected. | |
188 * | |
189 * Gets the log file from the input element and tries to read from it. | |
190 */ | |
191 DataView.prototype.logFileChanged = function() { | |
192 this.loadLogFile(this.loadFileElement_.files[0]); | |
193 }; | |
194 | |
195 /** | |
196 * Attempts to read from the File |logFile|. | |
197 */ | |
198 DataView.prototype.loadLogFile = function(logFile) { | |
199 if (logFile) { | |
200 this.setLoadFileStatus('Loading log...', true); | |
201 var fileReader = new FileReader(); | |
202 | |
203 fileReader.onload = this.onLoadLogFile.bind(this, logFile); | |
204 fileReader.onerror = this.onLoadLogFileError.bind(this); | |
205 | |
206 fileReader.readAsText(logFile); | |
207 } | |
208 }; | |
209 | |
210 /** | |
211 * Displays an error message when unable to read the selected log file. | |
212 * Also clears the file input control, so the same file can be reloaded. | |
213 */ | |
214 DataView.prototype.onLoadLogFileError = function(event) { | |
215 this.loadFileElement_.value = null; | |
216 this.setLoadFileStatus( | |
217 'Error ' + getKeyWithValue(FileError, event.target.error.code) + | |
218 '. Unable to read file.', | |
219 false); | |
220 }; | |
221 | |
222 DataView.prototype.onLoadLogFile = function(logFile, event) { | |
223 var result = loadLogFile(event.target.result, logFile.fileName); | |
224 this.setLoadFileStatus(result, false); | |
225 }; | |
226 | |
227 /** | |
228 * Sets the load from file status text, displayed below the load file button, | |
229 * to |text|. Also enables or disables the save/load buttons based on the value | |
230 * of |isLoading|, which must be true if the load process is still ongoing, and | |
231 * false when the operation has stopped, regardless of success of failure. | |
232 * Also, when loading is done, replaces the load button so the same file can be | |
233 * loaded again. | |
234 */ | |
235 DataView.prototype.setLoadFileStatus = function(text, isLoading) { | |
236 this.enableLoadFileElement_(!isLoading); | |
237 this.enableSaveFileButton_(!isLoading); | |
238 this.loadStatusText_.textContent = text; | |
239 this.saveStatusText_.textContent = ''; | |
240 | |
241 if (!isLoading) { | |
242 // Clear the button, so the same file can be reloaded. Recreating the | |
243 // element seems to be the only way to do this. | |
244 var loadFileElementId = this.loadFileElement_.id; | |
245 var loadFileElementOnChange = this.loadFileElement_.onchange; | |
246 this.loadFileElement_.outerHTML = this.loadFileElement_.outerHTML; | |
247 this.loadFileElement_ = $(loadFileElementId); | |
248 this.loadFileElement_.onchange = loadFileElementOnChange; | |
249 } | |
250 }; | 58 }; |
251 | 59 |
252 /** | 60 /** |
253 * Sets the save to file status text, displayed below the save to file button, | 61 * Sets the save to file status text, displayed below the save to file button, |
254 * to |text|. Also enables or disables the save/load buttons based on the value | 62 * to |text|. Also enables or disables the save button based on the value |
255 * of |isSaving|, which must be true if the save process is still ongoing, and | 63 * of |isSaving|, which must be true if the save process is still ongoing, and |
256 * false when the operation has stopped, regardless of success of failure. | 64 * false when the operation has stopped, regardless of success of failure. |
257 */ | 65 */ |
258 DataView.prototype.setSaveFileStatus = function(text, isSaving) { | 66 ExportView.prototype.setSaveFileStatus = function(text, isSaving) { |
259 this.enableSaveFileButton_(!isSaving); | 67 this.enableSaveFileButton_(!isSaving); |
260 this.enableLoadFileElement_(!isSaving); | |
261 this.loadStatusText_.textContent = ''; | |
262 this.saveStatusText_.textContent = text; | 68 this.saveStatusText_.textContent = text; |
263 }; | 69 }; |
264 | 70 |
265 DataView.prototype.enableSaveFileButton_ = function(enabled) { | 71 ExportView.prototype.enableSaveFileButton_ = function(enabled) { |
266 this.saveFileButton_.disabled = !enabled; | 72 this.saveFileButton_.disabled = !enabled; |
267 }; | 73 }; |
268 | 74 |
269 DataView.prototype.enableLoadFileElement_ = function(enabled) { | |
270 this.loadFileElement_.disabled = !enabled; | |
271 }; | |
272 | |
273 /** | 75 /** |
274 * If not already busy loading or saving a log dump, triggers asynchronous | 76 * If not already busy saving a log dump, triggers asynchronous |
275 * generation of log dump and starts waiting for it to complete. | 77 * generation of log dump and starts waiting for it to complete. |
276 */ | 78 */ |
277 DataView.prototype.onSaveFile_ = function() { | 79 ExportView.prototype.onSaveFile_ = function() { |
278 if (this.saveFileButton_.disabled) | 80 if (this.saveFileButton_.disabled) |
279 return; | 81 return; |
280 // Clean up previous blob, if any, to reduce resource usage. | 82 // Clean up previous blob, if any, to reduce resource usage. |
281 if (this.lastBlobURL_) { | 83 if (this.lastBlobURL_) { |
282 window.webkitURL.revokeObjectURL(this.lastBlobURL_); | 84 window.webkitURL.revokeObjectURL(this.lastBlobURL_); |
283 this.lastBlobURL_ = null; | 85 this.lastBlobURL_ = null; |
284 } | 86 } |
285 this.setSaveFileStatus('Preparing data...', true); | 87 this.setSaveFileStatus('Preparing data...', true); |
286 | 88 |
287 createLogDumpAsync(this.onLogDumpCreated_.bind(this)); | 89 createLogDumpAsync(this.onLogDumpCreated_.bind(this)); |
288 }; | 90 }; |
289 | 91 |
290 /** | 92 /** |
291 * Creates a blob url and starts downloading it. | 93 * Creates a blob url and starts downloading it. |
292 */ | 94 */ |
293 DataView.prototype.onLogDumpCreated_ = function(dumpText) { | 95 ExportView.prototype.onLogDumpCreated_ = function(dumpText) { |
294 var blobBuilder = new WebKitBlobBuilder(); | 96 var blobBuilder = new WebKitBlobBuilder(); |
295 blobBuilder.append(dumpText, 'native'); | 97 blobBuilder.append(dumpText, 'native'); |
296 var textBlob = blobBuilder.getBlob('octet/stream'); | 98 var textBlob = blobBuilder.getBlob('octet/stream'); |
297 this.lastBlobURL_ = window.webkitURL.createObjectURL(textBlob); | 99 this.lastBlobURL_ = window.webkitURL.createObjectURL(textBlob); |
298 this.downloadIframe_.src = this.lastBlobURL_; | 100 this.downloadIframe_.src = this.lastBlobURL_; |
299 this.setSaveFileStatus('Dump successful', false); | 101 this.setSaveFileStatus('Dump successful', false); |
300 }; | 102 }; |
301 | |
302 /** | |
303 * Prints some basic information about the environment when the log was made. | |
304 */ | |
305 DataView.prototype.updateLoadedClientInfo = function() { | |
306 this.loadedClientInfoText_.textContent = ''; | |
307 if (typeof(ClientInfo) != 'object') | |
308 return; | |
309 | |
310 var text = []; | |
311 | |
312 // Dumps made with the command line option don't have a date. | |
313 if (ClientInfo.date) { | |
314 text.push('Data exported on: ' + ClientInfo.date); | |
315 text.push(''); | |
316 } | |
317 | |
318 text.push(ClientInfo.name + | |
319 ' ' + ClientInfo.version + | |
320 ' (' + ClientInfo.official + | |
321 ' ' + ClientInfo.cl + | |
322 ') ' + ClientInfo.version_mod); | |
323 text.push('OS Type: ' + ClientInfo.os_type); | |
324 text.push('Command line: ' + ClientInfo.command_line); | |
325 | |
326 this.loadedClientInfoText_.textContent = text.join('\n'); | |
327 }; | |
OLD | NEW |