| OLD | NEW |
| (Empty) |
| 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 /** | |
| 6 * Wrapper for chrome.send. | |
| 7 */ | |
| 8 function chromeSend(func, arg) { | |
| 9 if (arg == undefined) | |
| 10 arg = ''; | |
| 11 | |
| 12 // Convert to string. | |
| 13 if (typeof arg == 'number') | |
| 14 arg = '' + arg; | |
| 15 | |
| 16 chrome.send(func, [arg]); | |
| 17 }; | |
| 18 | |
| 19 /** | |
| 20 * Create a child element. | |
| 21 * | |
| 22 * @param {string} type The type - div, span, etc. | |
| 23 * @param {string} className The class name | |
| 24 * @param {HTMLElement} parent Parent to append this child to. | |
| 25 * @param {string} textContent optional text content of child. | |
| 26 * @param {function(*)} onclick onclick function of child. | |
| 27 */ | |
| 28 function createChild(type, className, parent, textContent, onclick) { | |
| 29 var elem = document.createElement(type); | |
| 30 elem.className = className; | |
| 31 if (textContent !== undefined) | |
| 32 elem.textContent = textContent; | |
| 33 elem.onclick = onclick; | |
| 34 parent.appendChild(elem); | |
| 35 return elem; | |
| 36 }; | |
| 37 | |
| 38 var localStrings; | |
| 39 var downloadRowList; | |
| 40 | |
| 41 function init() { | |
| 42 localStrings = new LocalStrings(); | |
| 43 initTestHarness(); | |
| 44 | |
| 45 window.onkeydown = function(e) { | |
| 46 if (e.keyCode == 27) // Escape. | |
| 47 menu.clear(); | |
| 48 e.preventDefault(); // Suppress browser shortcuts. | |
| 49 }; | |
| 50 | |
| 51 document.body.addEventListener("blur", menu.clear); | |
| 52 document.body.addEventListener("click", menu.clear); | |
| 53 document.body.addEventListener("contextmenu", function (e) { | |
| 54 e.preventDefault(); }); | |
| 55 document.body.addEventListener("selectstart", function (e) { | |
| 56 e.preventDefault(); }); | |
| 57 | |
| 58 var sadt = $('showallfilestext'); | |
| 59 sadt.textContent = localStrings.getString('showallfiles'); | |
| 60 sadt.addEventListener("click", showAllFiles); | |
| 61 | |
| 62 downloadRowList = new DownloadRowList(); | |
| 63 chromeSend('getDownloads'); | |
| 64 } | |
| 65 | |
| 66 /** | |
| 67 * Testing. Allow this page to be loaded in a browser. | |
| 68 * Create stubs for localStrings and chrome.send. | |
| 69 */ | |
| 70 function initTestHarness() { | |
| 71 if (location.protocol != 'file:') | |
| 72 return; | |
| 73 | |
| 74 // Enable right click for dom inspector. | |
| 75 document.body.oncontextmenu = ''; | |
| 76 | |
| 77 // Fix localStrings. | |
| 78 localStrings = { | |
| 79 getString: function(name) { | |
| 80 if (name == 'showallfiles') | |
| 81 return 'Show all files'; | |
| 82 if (name == 'dangerousextension') | |
| 83 return 'Extensions, apps, and themes can harm your computer.' + | |
| 84 ' Are you sure you want to continue?' | |
| 85 if (name == 'continue') | |
| 86 return 'Continue'; | |
| 87 if (name == 'discard') | |
| 88 return 'Discard'; | |
| 89 return name; | |
| 90 }, | |
| 91 getStringF: function(name, path) { | |
| 92 return path + ' - Unknown file type.'; | |
| 93 }, | |
| 94 }; | |
| 95 | |
| 96 // Log chrome.send calls. | |
| 97 chrome.send = function(name, ary) { | |
| 98 console.log('chrome.send ' + name + ' ' + ary); | |
| 99 if (name == 'getDownloads' || | |
| 100 (name == 'openNewFullWindow' && | |
| 101 ary[0] == 'chrome://downloads')) | |
| 102 sendTestResults(); | |
| 103 }; | |
| 104 | |
| 105 // Fix resource images. | |
| 106 var cssRules = document.styleSheets[0].cssRules; | |
| 107 for (var i = 0; i < cssRules.length; i++) { | |
| 108 var cssRule = cssRules[i]; | |
| 109 if (cssRule.selectorText.match(/^div\.icon|^\.menuicon/)) { | |
| 110 cssRule.style.backgroundImage = | |
| 111 cssRule.style.backgroundImage.replace('chrome://resources', 'shared'); | |
| 112 } | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 /** | |
| 117 * Create a results array with test data and call downloadsList. | |
| 118 */ | |
| 119 var testElement; | |
| 120 var testId = 0; | |
| 121 var testResults = []; | |
| 122 function sendTestResults() { | |
| 123 var testState = (testId % 3 == 0 ? 'IN_PROGRESS' : | |
| 124 (testId % 3 == 1 ? 'DANGEROUS' : 'COMPLETE')); | |
| 125 state1 = (testId % 3 == 0); | |
| 126 testResults.push({ | |
| 127 state: testState, | |
| 128 percent: (testId % 3 == 0 ? 90 : 100), | |
| 129 id: testId, | |
| 130 file_name: ' Test' + testId + '.pdf', | |
| 131 file_path: '/home/achuith/Downloads/Test' + testId + '.pdf', | |
| 132 progress_status_text : '107 MB/s - 108 MB of 672 MB, 5 secs left', | |
| 133 }); | |
| 134 testId++; | |
| 135 downloadsList(testResults); | |
| 136 } | |
| 137 | |
| 138 /** | |
| 139 * Current Menu. | |
| 140 */ | |
| 141 var menu = { | |
| 142 current_: null, | |
| 143 | |
| 144 /** | |
| 145 * Close the current menu. | |
| 146 */ | |
| 147 clear: function() { | |
| 148 var current = this.current_; | |
| 149 if (current) { | |
| 150 current.firstChild.style.display = 'none'; | |
| 151 current.style.opacity = ''; | |
| 152 this.current_ = null; | |
| 153 } | |
| 154 }, | |
| 155 | |
| 156 /** | |
| 157 * If it's a second click on an open menu, close the menu. | |
| 158 * Otherwise, close any other open menu and open the clicked menu. | |
| 159 */ | |
| 160 clicked: function(row) { | |
| 161 var menuicon = row.menuicon; | |
| 162 if (this.current_ === menuicon) { | |
| 163 this.clear(); | |
| 164 return; | |
| 165 } | |
| 166 this.clear(); | |
| 167 if (menuicon.firstChild.style.display != 'block') { | |
| 168 menuicon.firstChild.style.display = 'block'; | |
| 169 menuicon.style.opacity = '1'; | |
| 170 menuicon.scrollIntoView(); | |
| 171 this.current_ = menuicon; | |
| 172 } | |
| 173 window.event.stopPropagation(); | |
| 174 }, | |
| 175 }; | |
| 176 | |
| 177 function DiscardResult(result) { | |
| 178 return (result.state == 'CANCELLED' || | |
| 179 result.state == 'INTERRUPTED' || | |
| 180 result.state == 'REMOVING'); | |
| 181 }; | |
| 182 | |
| 183 /** | |
| 184 * C++ api calls. | |
| 185 */ | |
| 186 function downloadsList(results) { | |
| 187 downloadRowList.list(results); | |
| 188 } | |
| 189 | |
| 190 function downloadUpdated(result) { | |
| 191 downloadRowList.update(result); | |
| 192 } | |
| 193 | |
| 194 function showAllFiles() { | |
| 195 chromeSend('showAllFiles'); | |
| 196 } | |
| 197 | |
| 198 /** | |
| 199 * DownloadRow contains all the elements that go into a row of the downloads | |
| 200 * list. It represents a single DownloadItem. | |
| 201 * | |
| 202 * @param {DownloadRowList} list Global DownloadRowList. | |
| 203 * @param {Object} result JSON representation of DownloadItem. | |
| 204 * @constructor | |
| 205 */ | |
| 206 function DownloadRow(list, result) { | |
| 207 this.path = result.file_path; | |
| 208 this.name = result.file_name; | |
| 209 this.fileUrl = result.file_url; | |
| 210 this.list = list; | |
| 211 this.id = result.id; | |
| 212 | |
| 213 this.createRow_(list); | |
| 214 this.createMenu_(); | |
| 215 this.createRowButton_(); | |
| 216 this.setMenuHidden_(true); | |
| 217 } | |
| 218 | |
| 219 DownloadRow.prototype = { | |
| 220 /** | |
| 221 * Create the row html element and book-keeping for the row. | |
| 222 * @param {DownloadRowList} list global DownloadRowList instance. | |
| 223 * @private | |
| 224 */ | |
| 225 createRow_: function(list) { | |
| 226 var elem = document.createElement('li'); | |
| 227 elem.className = 'downloadrow'; | |
| 228 elem.id = this.path; | |
| 229 elem.row = this; | |
| 230 this.element = elem; | |
| 231 | |
| 232 list.append(this); | |
| 233 }, | |
| 234 | |
| 235 setDangerousIcon_: function(warning) { | |
| 236 var escapedPath = encodeURIComponent(this.path).replace(/'/g,'%27'); | |
| 237 this.icon.className = warning ? 'iconwarning' : 'icon'; | |
| 238 this.icon.style.background = warning ? '' : | |
| 239 'url(\'chrome://fileicon/' + escapedPath + | |
| 240 '?iconsize=small\') no-repeat'; | |
| 241 }, | |
| 242 | |
| 243 /** | |
| 244 * Create the row button for the left of the row. | |
| 245 * This contains the icon, filename and error elements. | |
| 246 * @private | |
| 247 */ | |
| 248 createRowButton_: function () { | |
| 249 this.rowbutton = createChild('div', 'rowbutton rowbg', this.element); | |
| 250 | |
| 251 // Icon. | |
| 252 this.icon = createChild('div', 'icon', this.rowbutton); | |
| 253 this.setDangerousIcon_(false); | |
| 254 | |
| 255 // Filename. | |
| 256 this.filename = createChild('span', 'title', this.rowbutton, this.name); | |
| 257 }, | |
| 258 | |
| 259 setMenuHidden_: function(hidden) { | |
| 260 this.menubutton.hidden = hidden; | |
| 261 if (hidden) { | |
| 262 this.rowbutton.style.width = '238px'; | |
| 263 } else { | |
| 264 this.rowbutton.style.width = ''; | |
| 265 } | |
| 266 }, | |
| 267 | |
| 268 /** | |
| 269 * Create the menu button on the right of the row. | |
| 270 * This contains the menuicon. The menuicon contains the menu, which | |
| 271 * contains items for Pause/Resume and Cancel. | |
| 272 * @private | |
| 273 */ | |
| 274 createMenu_: function() { | |
| 275 var self = this; | |
| 276 this.menubutton = createChild('div', 'menubutton rowbg', this.element, '', | |
| 277 function() { | |
| 278 menu.clicked(self); | |
| 279 }); | |
| 280 | |
| 281 this.menuicon = createChild('div', 'menuicon', this.menubutton); | |
| 282 | |
| 283 var menudiv = createChild('div', 'menu', this.menuicon); | |
| 284 | |
| 285 this.pause = createChild('div', 'menuitem', menudiv, | |
| 286 localStrings.getString('pause'), function() { | |
| 287 self.pauseToggleDownload_(); | |
| 288 }); | |
| 289 | |
| 290 this.cancel = createChild('div', 'menuitem', menudiv, | |
| 291 localStrings.getString('cancel'), function() { | |
| 292 self.cancelDownload_(); | |
| 293 }); | |
| 294 }, | |
| 295 | |
| 296 allowDownload_: function() { | |
| 297 chromeSend('allowDownload', this.id); | |
| 298 }, | |
| 299 | |
| 300 cancelDownload_: function() { | |
| 301 chromeSend('cancelDownload', this.id); | |
| 302 }, | |
| 303 | |
| 304 pauseToggleDownload_: function() { | |
| 305 this.pause.textContent = | |
| 306 (this.pause.textContent == localStrings.getString('pause')) ? | |
| 307 localStrings.getString('resume') : | |
| 308 localStrings.getString('pause'); | |
| 309 | |
| 310 chromeSend('pauseToggleDownload', this.id); | |
| 311 }, | |
| 312 | |
| 313 changeElemHeight_: function(elem, x) { | |
| 314 elem.style.height = elem.clientHeight + x + 'px'; | |
| 315 }, | |
| 316 | |
| 317 changeRowHeight_: function(x) { | |
| 318 this.list.rowsHeight += x; | |
| 319 this.changeElemHeight_(this.element, x); | |
| 320 // rowbutton has 5px padding. | |
| 321 this.changeElemHeight_(this.rowbutton, x - 5); | |
| 322 this.list.resize(); | |
| 323 }, | |
| 324 | |
| 325 DANGEROUS_HEIGHT: 60, | |
| 326 createDangerousPrompt_: function(dangerType) { | |
| 327 if (this.dangerous) | |
| 328 return; | |
| 329 | |
| 330 this.dangerous = createChild('div', 'dangerousprompt', this.rowbutton); | |
| 331 | |
| 332 // Handle dangerous files, extensions and dangerous urls. | |
| 333 var dangerText; | |
| 334 if (dangerType == 'DANGEROUS_URL') { | |
| 335 dangerText = localStrings.getString('dangerousurl'); | |
| 336 } else if (dangerType == 'DANGEROUS_CONTENT') { | |
| 337 dangerText = localStrings.getStringF('dangerouscontent', this.name); | |
| 338 } else if (dangerType == 'UNCOMMON_CONTENT') { | |
| 339 dangerText = localStrings.getStringF('uncommoncontent', this.name); | |
| 340 } else if (dangerType == 'DANGEROUS_FILE' && this.path.match(/\.crx$/)) { | |
| 341 dangerText = localStrings.getString('dangerousextension'); | |
| 342 } else { | |
| 343 dangerText = localStrings.getStringF('dangerousfile', this.name); | |
| 344 } | |
| 345 createChild('span', 'dangerousprompttext', this.dangerous, dangerText); | |
| 346 | |
| 347 var self = this; | |
| 348 createChild('span', 'confirm', this.dangerous, | |
| 349 localStrings.getString('discard'), | |
| 350 function() { | |
| 351 self.cancelDownload_(); | |
| 352 }); | |
| 353 createChild('span', 'confirm', this.dangerous, | |
| 354 localStrings.getString('continue'), | |
| 355 function() { | |
| 356 self.allowDownload_(); | |
| 357 }); | |
| 358 | |
| 359 this.changeRowHeight_(this.DANGEROUS_HEIGHT); | |
| 360 this.setDangerousIcon_(true); | |
| 361 }, | |
| 362 | |
| 363 removeDangerousPrompt_: function() { | |
| 364 if (!this.dangerous) | |
| 365 return; | |
| 366 | |
| 367 this.rowbutton.removeChild(this.dangerous); | |
| 368 this.dangerous = null; | |
| 369 | |
| 370 this.changeRowHeight_(-this.DANGEROUS_HEIGHT); | |
| 371 this.setDangerousIcon_(false); | |
| 372 }, | |
| 373 | |
| 374 PROGRESS_HEIGHT: 8, | |
| 375 createProgress_: function() { | |
| 376 if (this.progress) | |
| 377 return; | |
| 378 | |
| 379 this.progress = createChild('div', 'progress', this.rowbutton); | |
| 380 | |
| 381 this.setMenuHidden_(false); | |
| 382 this.changeRowHeight_(this.PROGRESS_HEIGHT); | |
| 383 }, | |
| 384 | |
| 385 removeProgress_: function() { | |
| 386 if (!this.progress) | |
| 387 return; | |
| 388 | |
| 389 this.rowbutton.removeChild(this.progress); | |
| 390 this.progress = null; | |
| 391 | |
| 392 this.changeRowHeight_(-this.PROGRESS_HEIGHT); | |
| 393 this.setMenuHidden_(true); | |
| 394 }, | |
| 395 | |
| 396 updatePause_: function(result) { | |
| 397 var pause = this.pause; | |
| 398 var pauseStr = localStrings.getString('pause'); | |
| 399 var resumeStr = localStrings.getString('resume'); | |
| 400 | |
| 401 if (pause && | |
| 402 result.state == 'PAUSED' && | |
| 403 pause.textContent != resumeStr) { | |
| 404 pause.textContent = resumeStr; | |
| 405 } else if (pause && | |
| 406 result.state == 'IN_PROGRESS' && | |
| 407 pause.textContent != pauseStr) { | |
| 408 pause.textContent = pauseStr; | |
| 409 } | |
| 410 }, | |
| 411 | |
| 412 progressStatusText_: function(progress) { | |
| 413 if (!progress) | |
| 414 return progress; | |
| 415 | |
| 416 /* m looks like this: | |
| 417 ["107 MB/s - 108 MB of 672 MB, 5 secs left", | |
| 418 "107 MB/s", "108", "MB", "672", "MB", "5 secs left"] | |
| 419 We want to return progress text like this: | |
| 420 "108 / 672 MB, 5 secs left" | |
| 421 or | |
| 422 "108 kB / 672 MB, 5 secs left" | |
| 423 */ | |
| 424 var m = progress.match( | |
| 425 /([^-]*) - ([0-9\.]*) ([a-zA-Z]*) of ([0-9\.]*) ([a-zA-Z]*), (.*)/); | |
| 426 if (!m || m.length != 7) | |
| 427 return progress; | |
| 428 | |
| 429 return m[2] + (m[3] == m[5] ? '' : ' ' + m[3]) + | |
| 430 ' / ' + m[4] + ' ' + m[5] + ', ' + m[6]; | |
| 431 }, | |
| 432 | |
| 433 updateProgress_: function(result) { | |
| 434 this.removeDangerousPrompt_(); | |
| 435 this.createProgress_(); | |
| 436 this.progress.textContent = | |
| 437 this.progressStatusText_(result.progress_status_text); | |
| 438 this.updatePause_(result); | |
| 439 }, | |
| 440 | |
| 441 /** | |
| 442 * Called when the item has finished downloading. Switch the menu | |
| 443 * and remove the progress bar. | |
| 444 * @private | |
| 445 */ | |
| 446 finishedDownloading_: function() { | |
| 447 // Make rowbutton clickable. | |
| 448 var self = this; | |
| 449 this.rowbutton.onclick = function() { | |
| 450 chromeSend('viewFile', self.path); | |
| 451 }; | |
| 452 | |
| 453 this.rowbutton.style.cursor = 'pointer'; | |
| 454 | |
| 455 // Make rowbutton draggable. | |
| 456 this.rowbutton.setAttribute('draggable', 'true'); | |
| 457 var self = this; | |
| 458 this.rowbutton.addEventListener('dragstart', function(e) { | |
| 459 e.dataTransfer.effectAllowed = 'copy'; | |
| 460 e.dataTransfer.setData('Text', self.path); | |
| 461 e.dataTransfer.setData('URL', self.fileUrl); | |
| 462 }, false); | |
| 463 | |
| 464 this.removeDangerousPrompt_(); | |
| 465 this.removeProgress_(); | |
| 466 }, | |
| 467 | |
| 468 /** | |
| 469 * One of the DownloadItem we are observing has updated. | |
| 470 * @param {Object} result JSON representation of DownloadItem. | |
| 471 */ | |
| 472 update: function(result) { | |
| 473 this.filename.textContent = result.file_name; | |
| 474 this.id = result.id; | |
| 475 | |
| 476 if (result.state != 'COMPLETE') { | |
| 477 this.rowbutton.onclick = ''; | |
| 478 this.rowbutton.style.cursor = ''; | |
| 479 } | |
| 480 | |
| 481 if (DiscardResult(result)) { | |
| 482 this.list.remove(this); | |
| 483 } else if (result.state == 'DANGEROUS') { | |
| 484 this.createDangerousPrompt_(result.danger_type); | |
| 485 } else if (result.percent < 100) { | |
| 486 this.updateProgress_(result); | |
| 487 } else if (result.state == 'COMPLETE') { | |
| 488 this.finishedDownloading_(); | |
| 489 } | |
| 490 }, | |
| 491 }; | |
| 492 | |
| 493 /** | |
| 494 * DownloadRowList is a container for DownloadRows. | |
| 495 */ | |
| 496 function DownloadRowList() { | |
| 497 this.element = createChild('ul', 'downloadlist', $('main')); | |
| 498 | |
| 499 document.title = localStrings.getString('downloadpath'). | |
| 500 split('/').pop(); | |
| 501 } | |
| 502 | |
| 503 DownloadRowList.prototype = { | |
| 504 | |
| 505 /** | |
| 506 * numRows is the current number of rows. | |
| 507 * rowsHeight is the sum of the heights of all rows. | |
| 508 * rowListHeight is the height of the container containing the rows. | |
| 509 * rows is the list of DownloadRows. | |
| 510 */ | |
| 511 numRows: 0, | |
| 512 rowsHeight: 0, | |
| 513 rowListHeight: 72, | |
| 514 rows: [], | |
| 515 | |
| 516 /** | |
| 517 * Resize the panel to accomodate all rows. | |
| 518 */ | |
| 519 resize: function() { | |
| 520 var diff = this.rowsHeight - this.rowListHeight; | |
| 521 if (diff != 0 && (this.rowListHeight + diff > 72)) { | |
| 522 window.resizeBy(0, diff); | |
| 523 this.rowListHeight += diff; | |
| 524 } | |
| 525 }, | |
| 526 | |
| 527 /** | |
| 528 * Remove a row from the list, as when a download is canceled, or | |
| 529 * the the number of rows has exceeded the max allowed. | |
| 530 * | |
| 531 * @param {DownloadRow} row Row to be removed. | |
| 532 * @private | |
| 533 */ | |
| 534 remove: function(row) { | |
| 535 this.rows.splice(this.rows.indexOf(row), 1); | |
| 536 | |
| 537 this.numRows--; | |
| 538 this.rowsHeight -= row.element.offsetHeight; | |
| 539 this.resize(); | |
| 540 | |
| 541 this.element.removeChild(row.element); | |
| 542 row.element.row = null; | |
| 543 }, | |
| 544 | |
| 545 removeList: function(rows) { | |
| 546 for (i = 0; i < rows.length; i++) { | |
| 547 this.remove(rows[i]); | |
| 548 } | |
| 549 }, | |
| 550 | |
| 551 updateList: function(results) { | |
| 552 for (var i = 0; i < results.length; i++) { | |
| 553 this.update(results[i]); | |
| 554 } | |
| 555 }, | |
| 556 | |
| 557 /** | |
| 558 * Append a new row to the list, removing the last row if we exceed the | |
| 559 * maximum allowed. | |
| 560 * @param {DownloadRow} row Row to be removed. | |
| 561 */ | |
| 562 append: function(row) { | |
| 563 this.rows.push(row); | |
| 564 | |
| 565 var elem = row.element; | |
| 566 var list = this.element; | |
| 567 if (list.firstChild) { | |
| 568 list.insertBefore(elem, list.firstChild); | |
| 569 } else { | |
| 570 list.appendChild(elem); | |
| 571 } | |
| 572 | |
| 573 this.rowsHeight += elem.offsetHeight; | |
| 574 | |
| 575 this.numRows++; | |
| 576 // We display no more than 5 elements. | |
| 577 if (this.numRows > 5) | |
| 578 this.remove(list.lastChild.row); | |
| 579 | |
| 580 this.resize(); | |
| 581 }, | |
| 582 | |
| 583 getRow: function(path) { | |
| 584 for (var i = 0; i < this.rows.length; i++) { | |
| 585 if (this.rows[i].path == path) | |
| 586 return this.rows[i]; | |
| 587 } | |
| 588 }, | |
| 589 | |
| 590 /** | |
| 591 * Returns the list of rows that are not in the results array. | |
| 592 * @param {Array} results Array of JSONified DownloadItems. | |
| 593 */ | |
| 594 findMissing: function(results) { | |
| 595 var removeList = []; | |
| 596 | |
| 597 for (var i = 0; i < this.rows.length; i++) { | |
| 598 var row = this.rows[i]; | |
| 599 var found = false; | |
| 600 for (var j = 0; j < results.length; j++) { | |
| 601 if (row.path == results[j].file_path) { | |
| 602 found = true; | |
| 603 break; | |
| 604 } | |
| 605 } | |
| 606 if (!found) | |
| 607 removeList.push(row); | |
| 608 } | |
| 609 return removeList; | |
| 610 }, | |
| 611 | |
| 612 /** | |
| 613 * Handle list callback with list of DownloadItems. | |
| 614 * @param {Array} results Array of JSONified DownloadItems. | |
| 615 */ | |
| 616 list: function(results) { | |
| 617 var rows = this.findMissing(results); | |
| 618 this.updateList(results); | |
| 619 this.removeList(rows); | |
| 620 }, | |
| 621 | |
| 622 /** | |
| 623 * Handle update of a DownloadItem we're observing. | |
| 624 * @param {Object} result JSON representation of DownloadItem. | |
| 625 */ | |
| 626 update: function(result) { | |
| 627 var row = this.getRow(result.file_path); | |
| 628 if (!row && !DiscardResult(result)) | |
| 629 row = new DownloadRow(this, result); | |
| 630 | |
| 631 row && row.update(result); | |
| 632 }, | |
| 633 }; | |
| 634 | |
| 635 document.addEventListener('DOMContentLoaded', init); | |
| OLD | NEW |