• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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() {
6var dumpToTextButton = $('dump-to-text');
7var dataDump = $('data-dump');
8dumpToTextButton.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
35var 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  'serverModelType',
48  'SERVER_SPECIFICS',
49  'SPECIFICS',
50];
51
52function 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 */
64function 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 */
90function 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
100function makeBlobUrl(data) {
101  var textBlob = new Blob([data], {type: 'octet/stream'});
102  var blobUrl = window.URL.createObjectURL(textBlob);
103  return blobUrl;
104}
105
106function 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
119function 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 */
132function 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
159function 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
181function 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
190document.addEventListener('DOMContentLoaded', function() {
191  chrome.sync.events.addEventListener(
192      'onReceivedListOfTypes',
193      onReceivedListOfTypes);
194  chrome.sync.requestListOfTypes();
195});
196
197var dumpToFileLink = $('dump-to-file');
198dumpToFileLink.addEventListener('click', function(event) {
199  chrome.sync.getAllNodes(triggerDataDownload);
200});
201})();
202