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 (function() { | |
6 var dumpToTextButton = $('dump-to-text'); | |
7 var dataDump = $('data-dump'); | |
8 dumpToTextButton.addEventListener('click', function(event) { | |
9 // TODO(akalin): Add info like Chrome version, OS, date dumped, etc. | |
10 | |
11 var data = ''; | |
12 data += '======\n'; | |
13 data += 'Status\n'; | |
14 data += '======\n'; | |
15 data += JSON.stringify(chrome.sync.aboutInfo, null, 2); | |
16 data += '\n'; | |
17 data += '\n'; | |
18 | |
19 data += '=============\n'; | |
20 data += 'Notifications\n'; | |
21 data += '=============\n'; | |
22 data += JSON.stringify(chrome.sync.notifications, null, 2); | |
23 data += '\n'; | |
24 data += '\n'; | |
25 | |
26 data += '===\n'; | |
27 data += 'Log\n'; | |
28 data += '===\n'; | |
29 data += JSON.stringify(chrome.sync.log.entries, null, 2); | |
30 data += '\n'; | |
31 | |
32 dataDump.textContent = data; | |
33 }); | |
34 | |
35 var allFields = [ | |
36 'ID', | |
37 'IS_UNSYNCED', | |
38 'IS_UNAPPLIED_UPDATE', | |
39 'BASE_VERSION', | |
40 'BASE_VERSION_TIME', | |
41 'SERVER_VERSION', | |
42 'SERVER_VERSION_TIME', | |
43 'PARENT_ID', | |
44 'SERVER_PARENT_ID', | |
45 'IS_DEL', | |
46 'SERVER_IS_DEL', | |
47 'modelType', | |
48 'SERVER_SPECIFICS', | |
49 'SPECIFICS', | |
50 ]; | |
51 | |
52 function versionToDateString(version) { | |
53 // TODO(mmontgomery): ugly? Hacky? Is there a better way? | |
54 var epochLength = Date.now().toString().length; | |
55 var epochTime = parseInt(version.slice(0, epochLength)); | |
56 var date = new Date(epochTime); | |
57 return date.toString(); | |
58 } | |
59 | |
60 /** | |
61 * @param {!Object} node A JavaScript represenation of a sync entity. | |
62 * @return {string} A string representation of the sync entity. | |
63 */ | |
64 function serializeNode(node) { | |
65 return allFields.map(function(field) { | |
66 var fieldVal; | |
67 if (field == 'SERVER_VERSION_TIME') { | |
68 var version = node['SERVER_VERSION']; | |
69 fieldVal = versionToDateString(version); | |
70 } if (field == 'BASE_VERSION_TIME') { | |
71 var version = node['BASE_VERSION']; | |
72 fieldVal = versionToDateString(version); | |
73 } else if ((field == 'SERVER_SPECIFICS' || field == 'SPECIFICS') && | |
74 (!$('include-specifics').checked)) { | |
75 fieldVal = 'REDACTED'; | |
76 } else if ((field == 'SERVER_SPECIFICS' || field == 'SPECIFICS') && | |
77 $('include-specifics').checked) { | |
78 fieldVal = JSON.stringify(node[field]); | |
79 } else { | |
80 fieldVal = node[field]; | |
81 } | |
82 return fieldVal; | |
83 }); | |
84 } | |
85 | |
86 /** | |
87 * @param {string} type The name of a sync model type. | |
88 * @return {boolean} True if the type's checkbox is selected. | |
89 */ | |
90 function isSelectedDatatype(type) { | |
91 var typeCheckbox = $(type); | |
92 // Some types, such as 'Top level folder', appear in the list of nodes | |
93 // but not in the list of selectable items. | |
94 if (typeCheckbox == null) { | |
95 return false; | |
96 } | |
97 return typeCheckbox.checked; | |
98 } | |
99 | |
100 function makeBlobUrl(data) { | |
101 var textBlob = new Blob([data], {type: 'octet/stream'}); | |
102 var blobUrl = window.URL.createObjectURL(textBlob); | |
103 return blobUrl; | |
104 } | |
105 | |
106 function makeDownloadName() { | |
107 // Format is sync-data-dump-$epoch-$year-$month-$day-$OS.csv. | |
108 var now = new Date(); | |
109 var friendlyDate = [now.getFullYear(), | |
110 now.getMonth() + 1, | |
111 now.getDate()].join('-'); | |
112 var name = ['sync-data-dump', | |
113 friendlyDate, | |
114 Date.now(), | |
115 navigator.platform].join('-'); | |
116 return [name, 'csv'].join('.'); | |
117 } | |
118 | |
119 function makeDateUserAgentHeader() { | |
120 var now = new Date(); | |
121 var userAgent = window.navigator.userAgent; | |
122 var dateUaHeader = [now.toISOString(), userAgent].join(','); | |
123 return dateUaHeader; | |
124 } | |
125 | |
126 /** | |
127 * Builds a summary of current state and exports it as a downloaded file. | |
128 * | |
129 * @param {!Array<{type: string, nodes: !Array<!Object>}>} nodesMap | |
130 * Summary of local state by model type. | |
131 */ | |
132 function triggerDataDownload(nodesMap) { | |
133 // Prepend a header with ISO date and useragent. | |
134 var output = [makeDateUserAgentHeader()]; | |
135 output.push('====='); | |
136 | |
137 var aboutInfo = JSON.stringify(chrome.sync.aboutInfo, null, 2); | |
138 output.push(aboutInfo); | |
139 | |
140 // Filter out non-selected types. | |
141 var selectedTypesNodes = nodesMap.filter(function(x) { | |
142 return isSelectedDatatype(x.type); | |
143 }); | |
144 | |
145 // Serialize the remaining nodes and add them to the output. | |
146 selectedTypesNodes.forEach(function(typeNodes) { | |
147 output.push('====='); | |
148 output.push(typeNodes.nodes.map(serializeNode).join('\n')); | |
149 }); | |
150 | |
151 output = output.join('\n'); | |
152 | |
153 var anchor = $('dump-to-file-anchor'); | |
154 anchor.href = makeBlobUrl(output); | |
155 anchor.download = makeDownloadName(); | |
156 anchor.click(); | |
157 } | |
158 | |
159 function createTypesCheckboxes(types) { | |
160 var containerElt = $('node-type-checkboxes'); | |
161 | |
162 types.map(function(type) { | |
163 var div = document.createElement('div'); | |
164 | |
165 var checkbox = document.createElement('input'); | |
166 checkbox.id = type; | |
167 checkbox.type = 'checkbox'; | |
168 checkbox.checked = 'yes'; | |
169 div.appendChild(checkbox); | |
170 | |
171 var label = document.createElement('label'); | |
172 // Assigning to label.for doesn't work. | |
173 label.setAttribute('for', type); | |
174 label.innerText = type; | |
175 div.appendChild(label); | |
176 | |
177 containerElt.appendChild(div); | |
178 }); | |
179 } | |
180 | |
181 function onReceivedListOfTypes(e) { | |
182 var types = e.details.types; | |
183 types.sort(); | |
184 createTypesCheckboxes(types); | |
185 chrome.sync.events.removeEventListener( | |
186 'onReceivedListOfTypes', | |
187 onReceivedListOfTypes); | |
188 } | |
189 | |
190 document.addEventListener('DOMContentLoaded', function() { | |
191 chrome.sync.events.addEventListener( | |
192 'onReceivedListOfTypes', | |
193 onReceivedListOfTypes); | |
194 chrome.sync.requestListOfTypes(); | |
195 }); | |
196 | |
197 var dumpToFileLink = $('dump-to-file'); | |
198 dumpToFileLink.addEventListener('click', function(event) { | |
199 chrome.sync.getAllNodes(triggerDataDownload); | |
200 }); | |
201 })(); | |
OLD | NEW |