Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / webapp / app_remoting / js / feedback_consent.js
blob6611b8310c348ef5b8bf64cf2f57aade25af6316
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.
5 'use strict';
7 /**
8  * @type {string} The app id (from the webstore) for this application.
9  */
10 var appId = '';
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';
19 /**
20  * @type {string} The network stats at the time the feedback consent dialog
21  *     was shown.
22  */
23 var connectionStats = '';
25 /**
26  * @type {string} JSON representation of recent console error messages.
27  */
28 var consoleErrors = '';
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 = '';
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';
42 /**
43  * @type {Window} The main application window.
44  */
45 var applicationWindow = null;
47 /**
48  * @type {string} An unique identifier that links the feedback post with the
49  *     logs uploaded by the host.
50  */
51 var crashServiceReportId = '';
53 /**
54  * @type {string} The user-selected feedback category, represented by its
55  *     l10n tag.
56  */
57 var selectedCategory = '';
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;
67   /** @type {string} The base URL for Google Feedback. */
68   var url = 'https://www.google.com/tools/feedback/survey/xhtml';
70   /** @type {string} The feedback 'bucket', used for clustering. */
71   var bucket = 'feedback';
73   /** @type {string} The user's locale, used to localize the feedback page. */
74   var locale = chrome.i18n.getMessage('@@ui_locale');
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();
89   // If the VM was successfully abandoned, close the application.
90   if (abandonHost == 'yes') {
91     applicationWindow.close();
92   }
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;
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);
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));
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   }
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);
185 function onCancel() {
186   window.close();
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   }
204 function onToggleLogs() {
205   var includeLogs = document.getElementById('include-logs');
206   if (includeLogs.checked) {
207     crashServiceReportId = generateId();
208   } else {
209     crashServiceReportId = '';
210   }
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);
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);
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);
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   }
272 window.addEventListener('load', onLoad, false);