| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 'use strict'; | |
| 6 | |
| 7 /** | |
| 8 * @type {string} The app id (from the webstore) for this application. | |
| 9 */ | |
| 10 var appId = ''; | |
| 11 | |
| 12 /** | |
| 13 * @type {string} The host id corresponding to the user's VM. The @pending | |
| 14 * place-holder instructs the Orchestrator to abandon any pending host, | |
| 15 * and is used if no host id is provided by the main window. | |
| 16 */ | |
| 17 var hostId = '@pending'; | |
| 18 | |
| 19 /** | |
| 20 * @type {string} The network stats at the time the feedback consent dialog | |
| 21 * was shown. | |
| 22 */ | |
| 23 var connectionStats = ''; | |
| 24 | |
| 25 /** | |
| 26 * @type {string} JSON representation of recent console error messages. | |
| 27 */ | |
| 28 var consoleErrors = ''; | |
| 29 | |
| 30 /** | |
| 31 * @type {string} The most recent id for the session (unless the session is | |
| 32 * longer than 24hrs, this will be the only session id). | |
| 33 */ | |
| 34 var sessionId = ''; | |
| 35 | |
| 36 /** | |
| 37 * @type {string} "no" => user did not request a VM reset; "yes" => VM was | |
| 38 * successfully reset; "failed" => user requested a reset, but it failed. | |
| 39 */ | |
| 40 var abandonHost = 'no'; | |
| 41 | |
| 42 /** | |
| 43 * @type {Window} The main application window. | |
| 44 */ | |
| 45 var applicationWindow = null; | |
| 46 | |
| 47 /** | |
| 48 * @type {string} An unique identifier that links the feedback post with the | |
| 49 * logs uploaded by the host. | |
| 50 */ | |
| 51 var crashServiceReportId = ''; | |
| 52 | |
| 53 /** | |
| 54 * @type {string} The user-selected feedback category, represented by its | |
| 55 * l10n tag. | |
| 56 */ | |
| 57 var selectedCategory = ''; | |
| 58 | |
| 59 /** | |
| 60 * @param {string} email | |
| 61 * @param {string} realName | |
| 62 */ | |
| 63 function onUserInfo(email, realName) { | |
| 64 /** @type {number} Identifies this product to Google Feedback. **/ | |
| 65 var productId = 93407; | |
| 66 | |
| 67 /** @type {string} The base URL for Google Feedback. */ | |
| 68 var url = 'https://www.google.com/tools/feedback/survey/xhtml'; | |
| 69 | |
| 70 /** @type {string} The feedback 'bucket', used for clustering. */ | |
| 71 var bucket = 'feedback'; | |
| 72 | |
| 73 /** @type {string} The user's locale, used to localize the feedback page. */ | |
| 74 var locale = chrome.i18n.getMessage('@@ui_locale'); | |
| 75 | |
| 76 window.open(url + | |
| 77 '?productId=' + productId + | |
| 78 '&bucket=' + escape(bucket) + | |
| 79 '&hl=' + escape(locale) + | |
| 80 '&psd_email=' + escape(email) + | |
| 81 '&psd_hostId=' + escape(hostId) + | |
| 82 '&psd_abandonHost=' + escape(abandonHost) + | |
| 83 '&psd_crashServiceReportId=' + escape(crashServiceReportId) + | |
| 84 '&psd_connectionStats=' + escape(connectionStats) + | |
| 85 '&psd_category=' + escape(selectedCategory) + | |
| 86 '&psd_sessionId=' + escape(sessionId)); | |
| 87 window.close(); | |
| 88 | |
| 89 // If the VM was successfully abandoned, close the application. | |
| 90 if (abandonHost == 'yes') { | |
| 91 applicationWindow.close(); | |
| 92 } | |
| 93 }; | |
| 94 | |
| 95 /** | |
| 96 * @param {boolean} waiting | |
| 97 */ | |
| 98 function setWaiting(waiting) { | |
| 99 var ok = document.getElementById('feedback-consent-ok'); | |
| 100 var cancel = document.getElementById('feedback-consent-cancel'); | |
| 101 var abandon = document.getElementById('abandon-host'); | |
| 102 var working = document.getElementById('working'); | |
| 103 ok.disabled = waiting; | |
| 104 cancel.disabled = waiting; | |
| 105 abandon.disabled = waiting; | |
| 106 working.hidden = !waiting; | |
| 107 } | |
| 108 | |
| 109 function showError() { | |
| 110 setWaiting(false); | |
| 111 var error = document.getElementById('abandon-failed'); | |
| 112 var abandon = document.getElementById('abandon-host'); | |
| 113 var logs = document.getElementById('include-logs'); | |
| 114 var formBody = document.getElementById('form-body'); | |
| 115 error.hidden = false; | |
| 116 abandon.checked = false; | |
| 117 logs.checked = false; | |
| 118 abandonHost = 'failed'; | |
| 119 crashServiceReportId = ''; | |
| 120 formBody.hidden = true; | |
| 121 base.resizeWindowToContent(true); | |
| 122 } | |
| 123 | |
| 124 /** | |
| 125 * @return {string} A random string ID. | |
| 126 */ | |
| 127 function generateId() { | |
| 128 var idArray = new Uint8Array(20); | |
| 129 window.crypto.getRandomValues(idArray); | |
| 130 return window.btoa(String.fromCharCode.apply(null, idArray)); | |
| 131 } | |
| 132 | |
| 133 /** | |
| 134 * @param {string=} token | |
| 135 */ | |
| 136 function onToken(token) { | |
| 137 var getUserInfo = function() { | |
| 138 console.assert(Boolean(token), 'token is undefined.'); | |
| 139 var oauth2Api = new remoting.OAuth2ApiImpl(); | |
| 140 oauth2Api.getUserInfo( | |
| 141 onUserInfo, onUserInfo.bind(null, 'unknown', 'unknown'), | |
| 142 /** @type {string} */(token)); | |
| 143 }; | |
| 144 if (!token) { | |
| 145 onUserInfo('unknown', 'unknown'); | |
| 146 } else { | |
| 147 if (abandonHost == 'yes') { | |
| 148 var body = { | |
| 149 'abandonHost': 'true', | |
| 150 'crashServiceReportId': crashServiceReportId | |
| 151 }; | |
| 152 var uri = remoting.settings.APP_REMOTING_API_BASE_URL + | |
| 153 '/applications/' + appId + | |
| 154 '/hosts/' + hostId + | |
| 155 '/reportIssue'; | |
| 156 var onDone = function(/** !remoting.Xhr.Response */ response) { | |
| 157 if (response.status >= 200 && response.status < 300) { | |
| 158 getUserInfo(); | |
| 159 } else { | |
| 160 showError(); | |
| 161 } | |
| 162 }; | |
| 163 new remoting.Xhr({ | |
| 164 method: 'POST', | |
| 165 url: uri, | |
| 166 jsonContent: body, | |
| 167 oauthToken: token | |
| 168 }).start().then(onDone); | |
| 169 } else { | |
| 170 getUserInfo(); | |
| 171 } | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 function onOk() { | |
| 176 setWaiting(true); | |
| 177 var abandon = /** @type {HTMLInputElement} */ | |
| 178 (document.getElementById('abandon-host')); | |
| 179 if (abandon.checked) { | |
| 180 abandonHost = 'yes'; | |
| 181 } | |
| 182 chrome.identity.getAuthToken({ 'interactive': false }, onToken); | |
| 183 } | |
| 184 | |
| 185 function onCancel() { | |
| 186 window.close(); | |
| 187 } | |
| 188 | |
| 189 function onToggleAbandon() { | |
| 190 var abandon = document.getElementById('abandon-host'); | |
| 191 var includeLogs = document.getElementById('include-logs'); | |
| 192 var includeLogsLabel = document.getElementById('include-logs-label'); | |
| 193 var learnMoreLink = document.getElementById('learn-more'); | |
| 194 includeLogs.disabled = !abandon.checked; | |
| 195 if (abandon.checked) { | |
| 196 includeLogsLabel.classList.remove('disabled'); | |
| 197 learnMoreLink.classList.remove('disabled'); | |
| 198 } else { | |
| 199 includeLogsLabel.classList.add('disabled'); | |
| 200 learnMoreLink.classList.add('disabled'); | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 function onToggleLogs() { | |
| 205 var includeLogs = document.getElementById('include-logs'); | |
| 206 if (includeLogs.checked) { | |
| 207 crashServiceReportId = generateId(); | |
| 208 } else { | |
| 209 crashServiceReportId = ''; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 /** @param {Event} event */ | |
| 214 function onLearnMore(event) { | |
| 215 event.preventDefault(); // Clicking the link should not tick the checkbox. | |
| 216 var learnMoreLink = document.getElementById('learn-more'); | |
| 217 var learnMoreInfobox = document.getElementById('privacy-info'); | |
| 218 learnMoreLink.hidden = true; | |
| 219 learnMoreInfobox.hidden = false; | |
| 220 base.resizeWindowToContent(true); | |
| 221 } | |
| 222 | |
| 223 function onCategorySelect() { | |
| 224 var feedbackCategory = /** @type {HTMLSelectElement} */ | |
| 225 (document.getElementById('feedback-category')); | |
| 226 console.assert(feedbackCategory.selectedOptions.length == 1, | |
| 227 'Expected exactly one selection; got ' + | |
| 228 feedbackCategory.selectedOptions.length + '.'); | |
| 229 var selectedOption = /** @type {HTMLElement} */ | |
| 230 (feedbackCategory.selectedOptions[0]); | |
| 231 selectedCategory = selectedOption.getAttribute('i18n-content'); | |
| 232 var selected = selectedCategory != 'FEEDBACK_CATEGORY_SELECT'; | |
| 233 document.getElementById('feedback-consent-ok').disabled = !selected; | |
| 234 document.getElementById('form-body').hidden = !selected; | |
| 235 base.resizeWindowToContent(false); | |
| 236 } | |
| 237 | |
| 238 function onLoad() { | |
| 239 window.addEventListener('message', onWindowMessage, false); | |
| 240 remoting.settings = new remoting.Settings(); | |
| 241 l10n.localize(); | |
| 242 var ok = document.getElementById('feedback-consent-ok'); | |
| 243 var cancel = document.getElementById('feedback-consent-cancel'); | |
| 244 var abandon = document.getElementById('abandon-host-label'); | |
| 245 var includeLogs = document.getElementById('include-logs-label'); | |
| 246 var learnMoreLink = document.getElementById('learn-more'); | |
| 247 var feedbackCategory = document.getElementById('feedback-category'); | |
| 248 ok.addEventListener('click', onOk, false); | |
| 249 cancel.addEventListener('click', onCancel, false); | |
| 250 abandon.addEventListener('click', onToggleAbandon, false); | |
| 251 includeLogs.addEventListener('click', onToggleLogs, false); | |
| 252 learnMoreLink.addEventListener('click', onLearnMore, false); | |
| 253 feedbackCategory.addEventListener('change', onCategorySelect, false); | |
| 254 base.resizeWindowToContent(true); | |
| 255 } | |
| 256 | |
| 257 /** @param {Event} event */ | |
| 258 function onWindowMessage(event) { | |
| 259 applicationWindow = event.source; | |
| 260 var method = /** @type {string} */ (event.data['method']); | |
| 261 if (method == 'init') { | |
| 262 if (event.data['hostId']) { | |
| 263 hostId = /** @type {string} */ (event.data['hostId']); | |
| 264 } | |
| 265 appId = /** @type {string} */ (event.data['appId']); | |
| 266 connectionStats = /** @type {string} */ (event.data['connectionStats']); | |
| 267 consoleErrors = /** @type {string} */ (event.data['consoleErrors']); | |
| 268 sessionId = /** @type {string} */ (event.data['sessionId']); | |
| 269 } | |
| 270 }; | |
| 271 | |
| 272 window.addEventListener('load', onLoad, false); | |
| OLD | NEW |