Home | History | Annotate | Download | only in resources
      1 // Copyright (c) 2012 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 // Constants.
      6 /** @const */ var FEEDBACK_LANDING_PAGE =
      7     'https://www.google.com/support/chrome/go/feedback_confirmation';
      8 /** @const */ var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;
      9 
     10 var selectedThumbnailDivId = '';
     11 var selectedThumbnailId = '';
     12 var selectedImageUrl;
     13 
     14 var savedThumbnailIds = [];
     15 savedThumbnailIds['current-screenshots'] = '';
     16 savedThumbnailIds['saved-screenshots'] = '';
     17 
     18 var categoryTag = '';
     19 var filePath = '';
     20 var forceDisableScreenshots = false;
     21 var traceId = 0;
     22 
     23 // Globals to manage reading data from the attach a file option.
     24 var attachFileBinaryData = '';
     25 var lastReader = null;
     26 
     27 /**
     28  * Returns the base filename for a given path. Handles only Unix style paths.
     29  * @param {string} path The path to return the basename for.
     30  * @return {string} Basename for the path.
     31  */
     32 function getBaseName(path) {
     33   lastSeparator = path.lastIndexOf('/');
     34   if (lastSeparator == -1)
     35     return '';
     36   else
     37     return path.substr(lastSeparator + 1);
     38 }
     39 
     40 /**
     41  * Selects an image thumbnail in the specified div.
     42  * @param {string} divId The id of the div to search in.
     43  * @param {string} thumbnailId The id of the thumbnail to search for.
     44  */
     45 function selectImage(divId, thumbnailId) {
     46   var thumbnailDivs = $(divId).children;
     47   selectedThumbnailDivId = divId;
     48   if (thumbnailDivs.length == 0) {
     49     $(divId).hidden = true;
     50     return;
     51   }
     52 
     53   for (var i = 0; i < thumbnailDivs.length; i++) {
     54     thumbnailDivs[i].className = 'image-thumbnail-container';
     55 
     56     // If the the current div matches the thumbnail id provided,
     57     // or there is no thumbnail id given, and we're at the first thumbnail.
     58     if (thumbnailDivs[i].id == thumbnailId || (!thumbnailId && !i)) {
     59       thumbnailDivs[i].classList.add('image-thumbnail-container-selected');
     60       selectedThumbnailId = thumbnailDivs[i].id;
     61       savedThumbnailIds[divId] = thumbnailId;
     62     }
     63   }
     64 }
     65 
     66 /**
     67  * Adds an image thumbnail to the specified div.
     68  * @param {string} divId The id of the div to add a screenshot to.
     69  * @param {string} screenshot The URL of the screenshot being added.
     70  */
     71 function addScreenshot(divId, screenshot) {
     72   var thumbnailDiv = document.createElement('div');
     73   thumbnailDiv.className = 'image-thumbnail-container';
     74 
     75   thumbnailDiv.id = divId + '-thumbnailDiv-' + $(divId).children.length;
     76   thumbnailDiv.onclick = function() {
     77     selectImage(divId, thumbnailDiv.id);
     78   };
     79 
     80   var innerDiv = document.createElement('div');
     81   innerDiv.className = 'image-thumbnail';
     82 
     83   var thumbnail = document.createElement('img');
     84   thumbnail.id = thumbnailDiv.id + '-image';
     85   // We add the ?+timestamp to make sure the image URLs are unique
     86   // and Chrome does not load the image from cache.
     87   thumbnail.src = screenshot + '?' + Date.now();
     88   innerDiv.appendChild(thumbnail);
     89 
     90   thumbnailDiv.appendChild(innerDiv);
     91   $(divId).appendChild(thumbnailDiv);
     92 
     93   if (!selectedThumbnailId)
     94     selectImage(divId, thumbnailDiv.id);
     95 }
     96 
     97 /**
     98  * Enables screenshots.
     99  */
    100 function enableScreenshots() {
    101   if (forceDisableScreenshots)
    102     return;
    103   $('screenshot-row').hidden = false;
    104 }
    105 
    106 /**
    107  * Reads the selected file when the user selects a file.
    108  * @param {event} evtFileSelected The on changed event for the file input box.
    109  */
    110 function onFileSelected(evtFileSelected) {
    111   var file = evtFileSelected.target.files[0];
    112   if (!file) {
    113     // User canceled file selection.
    114     $('attach-file-checkbox').checked = false;
    115     attachFileBinaryData = null;
    116     return;
    117   }
    118 
    119   if (file.size > MAX_ATTACH_FILE_SIZE) {
    120     $('attach-error').hidden = false;
    121 
    122     // Clear our selected file.
    123     $('attach-file').value = '';
    124     attachFileBinaryData = null;
    125     $('attach-file-checkbox').checked = false;
    126 
    127     return;
    128   }
    129 
    130   $('attach-error').hidden = true;
    131 
    132   // Abort an existing file read operation if one exists.
    133   if (lastReader) {
    134     lastReader.abort();
    135     lastReader = null;
    136   }
    137 
    138   var reader = new FileReader();
    139   reader.onloadend = function(evtLoadEnd) {
    140     if (evtLoadEnd.target.readyState == FileReader.DONE) {
    141       attachFileBinaryData = evtLoadEnd.target.result;
    142       lastReader = null;
    143       // Check the checkbox so we do send this file. Users can uncheck the
    144       // box if they don't want to send the file.
    145       $('attach-file-checkbox').checked = true;
    146       $('reading-file').hidden = true;
    147       $('send-report-button').disabled = false;
    148     }
    149   };
    150 
    151   lastReader = reader;
    152   reader.readAsBinaryString(file);
    153   $('reading-file').hidden = false;
    154   $('send-report-button').disabled = true;
    155 }
    156 
    157 /**
    158  * Sends the report; after the report is sent, we need to be redirected to
    159  * the landing page, but we shouldn't be able to navigate back, hence
    160  * we open the landing page in a new tab and sendReport closes this tab.
    161  * @return {boolean} True if the report was sent.
    162  */
    163 function sendReport() {
    164   if ($('description-text').value.length == 0) {
    165     alert(loadTimeData.getString('no-description'));
    166     return false;
    167   }
    168 
    169   var imagePath = '';
    170   if ($('screenshot-checkbox').checked && selectedThumbnailId)
    171     imagePath = $(selectedThumbnailId + '-image').src;
    172   var pageUrl = $('page-url-text').value;
    173   if (!$('page-url-checkbox').checked)
    174     pageUrl = '';
    175   var userEmail = $('user-email-text').value;
    176   if (!$('user-email-checkbox').checked)
    177     userEmail = '';
    178 
    179   var reportArray = [pageUrl,
    180                      categoryTag,
    181                      $('description-text').value,
    182                      userEmail,
    183                      imagePath];
    184 
    185   // Add chromeos data if it exists.
    186   if ($('sys-info-checkbox')) {
    187     reportArray = reportArray.concat([String($('sys-info-checkbox').checked)]);
    188     if (!$('performance-info-checkbox').checked) {
    189       traceId = 0;
    190     }
    191     reportArray = reportArray.concat([String(traceId)]);
    192   }
    193 
    194   if ($('attach-file-checkbox') &&
    195       $('attach-file-checkbox').checked) {
    196     if (attachFileBinaryData) {
    197       reportArray = reportArray.concat(
    198           [$('attach-file').files[0].name, btoa(attachFileBinaryData)]);
    199     }
    200   } else if ($('attach-file-custom-checkbox') &&
    201              $('attach-file-custom-checkbox').checked) {
    202     if (filePath)
    203       reportArray = reportArray.concat([filePath, '']);
    204   }
    205 
    206   // open the landing page in a new tab, sendReport will close this one.
    207   window.open(FEEDBACK_LANDING_PAGE, '_blank');
    208   chrome.send('sendReport', reportArray);
    209   return true;
    210 }
    211 
    212 /**
    213  * Click listener for the cancel button.
    214  * @param {Event} e The click event being handled.
    215  */
    216 function cancel(e) {
    217   chrome.send('cancel');
    218   e.preventDefault();
    219 }
    220 
    221 /**
    222  * Select the current screenshots div, restoring the image that was
    223  * selected when we had this div open previously.
    224  */
    225 function currentSelected() {
    226   // TODO(rkc): Change this to use a class instead.
    227   $('current-screenshots').hidden = false;
    228   if ($('saved-screenshots'))
    229     $('saved-screenshots').hidden = true;
    230 
    231   if (selectedThumbnailDivId != 'current-screenshots')
    232     selectImage('current-screenshots',
    233                 savedThumbnailIds['current-screenshots']);
    234 }
    235 
    236 /**
    237  * Select the saved screenshots div, restoring the image that was
    238  * selected when we had this div open previously.
    239  */
    240 function savedSelected() {
    241   if ($('saved-screenshots').childElementCount == 0) {
    242     // setupSavedScreenshots will take care of changing visibility
    243     chrome.send('refreshSavedScreenshots');
    244   } else {
    245     $('current-screenshots').hidden = true;
    246     $('saved-screenshots').hidden = false;
    247     if (selectedThumbnailDivId != 'saved-screenshots')
    248       selectImage('saved-screenshots', savedThumbnailIds['saved-screenshots']);
    249   }
    250 }
    251 
    252 /**
    253  * Change the type of screenshot we're showing to the user from
    254  * the current screenshot to saved screenshots
    255  */
    256 function changeToSaved() {
    257   $('screenshot-label-current').hidden = true;
    258   $('screenshot-label-saved').hidden = false;
    259 
    260   // Change the link to say "go to original"
    261   $('screenshot-link-tosaved').hidden = true;
    262   $('screenshot-link-tocurrent').hidden = false;
    263 
    264   savedSelected();
    265 }
    266 
    267 /**
    268  * Change the type of screenshot we're showing to the user from
    269  * the saved screenshots to the current screenshots
    270  */
    271 function changeToCurrent() {
    272   $('screenshot-label-current').hidden = false;
    273   $('screenshot-label-saved').hidden = true;
    274 
    275   // Change the link to say "go to saved"
    276   $('screenshot-link-tosaved').hidden = false;
    277   $('screenshot-link-tocurrent').hidden = true;
    278 
    279   currentSelected();
    280 }
    281 
    282 <if expr="pp_ifdef('chromeos')">
    283 /**
    284  * Update the page when performance feedback state is changed.
    285  */
    286 function performanceFeedbackChanged() {
    287   if ($('performance-info-checkbox').checked) {
    288     $('attach-file-checkbox').disabled = true;
    289     $('attach-file-checkbox').checked = false;
    290 
    291     $('screenshot-checkbox').disabled = true;
    292     $('screenshot-checkbox').checked = false;
    293   } else {
    294     $('attach-file-checkbox').disabled = false;
    295     $('screenshot-checkbox').disabled = false;
    296   }
    297 }
    298 </if>
    299 
    300 ///////////////////////////////////////////////////////////////////////////////
    301 // Document Functions:
    302 /**
    303  * Window onload handler, sets up the page.
    304  */
    305 function load() {
    306   cr.ui.FocusOutlineManager.forDocument(document);
    307   if ($('attach-file'))
    308     $('attach-file').addEventListener('change', onFileSelected);
    309 
    310   if ($('sysinfo-url')) {
    311     $('sysinfo-url').onclick = function(event) {
    312       chrome.send('openSystemTab');
    313     };
    314   }
    315 
    316 <if expr="pp_ifdef('chromeos')">
    317   $('screenshot-link-tosaved').onclick = changeToSaved;
    318   $('screenshot-link-tocurrent').onclick = changeToCurrent;
    319 
    320   $('performance-info-checkbox').addEventListener(
    321       'change', performanceFeedbackChanged);
    322 </if>
    323   $('send-report-button').onclick = sendReport;
    324   $('cancel-button').onclick = cancel;
    325 
    326   // Set default values for the possible parameters, and then parse the actual
    327   // values from the URL href.
    328   var parameters = {
    329     'description': '',
    330     'categoryTag': '',
    331     'customPageUrl': '',
    332     'filePath': '',
    333     'traceId': 0,
    334   };
    335 
    336   var loc = window.location;
    337   // Split the query string into an array of parameters.
    338   var query = loc.search.substr(1).split('&');
    339   // If we have a query in the hash.
    340   if (loc.hash.indexOf('?') >= 0) {
    341     // Remove the hash and split this query into parameters too.
    342     query = query.concat(loc.hash.substr(loc.hash.indexOf('?') + 1).split('&'));
    343   }
    344   for (var i = 0; i < query.length; i++) {
    345     // Decode and store each parameter value.
    346     parameter = query[i].split('=');
    347     parameters[parameter[0]] = decodeURIComponent(parameter[1]);
    348   }
    349 
    350   // Set the initial description text.
    351   $('description-text').textContent = parameters['description'];
    352   // If a page url is spcified in the parameters, override the default page url.
    353   if (parameters['customPageUrl'] != '') {
    354     $('page-url-text').value = parameters['customPageUrl'];
    355     // and disable the page image, since it doesn't make sense on a custom url.
    356     $('screenshot-checkbox').checked = false;
    357     forceDisableScreenshots = true;
    358   }
    359 
    360   // Pick up the category tag (for most cases this will be an empty string)
    361   categoryTag = parameters['categoryTag'];
    362 
    363   // Pick up the file path for the attached file (only user for this at the
    364   // moment is the quick office extension).
    365   filePath = parameters['filePath'];
    366 
    367   if (filePath != '') {
    368     var baseName = getBaseName(filePath);
    369     if (baseName) {
    370       // Don't let the user choose another file, we were invoked by an
    371       // extension already providing us the file, this report should only
    372       // attach that file, or no file at all.
    373       $('attach-file-container').hidden = true;
    374 
    375       // Set our filename and unhide the "Attach this file" span.
    376       $('attach-file-custom-name').textContent = baseName;
    377       $('attach-file-custom-container').hidden = false;
    378       // No screenshots if we're being invoked by an extension - screenshot was
    379       // never taken.
    380       $('screenshot-checkbox').checked = false;
    381       forceDisableScreenshots = true;
    382     } else {
    383       filePath = '';
    384     }
    385   }
    386 
    387   traceId = parameters['traceId'];
    388   if (traceId != 0 && ($('performance-info-area'))) {
    389     $('performance-info-area').hidden = false;
    390     $('performance-info-checkbox').checked = true;
    391     performanceFeedbackChanged();
    392   }
    393 
    394   chrome.send('getDialogDefaults');
    395   chrome.send('refreshCurrentScreenshot');
    396 }
    397 
    398 function setupCurrentScreenshot(screenshot) {
    399   addScreenshot('current-screenshots', screenshot);
    400 }
    401 
    402 function setupSavedScreenshots(screenshots) {
    403   if (screenshots.length == 0) {
    404     $('saved-screenshots').textContent =
    405         loadTimeData.getString('no-saved-screenshots');
    406 
    407     // Make sure we make the display the message.
    408     $('current-screenshots').hidden = true;
    409     $('saved-screenshots').hidden = false;
    410 
    411     // In case the user tries to send now; fail safe, do not send a screenshot
    412     // at all versus sending the current screenshot.
    413     selectedThumbnailDivId = '';
    414     selectedThumbnailId = '';
    415   } else {
    416     $('saved-screenshots').textContent = '';
    417     for (i = 0; i < screenshots.length; ++i)
    418       addScreenshot('saved-screenshots', screenshots[i]);
    419 
    420     // Now that we have our screenshots, try selecting the saved screenshots
    421     // again.
    422     savedSelected();
    423   }
    424 }
    425 
    426 function setupDialogDefaults(defaults) {
    427   // Current url.
    428   if ($('page-url-text').value == '')
    429     $('page-url-text').value = defaults.currentUrl;
    430   if (defaults.currentUrl == '')
    431     $('page-url-checkbox').checked = false;
    432   // User e-mail.
    433   $('user-email-text').value = defaults.userEmail;
    434   $('user-email-checkbox').checked = defaults.emailCheckboxDefault;
    435 
    436   document.documentElement.classList.toggle('launcher-layout',
    437                                             defaults.launcherFeedback);
    438 
    439   if (!defaults.disableScreenshots)
    440     enableScreenshots();
    441 
    442   if (defaults.useSaved) {
    443     $('screenshot-link-tosaved').hidden = false;
    444   }
    445 }
    446 
    447 window.addEventListener('DOMContentLoaded', load);
    448