| 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 /** | 5 /** |
| 6 * Called from the main frame when unloading. | 6 * Called from the main frame when unloading. |
| 7 * @param {boolean=} opt_exiting True if the app is exiting. | 7 * @param {boolean=} opt_exiting True if the app is exiting. |
| 8 */ | 8 */ |
| 9 function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting); } | 9 function unload(opt_exiting) { gallery.onUnload(opt_exiting); } |
| 10 | 10 |
| 11 /** | 11 /** |
| 12 * Overrided metadata worker's path. | 12 * Overrided metadata worker's path. |
| 13 * @type {string} | 13 * @type {string} |
| 14 * @const | |
| 15 */ | 14 */ |
| 16 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; | 15 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; |
| 17 | 16 |
| 18 /** | 17 /** |
| 19 * Data model for gallery. | 18 * Data model for gallery. |
| 20 * | 19 * |
| 21 * @param {MetadataCache} metadataCache Metadata cache. | 20 * @param {!MetadataCache} metadataCache Metadata cache. |
| 22 * @constructor | 21 * @constructor |
| 23 * @extends {cr.ui.ArrayDataModel} | 22 * @extends {cr.ui.ArrayDataModel} |
| 24 */ | 23 */ |
| 25 function GalleryDataModel(metadataCache) { | 24 function GalleryDataModel(metadataCache) { |
| 26 cr.ui.ArrayDataModel.call(this, []); | 25 cr.ui.ArrayDataModel.call(this, []); |
| 27 | 26 |
| 28 /** | 27 /** |
| 29 * Metadata cache. | 28 * Metadata cache. |
| 30 * @type {MetadataCache} | 29 * @type {!MetadataCache} |
| 31 * @private | 30 * @private |
| 32 */ | 31 */ |
| 33 this.metadataCache_ = metadataCache; | 32 this.metadataCache_ = metadataCache; |
| 34 | 33 |
| 35 /** | 34 /** |
| 36 * Directory where the image is saved if the image is located in a read-only | 35 * Directory where the image is saved if the image is located in a read-only |
| 37 * volume. | 36 * volume. |
| 38 * @type {DirectoryEntry} | 37 * @type {DirectoryEntry} |
| 39 */ | 38 */ |
| 40 this.fallbackSaveDirectory = null; | 39 this.fallbackSaveDirectory = null; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 56 */ | 55 */ |
| 57 GalleryDataModel.MAX_SCREEN_IMAGE_CACHE_ = 5; | 56 GalleryDataModel.MAX_SCREEN_IMAGE_CACHE_ = 5; |
| 58 | 57 |
| 59 GalleryDataModel.prototype = { | 58 GalleryDataModel.prototype = { |
| 60 __proto__: cr.ui.ArrayDataModel.prototype | 59 __proto__: cr.ui.ArrayDataModel.prototype |
| 61 }; | 60 }; |
| 62 | 61 |
| 63 /** | 62 /** |
| 64 * Saves new image. | 63 * Saves new image. |
| 65 * | 64 * |
| 66 * @param {VolumeManager} volumeManager Volume manager instance. | 65 * @param {!VolumeManager} volumeManager Volume manager instance. |
| 67 * @param {Gallery.Item} item Original gallery item. | 66 * @param {!Gallery.Item} item Original gallery item. |
| 68 * @param {HTMLCanvasElement} canvas Canvas containing new image. | 67 * @param {!HTMLCanvasElement} canvas Canvas containing new image. |
| 69 * @param {boolean} overwrite Whether to overwrite the image to the item or not. | 68 * @param {boolean} overwrite Whether to overwrite the image to the item or not. |
| 70 * @return {Promise} Promise to be fulfilled with when the operation completes. | 69 * @return {!Promise} Promise to be fulfilled with when the operation completes. |
| 71 */ | 70 */ |
| 72 GalleryDataModel.prototype.saveItem = function( | 71 GalleryDataModel.prototype.saveItem = function( |
| 73 volumeManager, item, canvas, overwrite) { | 72 volumeManager, item, canvas, overwrite) { |
| 74 var oldEntry = item.getEntry(); | 73 var oldEntry = item.getEntry(); |
| 75 var oldMetadata = item.getMetadata(); | 74 var oldMetadata = item.getMetadata(); |
| 76 var oldLocationInfo = item.getLocationInfo(); | 75 var oldLocationInfo = item.getLocationInfo(); |
| 77 var metadataEncoder = ImageEncoder.encodeMetadata( | 76 var metadataEncoder = ImageEncoder.encodeMetadata( |
| 78 item.getMetadata(), canvas, 1 /* quality */); | 77 item.getMetadata(), canvas, 1 /* quality */); |
| 79 var newMetadata = ContentProvider.ConvertContentMetadata( | 78 var newMetadata = ContentProvider.ConvertContentMetadata( |
| 80 metadataEncoder.getMetadata(), | 79 metadataEncoder.getMetadata(), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 this.splice(this.indexOf(item) + 1, 0, anotherItem); | 129 this.splice(this.indexOf(item) + 1, 0, anotherItem); |
| 131 } | 130 } |
| 132 | 131 |
| 133 fulfill(); | 132 fulfill(); |
| 134 }.bind(this)); | 133 }.bind(this)); |
| 135 }.bind(this)); | 134 }.bind(this)); |
| 136 }; | 135 }; |
| 137 | 136 |
| 138 /** | 137 /** |
| 139 * Evicts image caches in the items. | 138 * Evicts image caches in the items. |
| 140 * @param {Gallery.Item} currentSelectedItem Current selected item. | |
| 141 */ | 139 */ |
| 142 GalleryDataModel.prototype.evictCache = function(currentSelectedItem) { | 140 GalleryDataModel.prototype.evictCache = function() { |
| 143 // Sort the item by the last accessed date. | 141 // Sort the item by the last accessed date. |
| 144 var sorted = this.slice().sort(function(a, b) { | 142 var sorted = this.slice().sort(function(a, b) { |
| 145 return b.getLastAccessedDate() - a.getLastAccessedDate(); | 143 return b.getLastAccessedDate() - a.getLastAccessedDate(); |
| 146 }); | 144 }); |
| 147 | 145 |
| 148 // Evict caches. | 146 // Evict caches. |
| 149 var contentCacheCount = 0; | 147 var contentCacheCount = 0; |
| 150 var screenCacheCount = 0; | 148 var screenCacheCount = 0; |
| 151 for (var i = 0; i < sorted.length; i++) { | 149 for (var i = 0; i < sorted.length; i++) { |
| 152 if (sorted[i].contentImage) { | 150 if (sorted[i].contentImage) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 175 } | 173 } |
| 176 } | 174 } |
| 177 }; | 175 }; |
| 178 | 176 |
| 179 /** | 177 /** |
| 180 * Gallery for viewing and editing image files. | 178 * Gallery for viewing and editing image files. |
| 181 * | 179 * |
| 182 * @param {!VolumeManager} volumeManager The VolumeManager instance of the | 180 * @param {!VolumeManager} volumeManager The VolumeManager instance of the |
| 183 * system. | 181 * system. |
| 184 * @constructor | 182 * @constructor |
| 183 * @struct |
| 185 */ | 184 */ |
| 186 function Gallery(volumeManager) { | 185 function Gallery(volumeManager) { |
| 186 /** |
| 187 * @type {{appWindow: chrome.app.window.AppWindow, onClose: function(), |
| 188 * onMaximize: function(), onMinimize: function(), |
| 189 * onAppRegionChanged: function(), metadataCache: MetadataCache, |
| 190 * readonlyDirName: string, displayStringFunction: function(), |
| 191 * loadTimeData: Object, curDirEntry: Entry, searchResults: *}} |
| 192 * @private |
| 193 * |
| 194 * TODO(yawano): curDirEntry and searchResults seem not to be used. |
| 195 * Investigate them and remove them if possible. |
| 196 */ |
| 187 this.context_ = { | 197 this.context_ = { |
| 188 appWindow: chrome.app.window.current(), | 198 appWindow: chrome.app.window.current(), |
| 189 onClose: function() { close(); }, | 199 onClose: function() { window.close(); }, |
| 190 onMaximize: function() { | 200 onMaximize: function() { |
| 191 var appWindow = chrome.app.window.current(); | 201 var appWindow = chrome.app.window.current(); |
| 192 if (appWindow.isMaximized()) | 202 if (appWindow.isMaximized()) |
| 193 appWindow.restore(); | 203 appWindow.restore(); |
| 194 else | 204 else |
| 195 appWindow.maximize(); | 205 appWindow.maximize(); |
| 196 }, | 206 }, |
| 197 onMinimize: function() { chrome.app.window.current().minimize(); }, | 207 onMinimize: function() { chrome.app.window.current().minimize(); }, |
| 198 onAppRegionChanged: function() {}, | 208 onAppRegionChanged: function() {}, |
| 199 metadataCache: MetadataCache.createFull(volumeManager), | 209 metadataCache: MetadataCache.createFull(volumeManager), |
| 200 readonlyDirName: '', | 210 readonlyDirName: '', |
| 201 displayStringFunction: function() { return ''; }, | 211 displayStringFunction: function() { return ''; }, |
| 202 loadTimeData: {} | 212 loadTimeData: {}, |
| 213 curDirEntry: null, |
| 214 searchResults: null |
| 203 }; | 215 }; |
| 204 this.container_ = document.querySelector('.gallery'); | 216 this.container_ = queryRequiredElement(document, '.gallery'); |
| 205 this.document_ = document; | 217 this.document_ = document; |
| 206 this.metadataCache_ = this.context_.metadataCache; | 218 this.metadataCache_ = this.context_.metadataCache; |
| 207 this.volumeManager_ = volumeManager; | 219 this.volumeManager_ = volumeManager; |
| 208 this.selectedEntry_ = null; | 220 this.selectedEntry_ = null; |
| 209 this.metadataCacheObserverId_ = null; | 221 this.metadataCacheObserverId_ = null; |
| 210 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); | 222 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); |
| 211 | 223 |
| 212 this.dataModel_ = new GalleryDataModel( | 224 this.dataModel_ = new GalleryDataModel( |
| 213 this.context_.metadataCache); | 225 this.context_.metadataCache); |
| 214 var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( | 226 var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( |
| 215 VolumeManagerCommon.VolumeType.DOWNLOADS); | 227 VolumeManagerCommon.VolumeType.DOWNLOADS); |
| 216 downloadVolumeInfo.resolveDisplayRoot().then(function(entry) { | 228 downloadVolumeInfo.resolveDisplayRoot().then(function(entry) { |
| 217 this.dataModel_.fallbackSaveDirectory = entry; | 229 this.dataModel_.fallbackSaveDirectory = entry; |
| 218 }.bind(this)).catch(function(error) { | 230 }.bind(this)).catch(function(error) { |
| 219 console.error( | 231 console.error( |
| 220 'Failed to obtain the fallback directory: ' + (error.stack || error)); | 232 'Failed to obtain the fallback directory: ' + (error.stack || error)); |
| 221 }); | 233 }); |
| 222 this.selectionModel_ = new cr.ui.ListSelectionModel(); | 234 this.selectionModel_ = new cr.ui.ListSelectionModel(); |
| 223 | 235 |
| 224 this.initDom_(); | 236 /** |
| 225 this.initListeners_(); | 237 * @type {(SlideMode|MosaicMode)} |
| 226 } | 238 * @private |
| 239 */ |
| 240 this.currentMode_ = null; |
| 227 | 241 |
| 228 /** | 242 /** |
| 229 * Gallery extends cr.EventTarget. | 243 * @type {boolean} |
| 230 */ | 244 * @private |
| 231 Gallery.prototype.__proto__ = cr.EventTarget.prototype; | 245 */ |
| 246 this.changingMode_ = false; |
| 232 | 247 |
| 233 /** | 248 // ----------------------------------------------------------------- |
| 234 * Tools fade-out timeout in milliseconds. | 249 // Initializes the UI. |
| 235 * @const | |
| 236 * @type {number} | |
| 237 */ | |
| 238 Gallery.FADE_TIMEOUT = 2000; | |
| 239 | 250 |
| 240 /** | |
| 241 * First time tools fade-out timeout in milliseconds. | |
| 242 * @const | |
| 243 * @type {number} | |
| 244 */ | |
| 245 Gallery.FIRST_FADE_TIMEOUT = 1000; | |
| 246 | |
| 247 /** | |
| 248 * Time until mosaic is initialized in the background. Used to make gallery | |
| 249 * in the slide mode load faster. In milliseconds. | |
| 250 * @const | |
| 251 * @type {number} | |
| 252 */ | |
| 253 Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000; | |
| 254 | |
| 255 /** | |
| 256 * Types of metadata Gallery uses (to query the metadata cache). | |
| 257 * @const | |
| 258 * @type {string} | |
| 259 */ | |
| 260 Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|external'; | |
| 261 | |
| 262 /** | |
| 263 * Initializes listeners. | |
| 264 * @private | |
| 265 */ | |
| 266 Gallery.prototype.initListeners_ = function() { | |
| 267 this.keyDownBound_ = this.onKeyDown_.bind(this); | |
| 268 this.document_.body.addEventListener('keydown', this.keyDownBound_); | |
| 269 | |
| 270 this.inactivityWatcher_ = new MouseInactivityWatcher( | |
| 271 this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this)); | |
| 272 | |
| 273 // Search results may contain files from different subdirectories so | |
| 274 // the observer is not going to work. | |
| 275 if (!this.context_.searchResults && this.context_.curDirEntry) { | |
| 276 this.metadataCacheObserverId_ = this.metadataCache_.addObserver( | |
| 277 this.context_.curDirEntry, | |
| 278 MetadataCache.CHILDREN, | |
| 279 'thumbnail', | |
| 280 this.updateThumbnails_.bind(this)); | |
| 281 } | |
| 282 this.volumeManager_.addEventListener( | |
| 283 'externally-unmounted', this.onExternallyUnmountedBound_); | |
| 284 }; | |
| 285 | |
| 286 /** | |
| 287 * Closes gallery when a volume containing the selected item is unmounted. | |
| 288 * @param {!Event} event The unmount event. | |
| 289 * @private | |
| 290 */ | |
| 291 Gallery.prototype.onExternallyUnmounted_ = function(event) { | |
| 292 if (!this.selectedEntry_) | |
| 293 return; | |
| 294 | |
| 295 if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) === | |
| 296 event.volumeInfo) { | |
| 297 close(); | |
| 298 } | |
| 299 }; | |
| 300 | |
| 301 /** | |
| 302 * Unloads the Gallery. | |
| 303 * @param {boolean} exiting True if the app is exiting. | |
| 304 */ | |
| 305 Gallery.prototype.onUnload = function(exiting) { | |
| 306 if (this.metadataCacheObserverId_ !== null) | |
| 307 this.metadataCache_.removeObserver(this.metadataCacheObserverId_); | |
| 308 this.volumeManager_.removeEventListener( | |
| 309 'externally-unmounted', this.onExternallyUnmountedBound_); | |
| 310 this.slideMode_.onUnload(exiting); | |
| 311 }; | |
| 312 | |
| 313 /** | |
| 314 * Initializes DOM UI | |
| 315 * @private | |
| 316 */ | |
| 317 Gallery.prototype.initDom_ = function() { | |
| 318 // Initialize the dialog label. | 251 // Initialize the dialog label. |
| 319 cr.ui.dialogs.BaseDialog.OK_LABEL = str('GALLERY_OK_LABEL'); | 252 cr.ui.dialogs.BaseDialog.OK_LABEL = str('GALLERY_OK_LABEL'); |
| 320 cr.ui.dialogs.BaseDialog.CANCEL_LABEL = str('GALLERY_CANCEL_LABEL'); | 253 cr.ui.dialogs.BaseDialog.CANCEL_LABEL = str('GALLERY_CANCEL_LABEL'); |
| 321 | 254 |
| 322 var content = document.querySelector('#content'); | 255 var content = queryRequiredElement(document, '#content'); |
| 323 content.addEventListener('click', this.onContentClick_.bind(this)); | 256 content.addEventListener('click', this.onContentClick_.bind(this)); |
| 324 | 257 |
| 325 this.header_ = document.querySelector('#header'); | 258 this.header_ = queryRequiredElement(document, '#header'); |
| 326 this.toolbar_ = document.querySelector('#toolbar'); | 259 this.toolbar_ = queryRequiredElement(document, '#toolbar'); |
| 327 | 260 |
| 328 var preventDefault = function(event) { event.preventDefault(); }; | 261 var preventDefault = function(event) { event.preventDefault(); }; |
| 329 | 262 |
| 330 var minimizeButton = util.createChild(this.header_, | 263 var minimizeButton = util.createChild(this.header_, |
| 331 'minimize-button tool dimmable', | 264 'minimize-button tool dimmable', |
| 332 'button'); | 265 'button'); |
| 333 minimizeButton.tabIndex = -1; | 266 minimizeButton.tabIndex = -1; |
| 334 minimizeButton.addEventListener('click', this.onMinimize_.bind(this)); | 267 minimizeButton.addEventListener('click', this.onMinimize_.bind(this)); |
| 335 minimizeButton.addEventListener('mousedown', preventDefault); | 268 minimizeButton.addEventListener('mousedown', preventDefault); |
| 336 | 269 |
| 337 var maximizeButton = util.createChild(this.header_, | 270 var maximizeButton = util.createChild(this.header_, |
| 338 'maximize-button tool dimmable', | 271 'maximize-button tool dimmable', |
| 339 'button'); | 272 'button'); |
| 340 maximizeButton.tabIndex = -1; | 273 maximizeButton.tabIndex = -1; |
| 341 maximizeButton.addEventListener('click', this.onMaximize_.bind(this)); | 274 maximizeButton.addEventListener('click', this.onMaximize_.bind(this)); |
| 342 maximizeButton.addEventListener('mousedown', preventDefault); | 275 maximizeButton.addEventListener('mousedown', preventDefault); |
| 343 | 276 |
| 344 var closeButton = util.createChild(this.header_, | 277 var closeButton = util.createChild(this.header_, |
| 345 'close-button tool dimmable', | 278 'close-button tool dimmable', |
| 346 'button'); | 279 'button'); |
| 347 closeButton.tabIndex = -1; | 280 closeButton.tabIndex = -1; |
| 348 closeButton.addEventListener('click', this.onClose_.bind(this)); | 281 closeButton.addEventListener('click', this.onClose_.bind(this)); |
| 349 closeButton.addEventListener('mousedown', preventDefault); | 282 closeButton.addEventListener('mousedown', preventDefault); |
| 350 | 283 |
| 351 this.filenameSpacer_ = this.toolbar_.querySelector('.filename-spacer'); | 284 this.filenameSpacer_ = queryRequiredElement(this.toolbar_, |
| 285 '.filename-spacer'); |
| 352 this.filenameEdit_ = util.createChild(this.filenameSpacer_, | 286 this.filenameEdit_ = util.createChild(this.filenameSpacer_, |
| 353 'namebox', 'input'); | 287 'namebox', 'input'); |
| 354 | 288 |
| 355 this.filenameEdit_.setAttribute('type', 'text'); | 289 this.filenameEdit_.setAttribute('type', 'text'); |
| 356 this.filenameEdit_.addEventListener('blur', | 290 this.filenameEdit_.addEventListener('blur', |
| 357 this.onFilenameEditBlur_.bind(this)); | 291 this.onFilenameEditBlur_.bind(this)); |
| 358 | 292 |
| 359 this.filenameEdit_.addEventListener('focus', | 293 this.filenameEdit_.addEventListener('focus', |
| 360 this.onFilenameFocus_.bind(this)); | 294 this.onFilenameFocus_.bind(this)); |
| 361 | 295 |
| 362 this.filenameEdit_.addEventListener('keydown', | 296 this.filenameEdit_.addEventListener('keydown', |
| 363 this.onFilenameEditKeydown_.bind(this)); | 297 this.onFilenameEditKeydown_.bind(this)); |
| 364 | 298 |
| 365 var middleSpacer = this.filenameSpacer_ = | 299 var middleSpacer = queryRequiredElement(this.toolbar_, '.middle-spacer'); |
| 366 this.toolbar_.querySelector('.middle-spacer'); | 300 var buttonSpacer = queryRequiredElement(this.toolbar_, '.button-spacer'); |
| 367 var buttonSpacer = this.toolbar_.querySelector('button-spacer'); | |
| 368 | 301 |
| 369 this.prompt_ = new ImageEditor.Prompt(this.container_, strf); | 302 this.prompt_ = new ImageEditor.Prompt(this.container_, strf); |
| 370 | 303 |
| 371 this.errorBanner_ = new ErrorBanner(this.container_); | 304 this.errorBanner_ = new ErrorBanner(this.container_); |
| 372 | 305 |
| 373 this.modeButton_ = this.toolbar_.querySelector('button.mode'); | 306 this.modeButton_ = queryRequiredElement(this.toolbar_, 'button.mode'); |
| 374 this.modeButton_.addEventListener('click', this.toggleMode_.bind(this, null)); | 307 this.modeButton_.addEventListener('click', |
| 308 this.toggleMode_.bind(this, undefined)); |
| 375 | 309 |
| 376 this.mosaicMode_ = new MosaicMode(content, | 310 this.mosaicMode_ = new MosaicMode(content, |
| 377 this.errorBanner_, | 311 this.errorBanner_, |
| 378 this.dataModel_, | 312 this.dataModel_, |
| 379 this.selectionModel_, | 313 this.selectionModel_, |
| 380 this.volumeManager_, | 314 this.volumeManager_, |
| 381 this.toggleMode_.bind(this, null)); | 315 this.toggleMode_.bind(this)); |
| 382 | 316 |
| 383 this.slideMode_ = new SlideMode(this.container_, | 317 this.slideMode_ = new SlideMode(this.container_, |
| 384 content, | 318 content, |
| 385 this.toolbar_, | 319 this.toolbar_, |
| 386 this.prompt_, | 320 this.prompt_, |
| 387 this.errorBanner_, | 321 this.errorBanner_, |
| 388 this.dataModel_, | 322 this.dataModel_, |
| 389 this.selectionModel_, | 323 this.selectionModel_, |
| 390 this.context_, | 324 this.context_, |
| 391 this.volumeManager_, | 325 this.volumeManager_, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 406 this.shareButton_.addEventListener( | 340 this.shareButton_.addEventListener( |
| 407 'click', this.onShareButtonClick_.bind(this)); | 341 'click', this.onShareButtonClick_.bind(this)); |
| 408 | 342 |
| 409 this.dataModel_.addEventListener('splice', this.onSplice_.bind(this)); | 343 this.dataModel_.addEventListener('splice', this.onSplice_.bind(this)); |
| 410 this.dataModel_.addEventListener('content', this.onContentChange_.bind(this)); | 344 this.dataModel_.addEventListener('content', this.onContentChange_.bind(this)); |
| 411 | 345 |
| 412 this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); | 346 this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); |
| 413 this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this)); | 347 this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this)); |
| 414 | 348 |
| 415 this.shareDialog_ = new ShareDialog(this.container_); | 349 this.shareDialog_ = new ShareDialog(this.container_); |
| 350 |
| 351 // ----------------------------------------------------------------- |
| 352 // Initialize listeners. |
| 353 |
| 354 this.keyDownBound_ = this.onKeyDown_.bind(this); |
| 355 this.document_.body.addEventListener('keydown', this.keyDownBound_); |
| 356 |
| 357 this.inactivityWatcher_ = new MouseInactivityWatcher( |
| 358 this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this)); |
| 359 |
| 360 // Search results may contain files from different subdirectories so |
| 361 // the observer is not going to work. |
| 362 if (!this.context_.searchResults && this.context_.curDirEntry) { |
| 363 this.metadataCacheObserverId_ = this.metadataCache_.addObserver( |
| 364 this.context_.curDirEntry, |
| 365 MetadataCache.CHILDREN, |
| 366 'thumbnail', |
| 367 this.updateThumbnails_.bind(this)); |
| 368 } |
| 369 this.volumeManager_.addEventListener( |
| 370 'externally-unmounted', this.onExternallyUnmountedBound_); |
| 371 } |
| 372 |
| 373 /** |
| 374 * Gallery extends cr.EventTarget. |
| 375 */ |
| 376 Gallery.prototype.__proto__ = cr.EventTarget.prototype; |
| 377 |
| 378 /** |
| 379 * Tools fade-out timeout in milliseconds. |
| 380 * @const |
| 381 * @type {number} |
| 382 */ |
| 383 Gallery.FADE_TIMEOUT = 2000; |
| 384 |
| 385 /** |
| 386 * First time tools fade-out timeout in milliseconds. |
| 387 * @const |
| 388 * @type {number} |
| 389 */ |
| 390 Gallery.FIRST_FADE_TIMEOUT = 1000; |
| 391 |
| 392 /** |
| 393 * Time until mosaic is initialized in the background. Used to make gallery |
| 394 * in the slide mode load faster. In milliseconds. |
| 395 * @const |
| 396 * @type {number} |
| 397 */ |
| 398 Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000; |
| 399 |
| 400 /** |
| 401 * Types of metadata Gallery uses (to query the metadata cache). |
| 402 * @const |
| 403 * @type {string} |
| 404 */ |
| 405 Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|external'; |
| 406 |
| 407 /** |
| 408 * Closes gallery when a volume containing the selected item is unmounted. |
| 409 * @param {!Event} event The unmount event. |
| 410 * @private |
| 411 */ |
| 412 Gallery.prototype.onExternallyUnmounted_ = function(event) { |
| 413 if (!this.selectedEntry_) |
| 414 return; |
| 415 |
| 416 if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) === |
| 417 event.volumeInfo) { |
| 418 window.close(); |
| 419 } |
| 416 }; | 420 }; |
| 417 | 421 |
| 418 /** | 422 /** |
| 423 * Unloads the Gallery. |
| 424 * @param {boolean=} opt_exiting True if the app is exiting. |
| 425 */ |
| 426 Gallery.prototype.onUnload = function(opt_exiting) { |
| 427 if (this.metadataCacheObserverId_ !== null) |
| 428 this.metadataCache_.removeObserver(this.metadataCacheObserverId_); |
| 429 this.volumeManager_.removeEventListener( |
| 430 'externally-unmounted', this.onExternallyUnmountedBound_); |
| 431 }; |
| 432 |
| 433 /** |
| 419 * Initializes a toolbar button. | 434 * Initializes a toolbar button. |
| 420 * | 435 * |
| 421 * @param {string} className Class to add. | 436 * @param {string} className Class to add. |
| 422 * @param {string} title Button title. | 437 * @param {string} title Button title. |
| 423 * @return {!HTMLElement} Newly created button. | 438 * @return {!HTMLElement} Newly created button. |
| 424 * @private | 439 * @private |
| 425 */ | 440 */ |
| 426 Gallery.prototype.initToolbarButton_ = function(className, title) { | 441 Gallery.prototype.initToolbarButton_ = function(className, title) { |
| 427 var button = this.toolbar_.querySelector('button.' + className); | 442 var button = queryRequiredElement(this.toolbar_, 'button.' + className); |
| 428 button.title = str(title); | 443 button.title = str(title); |
| 429 return button; | 444 return button; |
| 430 }; | 445 }; |
| 431 | 446 |
| 432 /** | 447 /** |
| 433 * Loads the content. | 448 * Loads the content. |
| 434 * | 449 * |
| 435 * @param {!Array.<Entry>} entries Array of entries. | 450 * @param {!Array.<Entry>} entries Array of entries. |
| 436 * @param {!Array.<Entry>} selectedEntries Array of selected entries. | 451 * @param {!Array.<Entry>} selectedEntries Array of selected entries. |
| 437 */ | 452 */ |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 | 607 |
| 593 /** | 608 /** |
| 594 * Executes a function when the editor is done with the modifications. | 609 * Executes a function when the editor is done with the modifications. |
| 595 * @param {function()} callback Function to execute. | 610 * @param {function()} callback Function to execute. |
| 596 */ | 611 */ |
| 597 Gallery.prototype.executeWhenReady = function(callback) { | 612 Gallery.prototype.executeWhenReady = function(callback) { |
| 598 this.currentMode_.executeWhenReady(callback); | 613 this.currentMode_.executeWhenReady(callback); |
| 599 }; | 614 }; |
| 600 | 615 |
| 601 /** | 616 /** |
| 602 * @return {Object} File manager private API. | 617 * @return {!Object} File manager private API. |
| 603 */ | 618 */ |
| 604 Gallery.getFileManagerPrivate = function() { | 619 Gallery.getFileManagerPrivate = function() { |
| 605 return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate; | 620 return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate; |
| 606 }; | 621 }; |
| 607 | 622 |
| 608 /** | 623 /** |
| 609 * @return {boolean} True if some tool is currently active. | 624 * @return {boolean} True if some tool is currently active. |
| 610 */ | 625 */ |
| 611 Gallery.prototype.hasActiveTool = function() { | 626 Gallery.prototype.hasActiveTool = function() { |
| 612 return (this.currentMode_ && this.currentMode_.hasActiveTool()) || | 627 return (this.currentMode_ && this.currentMode_.hasActiveTool()) || |
| 613 this.isRenaming_(); | 628 this.isRenaming_(); |
| 614 }; | 629 }; |
| 615 | 630 |
| 616 /** | 631 /** |
| 617 * External user action event handler. | 632 * External user action event handler. |
| 618 * @private | 633 * @private |
| 619 */ | 634 */ |
| 620 Gallery.prototype.onUserAction_ = function() { | 635 Gallery.prototype.onUserAction_ = function() { |
| 621 // Show the toolbar and hide it after the default timeout. | 636 // Show the toolbar and hide it after the default timeout. |
| 622 this.inactivityWatcher_.kick(); | 637 this.inactivityWatcher_.kick(); |
| 623 }; | 638 }; |
| 624 | 639 |
| 625 /** | 640 /** |
| 626 * Sets the current mode, update the UI. | 641 * Sets the current mode, update the UI. |
| 627 * @param {Object} mode Current mode. | 642 * @param {!(SlideMode|MosaicMode)} mode Current mode. |
| 628 * @private | 643 * @private |
| 629 */ | 644 */ |
| 630 Gallery.prototype.setCurrentMode_ = function(mode) { | 645 Gallery.prototype.setCurrentMode_ = function(mode) { |
| 631 if (mode !== this.slideMode_ && mode !== this.mosaicMode_) | 646 if (mode !== this.slideMode_ && mode !== this.mosaicMode_) |
| 632 console.error('Invalid Gallery mode'); | 647 console.error('Invalid Gallery mode'); |
| 633 | 648 |
| 634 this.currentMode_ = mode; | 649 this.currentMode_ = mode; |
| 635 this.container_.setAttribute('mode', this.currentMode_.getName()); | 650 this.container_.setAttribute('mode', this.currentMode_.getName()); |
| 636 this.updateSelectionAndState_(); | 651 this.updateSelectionAndState_(); |
| 637 this.updateButtons_(); | 652 this.updateButtons_(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 666 var tileRect = mosaic.getTileRect(tileIndex); | 681 var tileRect = mosaic.getTileRect(tileIndex); |
| 667 | 682 |
| 668 if (this.currentMode_ === this.slideMode_) { | 683 if (this.currentMode_ === this.slideMode_) { |
| 669 this.setCurrentMode_(this.mosaicMode_); | 684 this.setCurrentMode_(this.mosaicMode_); |
| 670 mosaic.transform( | 685 mosaic.transform( |
| 671 tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */); | 686 tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */); |
| 672 this.slideMode_.leave( | 687 this.slideMode_.leave( |
| 673 tileRect, | 688 tileRect, |
| 674 function() { | 689 function() { |
| 675 // Animate back to normal position. | 690 // Animate back to normal position. |
| 676 mosaic.transform(); | 691 mosaic.transform(null, null); |
| 677 mosaic.show(); | 692 mosaic.show(); |
| 678 onModeChanged(); | 693 onModeChanged(); |
| 679 }.bind(this)); | 694 }.bind(this)); |
| 680 } else { | 695 } else { |
| 681 this.setCurrentMode_(this.slideMode_); | 696 this.setCurrentMode_(this.slideMode_); |
| 682 this.slideMode_.enter( | 697 this.slideMode_.enter( |
| 683 tileRect, | 698 tileRect, |
| 684 function() { | 699 function() { |
| 685 // Animate to zoomed position. | 700 // Animate to zoomed position. |
| 686 mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect()); | 701 mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 this.selectionModel_.leadIndex = -1; | 751 this.selectionModel_.leadIndex = -1; |
| 737 // Remove items from the data model, starting from the highest index. | 752 // Remove items from the data model, starting from the highest index. |
| 738 while (indexesToRemove.length) | 753 while (indexesToRemove.length) |
| 739 this.dataModel_.splice(indexesToRemove.pop(), 1); | 754 this.dataModel_.splice(indexesToRemove.pop(), 1); |
| 740 // Delete actual files. | 755 // Delete actual files. |
| 741 deleteNext(); | 756 deleteNext(); |
| 742 }.bind(this), | 757 }.bind(this), |
| 743 function() { | 758 function() { |
| 744 // Restore the listener after a timeout so that ESC is processed. | 759 // Restore the listener after a timeout so that ESC is processed. |
| 745 setTimeout(restoreListener, 0); | 760 setTimeout(restoreListener, 0); |
| 746 }); | 761 }, |
| 762 null); |
| 747 }; | 763 }; |
| 748 | 764 |
| 749 /** | 765 /** |
| 750 * @return {Array.<Gallery.Item>} Current selection. | 766 * @return {!Array.<Gallery.Item>} Current selection. |
| 751 */ | 767 */ |
| 752 Gallery.prototype.getSelectedItems = function() { | 768 Gallery.prototype.getSelectedItems = function() { |
| 753 return this.selectionModel_.selectedIndexes.map( | 769 return this.selectionModel_.selectedIndexes.map( |
| 754 this.dataModel_.item.bind(this.dataModel_)); | 770 this.dataModel_.item.bind(this.dataModel_)); |
| 755 }; | 771 }; |
| 756 | 772 |
| 757 /** | 773 /** |
| 758 * @return {Array.<Entry>} Array of currently selected entries. | 774 * @return {!Array.<Entry>} Array of currently selected entries. |
| 759 */ | 775 */ |
| 760 Gallery.prototype.getSelectedEntries = function() { | 776 Gallery.prototype.getSelectedEntries = function() { |
| 761 return this.selectionModel_.selectedIndexes.map(function(index) { | 777 return this.selectionModel_.selectedIndexes.map(function(index) { |
| 762 return this.dataModel_.item(index).getEntry(); | 778 return this.dataModel_.item(index).getEntry(); |
| 763 }.bind(this)); | 779 }.bind(this)); |
| 764 }; | 780 }; |
| 765 | 781 |
| 766 /** | 782 /** |
| 767 * @return {?Gallery.Item} Current single selection. | 783 * @return {?Gallery.Item} Current single selection. |
| 768 */ | 784 */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 786 /** | 802 /** |
| 787 * Data model splice event handler. | 803 * Data model splice event handler. |
| 788 * @private | 804 * @private |
| 789 */ | 805 */ |
| 790 Gallery.prototype.onSplice_ = function() { | 806 Gallery.prototype.onSplice_ = function() { |
| 791 this.selectionModel_.adjustLength(this.dataModel_.length); | 807 this.selectionModel_.adjustLength(this.dataModel_.length); |
| 792 }; | 808 }; |
| 793 | 809 |
| 794 /** | 810 /** |
| 795 * Content change event handler. | 811 * Content change event handler. |
| 796 * @param {Event} event Event. | 812 * @param {!Event} event Event. |
| 797 * @private | 813 * @private |
| 798 */ | 814 */ |
| 799 Gallery.prototype.onContentChange_ = function(event) { | 815 Gallery.prototype.onContentChange_ = function(event) { |
| 800 var index = this.dataModel_.indexOf(event.item); | 816 var index = this.dataModel_.indexOf(event.item); |
| 801 if (index !== this.selectionModel_.selectedIndex) | 817 if (index !== this.selectionModel_.selectedIndex) |
| 802 console.error('Content changed for unselected item'); | 818 console.error('Content changed for unselected item'); |
| 803 this.updateSelectionAndState_(); | 819 this.updateSelectionAndState_(); |
| 804 }; | 820 }; |
| 805 | 821 |
| 806 /** | 822 /** |
| 807 * Keydown handler. | 823 * Keydown handler. |
| 808 * | 824 * |
| 809 * @param {Event} event Event. | 825 * @param {!Event} event Event. |
| 810 * @private | 826 * @private |
| 811 */ | 827 */ |
| 812 Gallery.prototype.onKeyDown_ = function(event) { | 828 Gallery.prototype.onKeyDown_ = function(event) { |
| 813 if (this.currentMode_.onKeyDown(event)) | 829 if (this.currentMode_.onKeyDown(event)) |
| 814 return; | 830 return; |
| 815 | 831 |
| 816 switch (util.getKeyModifiers(event) + event.keyIdentifier) { | 832 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
| 817 case 'U+0008': // Backspace. | 833 case 'U+0008': // Backspace. |
| 818 // The default handler would call history.back and close the Gallery. | 834 // The default handler would call history.back and close the Gallery. |
| 819 event.preventDefault(); | 835 event.preventDefault(); |
| 820 break; | 836 break; |
| 821 | 837 |
| 822 case 'U+004D': // 'm' switches between Slide and Mosaic mode. | 838 case 'U+004D': // 'm' switches between Slide and Mosaic mode. |
| 823 this.toggleMode_(null, event); | 839 this.toggleMode_(undefined, event); |
| 824 break; | 840 break; |
| 825 | 841 |
| 826 case 'U+0056': // 'v' | 842 case 'U+0056': // 'v' |
| 827 case 'MediaPlayPause': | 843 case 'MediaPlayPause': |
| 828 this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event); | 844 this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event); |
| 829 break; | 845 break; |
| 830 | 846 |
| 831 case 'U+007F': // Delete | 847 case 'U+007F': // Delete |
| 832 case 'Shift-U+0033': // Shift+'3' (Delete key might be missing). | 848 case 'Shift-U+0033': // Shift+'3' (Delete key might be missing). |
| 833 case 'U+0044': // 'd' | 849 case 'U+0044': // 'd' |
| 834 this.delete_(); | 850 this.delete_(); |
| 835 break; | 851 break; |
| 836 | 852 |
| 837 case 'U+001B': // Escape | 853 case 'U+001B': // Escape |
| 838 close(); | 854 window.close(); |
| 839 break; | 855 break; |
| 840 } | 856 } |
| 841 }; | 857 }; |
| 842 | 858 |
| 843 // Name box and rename support. | 859 // Name box and rename support. |
| 844 | 860 |
| 845 /** | 861 /** |
| 846 * Updates the UI related to the selected item and the persistent state. | 862 * Updates the UI related to the selected item and the persistent state. |
| 847 * | 863 * |
| 848 * @private | 864 * @private |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 911 Gallery.prototype.onFilenameFocus_ = function() { | 927 Gallery.prototype.onFilenameFocus_ = function() { |
| 912 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); | 928 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); |
| 913 this.filenameEdit_.originalValue = this.filenameEdit_.value; | 929 this.filenameEdit_.originalValue = this.filenameEdit_.value; |
| 914 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); | 930 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); |
| 915 this.onUserAction_(); | 931 this.onUserAction_(); |
| 916 }; | 932 }; |
| 917 | 933 |
| 918 /** | 934 /** |
| 919 * Blur event handler on filename edit box. | 935 * Blur event handler on filename edit box. |
| 920 * | 936 * |
| 921 * @param {Event} event Blur event. | 937 * @param {!Event} event Blur event. |
| 922 * @return {Promise} Promise fulfilled on renaming completed. | |
| 923 * @private | 938 * @private |
| 924 */ | 939 */ |
| 925 Gallery.prototype.onFilenameEditBlur_ = function(event) { | 940 Gallery.prototype.onFilenameEditBlur_ = function(event) { |
| 926 var item = this.getSingleSelectedItem(); | 941 var item = this.getSingleSelectedItem(); |
| 927 if (item) { | 942 if (item) { |
| 928 var oldEntry = item.getEntry(); | 943 var oldEntry = item.getEntry(); |
| 929 | 944 |
| 930 item.rename(this.filenameEdit_.value).then(function() { | 945 item.rename(this.filenameEdit_.value).then(function() { |
| 931 var event = new Event('content'); | 946 var event = new Event('content'); |
| 932 event.item = item; | 947 event.item = item; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 943 this.prompt_.showStringAt('center', error, 5000); | 958 this.prompt_.showStringAt('center', error, 5000); |
| 944 else | 959 else |
| 945 return Promise.reject(error); | 960 return Promise.reject(error); |
| 946 }.bind(this)).catch(function(error) { | 961 }.bind(this)).catch(function(error) { |
| 947 console.error(error.stack || error); | 962 console.error(error.stack || error); |
| 948 }); | 963 }); |
| 949 } | 964 } |
| 950 | 965 |
| 951 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); | 966 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); |
| 952 this.onUserAction_(); | 967 this.onUserAction_(); |
| 953 return Promise.resolve(); | |
| 954 }; | 968 }; |
| 955 | 969 |
| 956 /** | 970 /** |
| 957 * Keydown event handler on filename edit box | 971 * Keydown event handler on filename edit box |
| 972 * @param {!Event} event A keyboard event. |
| 958 * @private | 973 * @private |
| 959 */ | 974 */ |
| 960 Gallery.prototype.onFilenameEditKeydown_ = function() { | 975 Gallery.prototype.onFilenameEditKeydown_ = function(event) { |
| 976 event = assertInstanceof(event, KeyboardEvent); |
| 961 switch (event.keyCode) { | 977 switch (event.keyCode) { |
| 962 case 27: // Escape | 978 case 27: // Escape |
| 963 this.filenameEdit_.value = this.filenameEdit_.originalValue; | 979 this.filenameEdit_.value = this.filenameEdit_.originalValue; |
| 964 this.filenameEdit_.blur(); | 980 this.filenameEdit_.blur(); |
| 965 break; | 981 break; |
| 966 | 982 |
| 967 case 13: // Enter | 983 case 13: // Enter |
| 968 this.filenameEdit_.blur(); | 984 this.filenameEdit_.blur(); |
| 969 break; | 985 break; |
| 970 } | 986 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1027 }; | 1043 }; |
| 1028 | 1044 |
| 1029 /** | 1045 /** |
| 1030 * Singleton gallery. | 1046 * Singleton gallery. |
| 1031 * @type {Gallery} | 1047 * @type {Gallery} |
| 1032 */ | 1048 */ |
| 1033 var gallery = null; | 1049 var gallery = null; |
| 1034 | 1050 |
| 1035 /** | 1051 /** |
| 1036 * Initialize the window. | 1052 * Initialize the window. |
| 1037 * @param {Object} backgroundComponents Background components. | 1053 * @param {!BackgroundComponents} backgroundComponents Background components. |
| 1038 */ | 1054 */ |
| 1039 window.initialize = function(backgroundComponents) { | 1055 window.initialize = function(backgroundComponents) { |
| 1040 window.loadTimeData.data = backgroundComponents.stringData; | 1056 window.loadTimeData.data = backgroundComponents.stringData; |
| 1041 gallery = new Gallery(backgroundComponents.volumeManager); | 1057 gallery = new Gallery(backgroundComponents.volumeManager); |
| 1042 }; | 1058 }; |
| 1043 | 1059 |
| 1044 /** | 1060 /** |
| 1045 * Loads entries. | 1061 * Loads entries. |
| 1046 * @param {!Array.<Entry>} entries Array of entries. | 1062 * @param {!Array.<Entry>} entries Array of entries. |
| 1047 * @param {!Array.<Entry>} selectedEntries Array of selected entries. | 1063 * @param {!Array.<Entry>} selectedEntries Array of selected entries. |
| 1048 */ | 1064 */ |
| 1049 window.loadEntries = function(entries, selectedEntries) { | 1065 window.loadEntries = function(entries, selectedEntries) { |
| 1050 gallery.load(entries, selectedEntries); | 1066 gallery.load(entries, selectedEntries); |
| 1051 }; | 1067 }; |
| OLD | NEW |