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