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} |
fukino
2014/12/12 15:15:25
cannot this be const?
yawano
2014/12/15 01:45:24
Added reply at ContentProvider.WORKER_SCRIPT of me
| |
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)); | |
fukino
2014/12/12 15:15:25
'undefined' looks redundant
yawano
2014/12/15 01:45:24
Interface of toggleMode_ is function(opt_callback,
fukino
2014/12/15 02:15:28
Sorry, I misunderstood the code. Thank you for ex
| |
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 /** | |
375 * Gallery extends cr.EventTarget. | |
376 */ | |
377 Gallery.prototype.__proto__ = cr.EventTarget.prototype; | |
378 | |
379 /** | |
380 * Tools fade-out timeout in milliseconds. | |
381 * @const | |
382 * @type {number} | |
383 */ | |
384 Gallery.FADE_TIMEOUT = 2000; | |
385 | |
386 /** | |
387 * First time tools fade-out timeout in milliseconds. | |
388 * @const | |
389 * @type {number} | |
390 */ | |
391 Gallery.FIRST_FADE_TIMEOUT = 1000; | |
392 | |
393 /** | |
394 * Time until mosaic is initialized in the background. Used to make gallery | |
395 * in the slide mode load faster. In milliseconds. | |
396 * @const | |
397 * @type {number} | |
398 */ | |
399 Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000; | |
400 | |
401 /** | |
402 * Types of metadata Gallery uses (to query the metadata cache). | |
403 * @const | |
404 * @type {string} | |
405 */ | |
406 Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|external'; | |
407 | |
408 /** | |
409 * Closes gallery when a volume containing the selected item is unmounted. | |
410 * @param {!Event} event The unmount event. | |
411 * @private | |
412 */ | |
413 Gallery.prototype.onExternallyUnmounted_ = function(event) { | |
414 if (!this.selectedEntry_) | |
415 return; | |
416 | |
417 if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) === | |
418 event.volumeInfo) { | |
419 window.close(); | |
420 } | |
416 }; | 421 }; |
417 | 422 |
418 /** | 423 /** |
424 * Unloads the Gallery. | |
425 * @param {boolean=} opt_exiting True if the app is exiting. | |
426 */ | |
427 Gallery.prototype.onUnload = function(opt_exiting) { | |
428 if (this.metadataCacheObserverId_ !== null) | |
429 this.metadataCache_.removeObserver(this.metadataCacheObserverId_); | |
430 this.volumeManager_.removeEventListener( | |
431 'externally-unmounted', this.onExternallyUnmountedBound_); | |
432 }; | |
433 | |
434 /** | |
419 * Initializes a toolbar button. | 435 * Initializes a toolbar button. |
420 * | 436 * |
421 * @param {string} className Class to add. | 437 * @param {string} className Class to add. |
422 * @param {string} title Button title. | 438 * @param {string} title Button title. |
423 * @return {!HTMLElement} Newly created button. | 439 * @return {!HTMLElement} Newly created button. |
424 * @private | 440 * @private |
425 */ | 441 */ |
426 Gallery.prototype.initToolbarButton_ = function(className, title) { | 442 Gallery.prototype.initToolbarButton_ = function(className, title) { |
427 var button = this.toolbar_.querySelector('button.' + className); | 443 var button = queryRequiredElement(this.toolbar_, 'button.' + className); |
428 button.title = str(title); | 444 button.title = str(title); |
429 return button; | 445 return button; |
430 }; | 446 }; |
431 | 447 |
432 /** | 448 /** |
433 * Loads the content. | 449 * Loads the content. |
434 * | 450 * |
435 * @param {!Array.<Entry>} entries Array of entries. | 451 * @param {!Array.<Entry>} entries Array of entries. |
436 * @param {!Array.<Entry>} selectedEntries Array of selected entries. | 452 * @param {!Array.<Entry>} selectedEntries Array of selected entries. |
437 */ | 453 */ |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
592 | 608 |
593 /** | 609 /** |
594 * Executes a function when the editor is done with the modifications. | 610 * Executes a function when the editor is done with the modifications. |
595 * @param {function()} callback Function to execute. | 611 * @param {function()} callback Function to execute. |
596 */ | 612 */ |
597 Gallery.prototype.executeWhenReady = function(callback) { | 613 Gallery.prototype.executeWhenReady = function(callback) { |
598 this.currentMode_.executeWhenReady(callback); | 614 this.currentMode_.executeWhenReady(callback); |
599 }; | 615 }; |
600 | 616 |
601 /** | 617 /** |
602 * @return {Object} File manager private API. | 618 * @return {!Object} File manager private API. |
603 */ | 619 */ |
604 Gallery.getFileManagerPrivate = function() { | 620 Gallery.getFileManagerPrivate = function() { |
605 return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate; | 621 return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate; |
606 }; | 622 }; |
607 | 623 |
608 /** | 624 /** |
609 * @return {boolean} True if some tool is currently active. | 625 * @return {boolean} True if some tool is currently active. |
610 */ | 626 */ |
611 Gallery.prototype.hasActiveTool = function() { | 627 Gallery.prototype.hasActiveTool = function() { |
612 return (this.currentMode_ && this.currentMode_.hasActiveTool()) || | 628 return (this.currentMode_ && this.currentMode_.hasActiveTool()) || |
613 this.isRenaming_(); | 629 this.isRenaming_(); |
614 }; | 630 }; |
615 | 631 |
616 /** | 632 /** |
617 * External user action event handler. | 633 * External user action event handler. |
618 * @private | 634 * @private |
619 */ | 635 */ |
620 Gallery.prototype.onUserAction_ = function() { | 636 Gallery.prototype.onUserAction_ = function() { |
621 // Show the toolbar and hide it after the default timeout. | 637 // Show the toolbar and hide it after the default timeout. |
622 this.inactivityWatcher_.kick(); | 638 this.inactivityWatcher_.kick(); |
623 }; | 639 }; |
624 | 640 |
625 /** | 641 /** |
626 * Sets the current mode, update the UI. | 642 * Sets the current mode, update the UI. |
627 * @param {Object} mode Current mode. | 643 * @param {!(SlideMode|MosaicMode)} mode Current mode. |
628 * @private | 644 * @private |
629 */ | 645 */ |
630 Gallery.prototype.setCurrentMode_ = function(mode) { | 646 Gallery.prototype.setCurrentMode_ = function(mode) { |
631 if (mode !== this.slideMode_ && mode !== this.mosaicMode_) | 647 if (mode !== this.slideMode_ && mode !== this.mosaicMode_) |
632 console.error('Invalid Gallery mode'); | 648 console.error('Invalid Gallery mode'); |
633 | 649 |
634 this.currentMode_ = mode; | 650 this.currentMode_ = mode; |
635 this.container_.setAttribute('mode', this.currentMode_.getName()); | 651 this.container_.setAttribute('mode', this.currentMode_.getName()); |
636 this.updateSelectionAndState_(); | 652 this.updateSelectionAndState_(); |
637 this.updateButtons_(); | 653 this.updateButtons_(); |
(...skipping 28 matching lines...) Expand all Loading... | |
666 var tileRect = mosaic.getTileRect(tileIndex); | 682 var tileRect = mosaic.getTileRect(tileIndex); |
667 | 683 |
668 if (this.currentMode_ === this.slideMode_) { | 684 if (this.currentMode_ === this.slideMode_) { |
669 this.setCurrentMode_(this.mosaicMode_); | 685 this.setCurrentMode_(this.mosaicMode_); |
670 mosaic.transform( | 686 mosaic.transform( |
671 tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */); | 687 tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */); |
672 this.slideMode_.leave( | 688 this.slideMode_.leave( |
673 tileRect, | 689 tileRect, |
674 function() { | 690 function() { |
675 // Animate back to normal position. | 691 // Animate back to normal position. |
676 mosaic.transform(); | 692 mosaic.transform(null, null); |
677 mosaic.show(); | 693 mosaic.show(); |
678 onModeChanged(); | 694 onModeChanged(); |
679 }.bind(this)); | 695 }.bind(this)); |
680 } else { | 696 } else { |
681 this.setCurrentMode_(this.slideMode_); | 697 this.setCurrentMode_(this.slideMode_); |
682 this.slideMode_.enter( | 698 this.slideMode_.enter( |
683 tileRect, | 699 tileRect, |
684 function() { | 700 function() { |
685 // Animate to zoomed position. | 701 // Animate to zoomed position. |
686 mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect()); | 702 mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 this.selectionModel_.leadIndex = -1; | 752 this.selectionModel_.leadIndex = -1; |
737 // Remove items from the data model, starting from the highest index. | 753 // Remove items from the data model, starting from the highest index. |
738 while (indexesToRemove.length) | 754 while (indexesToRemove.length) |
739 this.dataModel_.splice(indexesToRemove.pop(), 1); | 755 this.dataModel_.splice(indexesToRemove.pop(), 1); |
740 // Delete actual files. | 756 // Delete actual files. |
741 deleteNext(); | 757 deleteNext(); |
742 }.bind(this), | 758 }.bind(this), |
743 function() { | 759 function() { |
744 // Restore the listener after a timeout so that ESC is processed. | 760 // Restore the listener after a timeout so that ESC is processed. |
745 setTimeout(restoreListener, 0); | 761 setTimeout(restoreListener, 0); |
746 }); | 762 }, |
763 null); | |
747 }; | 764 }; |
748 | 765 |
749 /** | 766 /** |
750 * @return {Array.<Gallery.Item>} Current selection. | 767 * @return {!Array.<Gallery.Item>} Current selection. |
751 */ | 768 */ |
752 Gallery.prototype.getSelectedItems = function() { | 769 Gallery.prototype.getSelectedItems = function() { |
753 return this.selectionModel_.selectedIndexes.map( | 770 return this.selectionModel_.selectedIndexes.map( |
754 this.dataModel_.item.bind(this.dataModel_)); | 771 this.dataModel_.item.bind(this.dataModel_)); |
755 }; | 772 }; |
756 | 773 |
757 /** | 774 /** |
758 * @return {Array.<Entry>} Array of currently selected entries. | 775 * @return {!Array.<Entry>} Array of currently selected entries. |
759 */ | 776 */ |
760 Gallery.prototype.getSelectedEntries = function() { | 777 Gallery.prototype.getSelectedEntries = function() { |
761 return this.selectionModel_.selectedIndexes.map(function(index) { | 778 return this.selectionModel_.selectedIndexes.map(function(index) { |
762 return this.dataModel_.item(index).getEntry(); | 779 return this.dataModel_.item(index).getEntry(); |
763 }.bind(this)); | 780 }.bind(this)); |
764 }; | 781 }; |
765 | 782 |
766 /** | 783 /** |
767 * @return {?Gallery.Item} Current single selection. | 784 * @return {?Gallery.Item} Current single selection. |
768 */ | 785 */ |
(...skipping 17 matching lines...) Expand all Loading... | |
786 /** | 803 /** |
787 * Data model splice event handler. | 804 * Data model splice event handler. |
788 * @private | 805 * @private |
789 */ | 806 */ |
790 Gallery.prototype.onSplice_ = function() { | 807 Gallery.prototype.onSplice_ = function() { |
791 this.selectionModel_.adjustLength(this.dataModel_.length); | 808 this.selectionModel_.adjustLength(this.dataModel_.length); |
792 }; | 809 }; |
793 | 810 |
794 /** | 811 /** |
795 * Content change event handler. | 812 * Content change event handler. |
796 * @param {Event} event Event. | 813 * @param {!Event} event Event. |
797 * @private | 814 * @private |
798 */ | 815 */ |
799 Gallery.prototype.onContentChange_ = function(event) { | 816 Gallery.prototype.onContentChange_ = function(event) { |
800 var index = this.dataModel_.indexOf(event.item); | 817 var index = this.dataModel_.indexOf(event.item); |
801 if (index !== this.selectionModel_.selectedIndex) | 818 if (index !== this.selectionModel_.selectedIndex) |
802 console.error('Content changed for unselected item'); | 819 console.error('Content changed for unselected item'); |
803 this.updateSelectionAndState_(); | 820 this.updateSelectionAndState_(); |
804 }; | 821 }; |
805 | 822 |
806 /** | 823 /** |
807 * Keydown handler. | 824 * Keydown handler. |
808 * | 825 * |
809 * @param {Event} event Event. | 826 * @param {!Event} event Event. |
810 * @private | 827 * @private |
811 */ | 828 */ |
812 Gallery.prototype.onKeyDown_ = function(event) { | 829 Gallery.prototype.onKeyDown_ = function(event) { |
813 if (this.currentMode_.onKeyDown(event)) | 830 if (this.currentMode_.onKeyDown(event)) |
814 return; | 831 return; |
815 | 832 |
816 switch (util.getKeyModifiers(event) + event.keyIdentifier) { | 833 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
817 case 'U+0008': // Backspace. | 834 case 'U+0008': // Backspace. |
818 // The default handler would call history.back and close the Gallery. | 835 // The default handler would call history.back and close the Gallery. |
819 event.preventDefault(); | 836 event.preventDefault(); |
820 break; | 837 break; |
821 | 838 |
822 case 'U+004D': // 'm' switches between Slide and Mosaic mode. | 839 case 'U+004D': // 'm' switches between Slide and Mosaic mode. |
823 this.toggleMode_(null, event); | 840 this.toggleMode_(undefined, event); |
824 break; | 841 break; |
825 | 842 |
826 case 'U+0056': // 'v' | 843 case 'U+0056': // 'v' |
827 case 'MediaPlayPause': | 844 case 'MediaPlayPause': |
828 this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event); | 845 this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event); |
829 break; | 846 break; |
830 | 847 |
831 case 'U+007F': // Delete | 848 case 'U+007F': // Delete |
832 case 'Shift-U+0033': // Shift+'3' (Delete key might be missing). | 849 case 'Shift-U+0033': // Shift+'3' (Delete key might be missing). |
833 case 'U+0044': // 'd' | 850 case 'U+0044': // 'd' |
834 this.delete_(); | 851 this.delete_(); |
835 break; | 852 break; |
836 | 853 |
837 case 'U+001B': // Escape | 854 case 'U+001B': // Escape |
838 close(); | 855 window.close(); |
839 break; | 856 break; |
840 } | 857 } |
841 }; | 858 }; |
842 | 859 |
843 // Name box and rename support. | 860 // Name box and rename support. |
844 | 861 |
845 /** | 862 /** |
846 * Updates the UI related to the selected item and the persistent state. | 863 * Updates the UI related to the selected item and the persistent state. |
847 * | 864 * |
848 * @private | 865 * @private |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
911 Gallery.prototype.onFilenameFocus_ = function() { | 928 Gallery.prototype.onFilenameFocus_ = function() { |
912 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); | 929 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); |
913 this.filenameEdit_.originalValue = this.filenameEdit_.value; | 930 this.filenameEdit_.originalValue = this.filenameEdit_.value; |
914 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); | 931 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); |
915 this.onUserAction_(); | 932 this.onUserAction_(); |
916 }; | 933 }; |
917 | 934 |
918 /** | 935 /** |
919 * Blur event handler on filename edit box. | 936 * Blur event handler on filename edit box. |
920 * | 937 * |
921 * @param {Event} event Blur event. | 938 * @param {!Event} event Blur event. |
922 * @return {Promise} Promise fulfilled on renaming completed. | |
923 * @private | 939 * @private |
924 */ | 940 */ |
925 Gallery.prototype.onFilenameEditBlur_ = function(event) { | 941 Gallery.prototype.onFilenameEditBlur_ = function(event) { |
926 var item = this.getSingleSelectedItem(); | 942 var item = this.getSingleSelectedItem(); |
927 if (item) { | 943 if (item) { |
928 var oldEntry = item.getEntry(); | 944 var oldEntry = item.getEntry(); |
929 | 945 |
930 item.rename(this.filenameEdit_.value).then(function() { | 946 item.rename(this.filenameEdit_.value).then(function() { |
931 var event = new Event('content'); | 947 var event = new Event('content'); |
932 event.item = item; | 948 event.item = item; |
(...skipping 10 matching lines...) Expand all Loading... | |
943 this.prompt_.showStringAt('center', error, 5000); | 959 this.prompt_.showStringAt('center', error, 5000); |
944 else | 960 else |
945 return Promise.reject(error); | 961 return Promise.reject(error); |
946 }.bind(this)).catch(function(error) { | 962 }.bind(this)).catch(function(error) { |
947 console.error(error.stack || error); | 963 console.error(error.stack || error); |
948 }); | 964 }); |
949 } | 965 } |
950 | 966 |
951 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); | 967 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); |
952 this.onUserAction_(); | 968 this.onUserAction_(); |
953 return Promise.resolve(); | |
954 }; | 969 }; |
955 | 970 |
956 /** | 971 /** |
957 * Keydown event handler on filename edit box | 972 * Keydown event handler on filename edit box |
973 * @param {!Event} event A keyboard event. | |
958 * @private | 974 * @private |
959 */ | 975 */ |
960 Gallery.prototype.onFilenameEditKeydown_ = function() { | 976 Gallery.prototype.onFilenameEditKeydown_ = function(event) { |
977 event = assertInstanceof(event, KeyboardEvent); | |
961 switch (event.keyCode) { | 978 switch (event.keyCode) { |
962 case 27: // Escape | 979 case 27: // Escape |
963 this.filenameEdit_.value = this.filenameEdit_.originalValue; | 980 this.filenameEdit_.value = this.filenameEdit_.originalValue; |
964 this.filenameEdit_.blur(); | 981 this.filenameEdit_.blur(); |
965 break; | 982 break; |
966 | 983 |
967 case 13: // Enter | 984 case 13: // Enter |
968 this.filenameEdit_.blur(); | 985 this.filenameEdit_.blur(); |
969 break; | 986 break; |
970 } | 987 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1027 }; | 1044 }; |
1028 | 1045 |
1029 /** | 1046 /** |
1030 * Singleton gallery. | 1047 * Singleton gallery. |
1031 * @type {Gallery} | 1048 * @type {Gallery} |
1032 */ | 1049 */ |
1033 var gallery = null; | 1050 var gallery = null; |
1034 | 1051 |
1035 /** | 1052 /** |
1036 * Initialize the window. | 1053 * Initialize the window. |
1037 * @param {Object} backgroundComponents Background components. | 1054 * @param {!BackgroundComponents} backgroundComponents Background components. |
1038 */ | 1055 */ |
1039 window.initialize = function(backgroundComponents) { | 1056 window.initialize = function(backgroundComponents) { |
1040 window.loadTimeData.data = backgroundComponents.stringData; | 1057 window.loadTimeData.data = backgroundComponents.stringData; |
1041 gallery = new Gallery(backgroundComponents.volumeManager); | 1058 gallery = new Gallery(backgroundComponents.volumeManager); |
1042 }; | 1059 }; |
1043 | 1060 |
1044 /** | 1061 /** |
1045 * Loads entries. | 1062 * Loads entries. |
1046 * @param {!Array.<Entry>} entries Array of entries. | 1063 * @param {!Array.<Entry>} entries Array of entries. |
1047 * @param {!Array.<Entry>} selectedEntries Array of selected entries. | 1064 * @param {!Array.<Entry>} selectedEntries Array of selected entries. |
1048 */ | 1065 */ |
1049 window.loadEntries = function(entries, selectedEntries) { | 1066 window.loadEntries = function(entries, selectedEntries) { |
1050 gallery.load(entries, selectedEntries); | 1067 gallery.load(entries, selectedEntries); |
1051 }; | 1068 }; |
OLD | NEW |