Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Namespace | 5 // Namespace |
| 6 var importer = importer || {}; | 6 var importer = importer || {}; |
| 7 | 7 |
| 8 /** @enum {string} */ | 8 /** @enum {string} */ |
| 9 importer.ResponseId = { | 9 importer.ResponseId = { |
| 10 HIDDEN: 'hidden', | 10 HIDDEN: 'hidden', |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 * behalf of Cloud Import. | 29 * behalf of Cloud Import. |
| 30 * | 30 * |
| 31 * @constructor | 31 * @constructor |
| 32 * @struct | 32 * @struct |
| 33 * | 33 * |
| 34 * @param {!importer.ControllerEnvironment} environment The class providing | 34 * @param {!importer.ControllerEnvironment} environment The class providing |
| 35 * access to runtime environmental information, like the current directory, | 35 * access to runtime environmental information, like the current directory, |
| 36 * volume lookup and so-on. | 36 * volume lookup and so-on. |
| 37 * @param {!importer.MediaScanner} scanner | 37 * @param {!importer.MediaScanner} scanner |
| 38 * @param {!importer.ImportRunner} importRunner | 38 * @param {!importer.ImportRunner} importRunner |
| 39 * @param {function()} commandUpdateHandler | 39 * @param {!importer.CommandWidget} commandWidget |
| 40 */ | 40 */ |
| 41 importer.ImportController = | 41 importer.ImportController = |
| 42 function(environment, scanner, importRunner, commandUpdateHandler) { | 42 function(environment, scanner, importRunner, commandWidget) { |
| 43 | 43 |
| 44 /** @private {!importer.ControllerEnvironment} */ | 44 /** @private {!importer.ControllerEnvironment} */ |
| 45 this.environment_ = environment; | 45 this.environment_ = environment; |
| 46 | 46 |
| 47 /** @private {!importer.ImportRunner} */ | 47 /** @private {!importer.ImportRunner} */ |
| 48 this.importRunner_ = importRunner; | 48 this.importRunner_ = importRunner; |
| 49 | 49 |
| 50 /** @private {!importer.MediaScanner} */ | 50 /** @private {!importer.MediaScanner} */ |
| 51 this.scanner_ = scanner; | 51 this.scanner_ = scanner; |
| 52 | 52 |
| 53 /** @private {function()} */ | 53 /** @private {!importer.CommandWidget} */ |
| 54 this.updateCommands_ = commandUpdateHandler; | 54 this.commandWidget_ = commandWidget; |
| 55 | 55 |
| 56 /** | 56 /** |
| 57 * A cache of scans by volumeId, directory URL. | 57 * A cache of scans by volumeId, directory URL. |
| 58 * Currently only scans of directories are cached. | 58 * Currently only scans of directories are cached. |
| 59 * @private {!Object.<string, !Object.<string, !importer.ScanResult>>} | 59 * @private {!Object.<string, !Object.<string, !importer.ScanResult>>} |
| 60 */ | 60 */ |
| 61 this.cachedScans_ = {}; | 61 this.cachedScans_ = {}; |
| 62 | 62 |
| 63 var listener = this.onScanEvent_.bind(this); | 63 var listener = this.onScanEvent_.bind(this); |
| 64 this.scanner_.addObserver(listener); | 64 this.scanner_.addObserver(listener); |
| 65 // Remove the observer when the foreground window is closed. | 65 // Remove the observer when the foreground window is closed. |
| 66 window.addEventListener('pagehide', function() { | 66 window.addEventListener( |
| 67 this.scanner_.removeObserver(listener); | 67 'pagehide', |
| 68 }.bind(this)); | 68 function() { |
| 69 this.scanner_.removeObserver(listener); | |
| 70 }.bind(this)); | |
| 71 | |
| 69 this.environment_.addVolumeUnmountListener( | 72 this.environment_.addVolumeUnmountListener( |
| 70 this.onVolumeUnmounted_.bind(this)); | 73 this.onVolumeUnmounted_.bind(this)); |
| 74 | |
| 71 this.environment_.addDirectoryChangedListener( | 75 this.environment_.addDirectoryChangedListener( |
| 72 this.onDirectoryChanged_.bind(this)); | 76 this.onDirectoryChanged_.bind(this)); |
| 77 | |
| 78 this.commandWidget_.addExecuteListener( | |
| 79 this.execute.bind(this)); | |
| 73 }; | 80 }; |
| 74 | 81 |
| 75 /** | 82 /** |
| 76 * @param {!importer.ScanEvent} event Command event. | 83 * @param {!importer.ScanEvent} event Command event. |
| 77 * @param {importer.ScanResult} result | 84 * @param {importer.ScanResult} result |
| 78 * | 85 * |
| 79 * @private | 86 * @private |
| 80 */ | 87 */ |
| 81 importer.ImportController.prototype.onScanEvent_ = function(event, result) { | 88 importer.ImportController.prototype.onScanEvent_ = function(event, result) { |
| 82 if (event === importer.ScanEvent.INVALIDATED) { | 89 if (event === importer.ScanEvent.INVALIDATED) { |
| 83 for (var key in this.cachedScans_) { | 90 for (var key in this.cachedScans_) { |
| 84 for (var url in this.cachedScans_[key]) { | 91 for (var url in this.cachedScans_[key]) { |
| 85 if (this.cachedScans_[key][url].isInvalidated()) { | 92 if (this.cachedScans_[key][url].isInvalidated()) { |
| 86 delete this.cachedScans_[key][url]; | 93 delete this.cachedScans_[key][url]; |
| 87 } | 94 } |
| 88 } | 95 } |
| 89 } | 96 } |
| 90 } | 97 } |
| 91 if (event === importer.ScanEvent.FINALIZED || | 98 if (event === importer.ScanEvent.FINALIZED || |
| 92 event === importer.ScanEvent.INVALIDATED) { | 99 event === importer.ScanEvent.INVALIDATED) { |
| 93 this.updateCommands_(); | 100 this.pushUpdate_(); |
| 94 } | 101 } |
| 95 }; | 102 }; |
| 96 | 103 |
| 97 /** | 104 /** |
| 98 * Executes import against the current directory. Should only | 105 * Executes import against the current directory. Should only |
| 99 * be called when the current directory has been validated | 106 * be called when the current directory has been validated |
| 100 * by calling "update" on this class. | 107 * by calling "update" on this class. |
| 101 */ | 108 */ |
| 102 importer.ImportController.prototype.execute = function() { | 109 importer.ImportController.prototype.execute = function() { |
| 103 metrics.recordEnum('CloudImport.UserAction', 'IMPORT_INITIATED'); | 110 metrics.recordEnum('CloudImport.UserAction', 'IMPORT_INITIATED'); |
| 104 var result = this.getScanForImport_(); | 111 var result = this.getScanForImport_(); |
| 105 var importTask = this.importRunner_.importFromScanResult(result); | 112 var importTask = this.importRunner_.importFromScanResult(result); |
| 106 }; | 113 }; |
| 107 | 114 |
| 108 /** | 115 /** |
| 109 * Called by the 'cloud-import' command when it wants an update | 116 * Push an update to the command widget. |
| 110 * on the command state. | 117 * @private |
| 118 */ | |
| 119 importer.ImportController.prototype.pushUpdate_ = function() { | |
| 120 this.commandWidget_.update(this.getCommandUpdate()); | |
| 121 }; | |
| 122 | |
| 123 /** | |
| 124 * Returns an update describing the state of the CommandWidget. | |
| 111 * | 125 * |
| 112 * @return {!importer.CommandUpdate} response | 126 * @return {!importer.CommandUpdate} response |
| 113 */ | 127 */ |
| 114 importer.ImportController.prototype.getCommandUpdate = function() { | 128 importer.ImportController.prototype.getCommandUpdate = function() { |
| 115 // If there is no Google Drive mount, Drive may be disabled | 129 // If there is no Google Drive mount, Drive may be disabled |
| 116 // or the machine may be running in guest mode. | 130 // or the machine may be running in guest mode. |
| 117 if (this.environment_.isGoogleDriveMounted()) { | 131 if (this.environment_.isGoogleDriveMounted()) { |
| 118 var entries = this.environment_.getSelection(); | 132 var entries = this.environment_.getSelection(); |
| 119 | 133 |
| 120 // Enabled if user has a selection and it consists entirely of files | 134 // Enabled if user has a selection and it consists entirely of files |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 | 271 |
| 258 /** | 272 /** |
| 259 * @param {string} volumeId | 273 * @param {string} volumeId |
| 260 * @private | 274 * @private |
| 261 */ | 275 */ |
| 262 importer.ImportController.prototype.onVolumeUnmounted_ = function(volumeId) { | 276 importer.ImportController.prototype.onVolumeUnmounted_ = function(volumeId) { |
| 263 // Forget all scans related to the unmounted volume volume. | 277 // Forget all scans related to the unmounted volume volume. |
| 264 if (this.cachedScans_.hasOwnProperty(volumeId)) { | 278 if (this.cachedScans_.hasOwnProperty(volumeId)) { |
| 265 delete this.cachedScans_[volumeId]; | 279 delete this.cachedScans_[volumeId]; |
| 266 } | 280 } |
| 281 this.pushUpdate_(); | |
| 282 }; | |
| 283 | |
| 284 /** @private */ | |
| 285 importer.ImportController.prototype.onDirectoryChanged_ = function() { | |
| 286 this.pushUpdate_(); | |
| 267 }; | 287 }; |
| 268 | 288 |
| 269 /** | 289 /** |
| 270 * @param {string} volumeId | |
| 271 * @private | |
| 272 */ | |
| 273 importer.ImportController.prototype.onDirectoryChanged_ = function() { | |
| 274 this.updateCommands_(); | |
| 275 }; | |
| 276 | |
| 277 /** | |
| 278 * Interface abstracting away the concrete file manager available | 290 * Interface abstracting away the concrete file manager available |
| 279 * to commands. By hiding file manager we make it easy to test | 291 * to commands. By hiding file manager we make it easy to test |
| 280 * ImportController. | 292 * ImportController. |
| 281 * | 293 * |
| 282 * @interface | 294 * @interface |
| 283 * @extends {VolumeManagerCommon.VolumeInfoProvider} | 295 * @extends {VolumeManagerCommon.VolumeInfoProvider} |
| 284 */ | 296 */ |
| 285 importer.ControllerEnvironment = function() {}; | 297 importer.ControllerEnvironment = function() {}; |
| 286 | 298 |
| 287 /** | 299 /** |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 // TODO(smckay): remove listeners when the page is torn down. | 403 // TODO(smckay): remove listeners when the page is torn down. |
| 392 this.fileManager_.directoryModel.addEventListener( | 404 this.fileManager_.directoryModel.addEventListener( |
| 393 'directory-changed', | 405 'directory-changed', |
| 394 listener); | 406 listener); |
| 395 }; | 407 }; |
| 396 | 408 |
| 397 /** | 409 /** |
| 398 * Class that adapts from the new non-command button to the old | 410 * Class that adapts from the new non-command button to the old |
| 399 * command style interface. | 411 * command style interface. |
| 400 * | 412 * |
| 401 * <p>NOTE: This adapter is a stop gap bridge between the old-style | 413 * @interface |
| 402 * Command button and our new do-it-yourself toolbar button. We used | 414 */ |
| 403 * an adapter to minimize changes to RuntimeImportController while other | 415 importer.CommandWidget = function() {}; |
| 404 * people are working on that file. Once the dust settles we can make | 416 |
| 405 * more transformative changes. | 417 /** |
| 418 * Install a listener that get's called when the user wants to initiate | |
| 419 * import. | |
| 420 * | |
| 421 * @param {function()} listener | |
| 422 */ | |
| 423 importer.CommandWidget.prototype.addExecuteListener; | |
| 424 | |
| 425 /** | |
| 426 * @param {!importer.CommandUpdate} update | |
| 427 */ | |
| 428 importer.CommandWidget.prototype.update; | |
| 429 | |
| 430 /** | |
| 431 * Runtime implementation of CommandWidget. | |
| 406 * | 432 * |
| 407 * @constructor | 433 * @constructor |
| 434 * @implements {importer.CommandWidget} | |
| 408 * @struct | 435 * @struct |
| 409 * | |
| 410 * @param {!FileManager} fileManager | |
| 411 */ | 436 */ |
| 412 importer.ButtonCommandAdapter = function(fileManager) { | 437 importer.RuntimeCommandWidget = function() { |
| 413 | 438 /** @private {Element} */ |
| 414 /** @param {!FileManager} */ | |
| 415 this.fileManager_ = fileManager; | |
| 416 | |
| 417 /** @param {Element} */ | |
| 418 this.buttonElement_ = document.querySelector('#cloud-import-button'); | 439 this.buttonElement_ = document.querySelector('#cloud-import-button'); |
| 419 | 440 |
| 420 this.buttonElement_.onclick = this.execute_.bind(this); | 441 this.buttonElement_.onclick = this.notifyExecuteListener_.bind(this); |
| 421 | 442 |
| 422 /** @param {Element} */ | 443 /** @private {Element} */ |
| 423 this.iconElement_ = document.querySelector('#cloud-import-button core-icon'); | 444 this.iconElement_ = document.querySelector('#cloud-import-button core-icon'); |
| 445 | |
| 446 /** @private {function()} */ | |
| 447 this.listener_; | |
| 448 }; | |
| 449 | |
| 450 /** @override */ | |
| 451 importer.RuntimeCommandWidget.prototype.addExecuteListener = | |
| 452 function(listener) { | |
| 453 console.assert(!this.listener_); | |
| 454 this.listener_ = listener; | |
| 424 }; | 455 }; |
| 425 | 456 |
| 426 /** @private */ | 457 /** @private */ |
| 427 importer.ButtonCommandAdapter.prototype.execute_ = function() { | 458 importer.RuntimeCommandWidget.prototype.notifyExecuteListener_ = function() { |
| 428 this.fileManager_.importController.execute(); | 459 console.assert(!!this.listener_); |
| 460 this.listener_(); | |
| 429 }; | 461 }; |
| 430 | 462 |
| 431 /** | 463 /** @override */ |
| 432 * @param {!Event} event Command event. | 464 importer.RuntimeCommandWidget.prototype.update = function(update) { |
| 433 * @param {!FileManager} fileManager | |
| 434 */ | |
| 435 importer.ButtonCommandAdapter.prototype.update = function() { | |
| 436 if (this.fileManager_.importController) { | |
| 437 var update = fileManager.importController.getCommandUpdate(); | |
| 438 this.buttonElement_.setAttribute('title', update.label); | 465 this.buttonElement_.setAttribute('title', update.label); |
| 439 this.buttonElement_.disabled = !update.executable; | 466 this.buttonElement_.disabled = !update.executable; |
| 440 this.buttonElement_.style.display = update.visible ? 'block' : 'none'; | 467 this.buttonElement_.style.display = update.visible ? 'block' : 'none'; |
| 441 this.iconElement_.setAttribute('icon', update.coreIcon); | 468 this.iconElement_.setAttribute('icon', update.coreIcon); |
| 442 } else { | |
| 443 this.buttonElement_.setAttribute('display', 'none'); | |
| 444 this.iconElement_.setAttribute('icon', 'cloud-off'); | |
| 445 } | |
| 446 }; | 469 }; |
| 470 | |
|
mtomasz
2015/01/28 22:54:03
nit: remove \n
| |
| OLD | NEW |