| 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 |