• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2013 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/** @type {string}
6 * @const
7 */
8var FEEDBACK_LANDING_PAGE =
9    'https://www.google.com/support/chrome/go/feedback_confirmation';
10/** @type {number}
11 * @const
12 */
13var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;
14
15/**
16 * @type {number}
17 * @const
18 */
19var FEEDBACK_MIN_WIDTH = 500;
20/**
21 * @type {number}
22 * @const
23 */
24var FEEDBACK_MIN_HEIGHT = 585;
25
26/** @type {number}
27 * @const
28 */
29var CONTENT_MARGIN_HEIGHT = 40;
30
31/** @type {number}
32 * @const
33 */
34var MAX_SCREENSHOT_WIDTH = 100;
35
36/** @type {string}
37 * @const
38 */
39var SYSINFO_WINDOW_ID = 'sysinfo_window';
40
41/** @type {string}
42 * @const
43 */
44var STATS_WINDOW_ID = 'stats_window';
45
46var attachedFileBlob = null;
47var lastReader = null;
48
49var feedbackInfo = null;
50var systemInfo = null;
51
52/**
53 * Reads the selected file when the user selects a file.
54 * @param {Event} fileSelectedEvent The onChanged event for the file input box.
55 */
56function onFileSelected(fileSelectedEvent) {
57  $('attach-error').hidden = true;
58  var file = fileSelectedEvent.target.files[0];
59  if (!file) {
60    // User canceled file selection.
61    attachedFileBlob = null;
62    return;
63  }
64
65  if (file.size > MAX_ATTACH_FILE_SIZE) {
66    $('attach-error').hidden = false;
67
68    // Clear our selected file.
69    $('attach-file').value = '';
70    attachedFileBlob = null;
71    return;
72  }
73
74  attachedFileBlob = file.slice();
75}
76
77/**
78 * Clears the file that was attached to the report with the initial request.
79 * Instead we will now show the attach file button in case the user wants to
80 * attach another file.
81 */
82function clearAttachedFile() {
83  $('custom-file-container').hidden = true;
84  attachedFileBlob = null;
85  feedbackInfo.attachedFile = null;
86  $('attach-file').hidden = false;
87}
88
89/**
90 * Creates a closure that creates or shows a window with the given url.
91 * @param {string} windowId A string with the ID of the window we are opening.
92 * @param {string} url The destination URL of the new window.
93 * @return {function()} A function to be called to open the window.
94 */
95function windowOpener(windowId, url) {
96  return function(e) {
97    e.preventDefault();
98    chrome.app.window.create(url, {id: windowId});
99  };
100}
101
102/**
103 * Opens a new window with chrome://slow_trace, downloading performance data.
104 */
105function openSlowTraceWindow() {
106  chrome.app.window.create(
107      'chrome://slow_trace/tracing.zip#' + feedbackInfo.traceId);
108}
109
110/**
111 * Sends the report; after the report is sent, we need to be redirected to
112 * the landing page, but we shouldn't be able to navigate back, hence
113 * we open the landing page in a new tab and sendReport closes this tab.
114 * @return {boolean} True if the report was sent.
115 */
116function sendReport() {
117  if ($('description-text').value.length == 0) {
118    var description = $('description-text');
119    description.placeholder = loadTimeData.getString('no-description');
120    description.focus();
121    return false;
122  }
123
124  // Prevent double clicking from sending additional reports.
125  $('send-report-button').disabled = true;
126  console.log('Feedback: Sending report');
127  if (!feedbackInfo.attachedFile && attachedFileBlob) {
128    feedbackInfo.attachedFile = { name: $('attach-file').value,
129                                  data: attachedFileBlob };
130  }
131
132  feedbackInfo.description = $('description-text').value;
133  feedbackInfo.pageUrl = $('page-url-text').value;
134  feedbackInfo.email = $('user-email-text').value;
135
136  var useSystemInfo = false;
137  var useHistograms = false;
138  if ($('sys-info-checkbox') != null &&
139      $('sys-info-checkbox').checked &&
140      systemInfo != null) {
141    // Send histograms along with system info.
142    useSystemInfo = useHistograms = true;
143  }
144<if expr="chromeos">
145  if ($('performance-info-checkbox') == null ||
146      !($('performance-info-checkbox').checked)) {
147    feedbackInfo.traceId = null;
148  }
149</if>
150
151  if (useSystemInfo) {
152    if (feedbackInfo.systemInformation != null) {
153      // Concatenate sysinfo if we had any initial system information
154      // sent with the feedback request event.
155      feedbackInfo.systemInformation =
156          feedbackInfo.systemInformation.concat(systemInfo);
157    } else {
158      feedbackInfo.systemInformation = systemInfo;
159    }
160  }
161
162  feedbackInfo.sendHistograms = useHistograms;
163
164  // If the user doesn't want to send the screenshot.
165  if (!$('screenshot-checkbox').checked)
166    feedbackInfo.screenshot = null;
167
168  chrome.feedbackPrivate.sendFeedback(feedbackInfo, function(result) {
169    window.open(FEEDBACK_LANDING_PAGE, '_blank');
170    window.close();
171  });
172
173  return true;
174}
175
176/**
177 * Click listener for the cancel button.
178 * @param {Event} e The click event being handled.
179 */
180function cancel(e) {
181  e.preventDefault();
182  window.close();
183}
184
185/**
186 * Converts a blob data URL to a blob object.
187 * @param {string} url The data URL to convert.
188 * @return {Blob} Blob object containing the data.
189 */
190function dataUrlToBlob(url) {
191  var mimeString = url.split(',')[0].split(':')[1].split(';')[0];
192  var data = atob(url.split(',')[1]);
193  var dataArray = [];
194  for (var i = 0; i < data.length; ++i)
195    dataArray.push(data.charCodeAt(i));
196
197  return new Blob([new Uint8Array(dataArray)], {type: mimeString});
198}
199
200<if expr="chromeos">
201/**
202 * Update the page when performance feedback state is changed.
203 */
204function performanceFeedbackChanged() {
205  if ($('performance-info-checkbox').checked) {
206    $('attach-file').disabled = true;
207    $('attach-file').checked = false;
208
209    $('screenshot-checkbox').disabled = true;
210    $('screenshot-checkbox').checked = false;
211  } else {
212    $('attach-file').disabled = false;
213    $('screenshot-checkbox').disabled = false;
214  }
215}
216</if>
217
218function resizeAppWindow() {
219  // We pick the width from the titlebar, which has no margins.
220  var width = $('title-bar').scrollWidth;
221  if (width < FEEDBACK_MIN_WIDTH)
222    width = FEEDBACK_MIN_WIDTH;
223
224  // We get the height by adding the titlebar height and the content height +
225  // margins. We can't get the margins for the content-pane here by using
226  // style.margin - the variable seems to not exist.
227  var height = $('title-bar').scrollHeight +
228      $('content-pane').scrollHeight + CONTENT_MARGIN_HEIGHT;
229  if (height < FEEDBACK_MIN_HEIGHT)
230    height = FEEDBACK_MIN_HEIGHT;
231
232  chrome.app.window.current().resizeTo(width, height);
233}
234
235/**
236 * Initializes our page.
237 * Flow:
238 * .) DOMContent Loaded        -> . Request feedbackInfo object
239 *                                . Setup page event handlers
240 * .) Feedback Object Received -> . take screenshot
241 *                                . request email
242 *                                . request System info
243 *                                . request i18n strings
244 * .) Screenshot taken         -> . Show Feedback window.
245 */
246function initialize() {
247  // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
248  console.log('FEEDBACK_DEBUG: feedback.js: initialize()');
249
250  // Add listener to receive the feedback info object.
251  chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
252    if (request.sentFromEventPage) {
253      // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
254      console.log('FEEDBACK_DEBUG: Received feedbackInfo.');
255      feedbackInfo = request.data;
256      $('description-text').textContent = feedbackInfo.description;
257      if (feedbackInfo.pageUrl)
258        $('page-url-text').value = feedbackInfo.pageUrl;
259
260      takeScreenshot(function(screenshotCanvas) {
261        // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
262        console.log('FEEDBACK_DEBUG: Taken screenshot. Showing window.');
263
264        // We've taken our screenshot, show the feedback page without any
265        // further delay.
266        window.webkitRequestAnimationFrame(function() {
267          resizeAppWindow();
268        });
269        chrome.app.window.current().show();
270
271        var screenshotDataUrl = screenshotCanvas.toDataURL('image/png');
272        $('screenshot-image').src = screenshotDataUrl;
273        $('screenshot-image').classList.toggle('wide-screen',
274            $('screenshot-image').width > MAX_SCREENSHOT_WIDTH);
275        feedbackInfo.screenshot = dataUrlToBlob(screenshotDataUrl);
276      });
277
278      chrome.feedbackPrivate.getUserEmail(function(email) {
279        $('user-email-text').value = email;
280      });
281
282      chrome.feedbackPrivate.getSystemInformation(function(sysInfo) {
283        systemInfo = sysInfo;
284      });
285
286      // An extension called us with an attached file.
287      if (feedbackInfo.attachedFile) {
288        $('attached-filename-text').textContent =
289            feedbackInfo.attachedFile.name;
290        attachedFileBlob = feedbackInfo.attachedFile.data;
291        $('custom-file-container').hidden = false;
292        $('attach-file').hidden = true;
293      }
294
295<if expr="chromeos">
296      if (feedbackInfo.traceId && ($('performance-info-area'))) {
297        $('performance-info-area').hidden = false;
298        $('performance-info-checkbox').checked = true;
299        performanceFeedbackChanged();
300        $('performance-info-link').onclick = openSlowTraceWindow;
301      }
302</if>
303
304      chrome.feedbackPrivate.getStrings(function(strings) {
305        loadTimeData.data = strings;
306        i18nTemplate.process(document, loadTimeData);
307
308        if ($('sys-info-url')) {
309          // Opens a new window showing the current system info.
310          $('sys-info-url').onclick =
311              windowOpener(SYSINFO_WINDOW_ID, 'chrome://system');
312        }
313        if ($('histograms-url')) {
314          // Opens a new window showing the histogram metrics.
315          $('histograms-url').onclick =
316              windowOpener(STATS_WINDOW_ID, 'chrome://histograms');
317        }
318      });
319    }
320  });
321
322  window.addEventListener('DOMContentLoaded', function() {
323    // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
324    console.log('FEEDBACK_DEBUG: feedback.js: DOMContentLoaded');
325    // Ready to receive the feedback object.
326    chrome.runtime.sendMessage({ready: true});
327
328    // Setup our event handlers.
329    $('attach-file').addEventListener('change', onFileSelected);
330    $('send-report-button').onclick = sendReport;
331    $('cancel-button').onclick = cancel;
332    $('remove-attached-file').onclick = clearAttachedFile;
333<if expr="chromeos">
334    $('performance-info-checkbox').addEventListener(
335        'change', performanceFeedbackChanged);
336</if>
337  });
338}
339
340initialize();
341