| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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 document.addEventListener('DOMContentLoaded', function() { | 5 document.addEventListener('DOMContentLoaded', function() { |
| 6 if (document.location.hash) // File path passed after the #. | 6 if (document.location.hash) // File path passed after the #. |
| 7 Gallery.openStandalone(decodeURI(document.location.hash.substr(1))); | 7 Gallery.openStandalone(decodeURI(document.location.hash.substr(1))); |
| 8 }); | 8 }); |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 * {function(string)} displayStringFunction | 21 * {function(string)} displayStringFunction |
| 22 * @class | 22 * @class |
| 23 * @constructor | 23 * @constructor |
| 24 */ | 24 */ |
| 25 function Gallery(context) { | 25 function Gallery(context) { |
| 26 this.container_ = document.querySelector('.gallery'); | 26 this.container_ = document.querySelector('.gallery'); |
| 27 this.document_ = document; | 27 this.document_ = document; |
| 28 this.context_ = context; | 28 this.context_ = context; |
| 29 this.metadataCache_ = context.metadataCache; | 29 this.metadataCache_ = context.metadataCache; |
| 30 | 30 |
| 31 this.dataModel_ = new cr.ui.ArrayDataModel([]); |
| 32 this.selectionModel_ = new cr.ui.ListSelectionModel(); |
| 33 |
| 31 var strf = context.displayStringFunction; | 34 var strf = context.displayStringFunction; |
| 32 this.displayStringFunction_ = function(id, formatArgs) { | 35 this.displayStringFunction_ = function(id, formatArgs) { |
| 33 var args = Array.prototype.slice.call(arguments); | 36 var args = Array.prototype.slice.call(arguments); |
| 34 args[0] = 'GALLERY_' + id.toUpperCase(); | 37 args[0] = 'GALLERY_' + id.toUpperCase(); |
| 35 return strf.apply(null, args); | 38 return strf.apply(null, args); |
| 36 }; | 39 }; |
| 37 | 40 |
| 38 this.initListeners_(); | 41 this.initListeners_(); |
| 39 this.initDom_(); | 42 this.initDom_(); |
| 40 } | 43 } |
| 41 | 44 |
| 42 /** | 45 /** |
| 43 * Create and initialize a Gallery object based on a context. | 46 * Create and initialize a Gallery object based on a context. |
| 44 * | 47 * |
| 45 * @param {Object} context Gallery context. | 48 * @param {Object} context Gallery context. |
| 46 * @param {Array.<string>} urls Array of image urls. | 49 * @param {Array.<string>} urls Array of image urls. |
| 47 * @param {string} selectedUrl Selected url. | 50 * @param {string} selectedUrl Selected url. |
| 51 * @param {boolean} opt_grid True if open in the grid view. |
| 48 */ | 52 */ |
| 49 Gallery.open = function(context, urls, selectedUrl) { | 53 Gallery.open = function(context, urls, selectedUrl, opt_grid) { |
| 50 Gallery.instance = new Gallery(context); | 54 Gallery.instance = new Gallery(context); |
| 51 Gallery.instance.load(urls, selectedUrl); | 55 Gallery.instance.load(urls, selectedUrl, opt_grid); |
| 52 }; | 56 }; |
| 53 | 57 |
| 54 /** | 58 /** |
| 55 * Create a Gallery object in a tab. | 59 * Create a Gallery object in a tab. |
| 56 * @param {string} path File system path to a selected file. | 60 * @param {string} path File system path to a selected file. |
| 57 */ | 61 */ |
| 58 Gallery.openStandalone = function(path) { | 62 Gallery.openStandalone = function(path) { |
| 59 ImageUtil.metrics = metrics; | 63 ImageUtil.metrics = metrics; |
| 60 | 64 |
| 61 var currentDir; | 65 var currentDir; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 83 } else if (FileType.isImageOrVideo(entry)) { | 87 } else if (FileType.isImageOrVideo(entry)) { |
| 84 var url = entry.toURL(); | 88 var url = entry.toURL(); |
| 85 urls.push(url); | 89 urls.push(url); |
| 86 if (entry.fullPath == path) | 90 if (entry.fullPath == path) |
| 87 selectedUrl = url; | 91 selectedUrl = url; |
| 88 } | 92 } |
| 89 }); | 93 }); |
| 90 } | 94 } |
| 91 | 95 |
| 92 function onNameChange(name) { | 96 function onNameChange(name) { |
| 93 window.top.document.title = name; | 97 window.top.document.title = name || currentDir.name; |
| 94 | 98 |
| 95 var newPath = currentDir.fullPath + '/' + name; | 99 var newPath = currentDir.fullPath + '/' + name; |
| 96 var location = document.location.origin + document.location.pathname + | 100 var location = document.location.origin + document.location.pathname + |
| 97 '#' + encodeURI(newPath); | 101 '#' + encodeURI(newPath); |
| 98 history.replaceState(undefined, newPath, location); | 102 history.replaceState(undefined, newPath, location); |
| 99 } | 103 } |
| 100 | 104 |
| 101 function onClose() { | 105 function onClose() { |
| 102 document.location = 'main.html?' + | 106 document.location = 'main.html?' + |
| 103 JSON.stringify({defaultPath: document.location.hash.substr(1)}); | 107 JSON.stringify({defaultPath: document.location.hash.substr(1)}); |
| 104 } | 108 } |
| 105 | 109 |
| 106 function open() { | 110 function open() { |
| 111 urls.sort(); |
| 107 Gallery.getFileBrowserPrivate().getStrings(function(strings) { | 112 Gallery.getFileBrowserPrivate().getStrings(function(strings) { |
| 108 loadTimeData.data = strings; | 113 loadTimeData.data = strings; |
| 109 var context = { | 114 var context = { |
| 110 readonlyDirName: null, | 115 readonlyDirName: null, |
| 111 saveDirEntry: currentDir, | 116 saveDirEntry: currentDir, |
| 112 metadataCache: MetadataCache.createFull(), | 117 metadataCache: MetadataCache.createFull(), |
| 113 onNameChange: onNameChange, | 118 onNameChange: onNameChange, |
| 114 onClose: onClose, | 119 onClose: onClose, |
| 115 displayStringFunction: strf | 120 displayStringFunction: strf |
| 116 }; | 121 }; |
| 117 Gallery.open(context, urls, selectedUrl || urls[0]); | 122 Gallery.open(context, urls, selectedUrl, !selectedUrl); |
| 118 }); | 123 }); |
| 119 } | 124 } |
| 120 }; | 125 }; |
| 121 | 126 |
| 122 /** | 127 /** |
| 123 * Tools fade-out timeout im milliseconds. | 128 * Tools fade-out timeout im milliseconds. |
| 124 * @type {Number} | 129 * @type {Number} |
| 125 */ | 130 */ |
| 126 Gallery.FADE_TIMEOUT = 3000; | 131 Gallery.FADE_TIMEOUT = 3000; |
| 127 | 132 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 this.onFilenameEditBlur_.bind(this)); | 192 this.onFilenameEditBlur_.bind(this)); |
| 188 this.filenameEdit_.addEventListener('keydown', | 193 this.filenameEdit_.addEventListener('keydown', |
| 189 this.onFilenameEditKeydown_.bind(this)); | 194 this.onFilenameEditKeydown_.bind(this)); |
| 190 nameBox.appendChild(this.filenameEdit_); | 195 nameBox.appendChild(this.filenameEdit_); |
| 191 | 196 |
| 192 util.createChild(this.toolbar_, 'button-spacer'); | 197 util.createChild(this.toolbar_, 'button-spacer'); |
| 193 | 198 |
| 194 this.prompt_ = new ImageEditor.Prompt( | 199 this.prompt_ = new ImageEditor.Prompt( |
| 195 this.container_, this.displayStringFunction_); | 200 this.container_, this.displayStringFunction_); |
| 196 | 201 |
| 197 this.slideMode_ = new SlideMode(this.container_, this.toolbar_, this.prompt_, | 202 this.modeButton_ = util.createChild(this.toolbar_, 'button mode'); |
| 203 this.modeButton_.addEventListener('click', this.toggleMode_.bind(this, null)); |
| 204 |
| 205 this.gridMode_ = new GridMode(this.container_, content, |
| 206 this.dataModel_, this.selectionModel_, this.metadataCache_, |
| 207 this.toggleMode_.bind(this, null)); |
| 208 |
| 209 this.slideMode_ = new SlideMode(this.container_, content, |
| 210 this.toolbar_, this.prompt_, |
| 211 this.dataModel_, this.selectionModel_, |
| 198 this.context_, this.displayStringFunction_); | 212 this.context_, this.displayStringFunction_); |
| 199 this.slideMode_.addEventListener('edit', this.onEdit_.bind(this)); | |
| 200 this.slideMode_.addEventListener('selection', this.onSelection_.bind(this)); | |
| 201 | 213 |
| 202 this.shareMode_ = new ShareMode( | 214 var deleteButton = this.document_.createElement('div'); |
| 203 this.slideMode_.editor_, this.container_, this.toolbar_, | 215 deleteButton.className = 'button delete'; |
| 204 this.onShare_.bind(this), this.executeWhenReady.bind(this), | 216 deleteButton.title = this.displayStringFunction_('delete'); |
| 205 this.displayStringFunction_); | 217 deleteButton.addEventListener('click', this.onDelete_.bind(this)); |
| 218 this.toolbar_.insertBefore( |
| 219 deleteButton, this.toolbar_.querySelector('.edit')); |
| 220 |
| 221 this.shareButton_ = util.createChild(this.toolbar_, 'button share'); |
| 222 this.shareButton_.title = this.displayStringFunction_('share'); |
| 223 this.shareButton_.addEventListener('click', this.toggleShare_.bind(this)); |
| 224 |
| 225 this.shareMenu_ = util.createChild(this.container_, 'share-menu'); |
| 226 this.shareMenu_.hidden = true; |
| 227 util.createChild(this.shareMenu_, 'bubble-point'); |
| 206 | 228 |
| 207 Gallery.getFileBrowserPrivate().isFullscreen(function(fullscreen) { | 229 Gallery.getFileBrowserPrivate().isFullscreen(function(fullscreen) { |
| 208 this.originalFullscreen_ = fullscreen; | 230 this.originalFullscreen_ = fullscreen; |
| 209 }.bind(this)); | 231 }.bind(this)); |
| 232 |
| 233 this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this)); |
| 234 this.slideMode_.addEventListener('content', this.onContentChange_.bind(this)); |
| 235 this.slideMode_.addEventListener('namechange', this.onSelection_.bind(this)); |
| 236 this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); |
| 210 }; | 237 }; |
| 211 | 238 |
| 212 /** | 239 /** |
| 213 * Load the content. | 240 * Load the content. |
| 214 * | 241 * |
| 215 * @param {Array.<string>} urls Array of urls. | 242 * @param {Array.<string>} urls Array of urls. |
| 216 * @param {string} selectedUrl Selected url. | 243 * @param {string} selectedUrl Selected url. |
| 244 * @param {boolean} opt_grid True if open in the grid view. |
| 217 */ | 245 */ |
| 218 Gallery.prototype.load = function(urls, selectedUrl) { | 246 Gallery.prototype.load = function(urls, selectedUrl, opt_grid) { |
| 219 this.items_ = []; | 247 var items = []; |
| 220 for (var index = 0; index < urls.length; ++index) { | 248 for (var index = 0; index < urls.length; ++index) { |
| 221 this.items_.push(new Gallery.Item(urls[index])); | 249 items.push(new Gallery.Item(urls[index])); |
| 222 } | 250 } |
| 251 this.dataModel_.push.apply(this.dataModel_, items); |
| 223 | 252 |
| 224 var selectedIndex = urls.indexOf(selectedUrl); | 253 var selectedIndex = urls.indexOf(selectedUrl); |
| 225 this.slideMode_.load(this.items_, selectedIndex, function() { | 254 if (selectedIndex >= 0) |
| 226 // Flash the toolbar briefly to show it is there. | 255 this.selectionModel_.setIndexSelected(selectedIndex, true); |
| 227 this.inactivityWatcher_.startActivity(); | 256 else |
| 228 this.inactivityWatcher_.stopActivity(Gallery.FIRST_FADE_TIMEOUT); | 257 this.onSelection_(); |
| 229 }.bind(this)); | 258 |
| 259 this.currentMode_ = opt_grid ? this.gridMode_ : this.slideMode_; |
| 260 this.currentMode_.enter(function() { |
| 261 // Flash the toolbar briefly to show it is there. |
| 262 this.inactivityWatcher_.startActivity(); |
| 263 this.inactivityWatcher_.stopActivity(Gallery.FIRST_FADE_TIMEOUT); |
| 264 }.bind(this)); |
| 230 }; | 265 }; |
| 231 | 266 |
| 232 /** | 267 /** |
| 233 * Close the Gallery. | 268 * Close the Gallery. |
| 234 * @private | 269 * @private |
| 235 */ | 270 */ |
| 236 Gallery.prototype.close_ = function() { | 271 Gallery.prototype.close_ = function() { |
| 237 Gallery.getFileBrowserPrivate().isFullscreen(function(fullscreen) { | 272 Gallery.getFileBrowserPrivate().isFullscreen(function(fullscreen) { |
| 238 if (this.originalFullscreen_ != fullscreen) { | 273 if (this.originalFullscreen_ != fullscreen) { |
| 239 Gallery.toggleFullscreen(); | 274 Gallery.toggleFullscreen(); |
| 240 } | 275 } |
| 241 this.context_.onClose(); | 276 this.context_.onClose(); |
| 242 }.bind(this)); | 277 }.bind(this)); |
| 243 }; | 278 }; |
| 244 | 279 |
| 245 /** | 280 /** |
| 246 * Handle user's 'Close' action (Escape or a click on the X icon). | 281 * Handle user's 'Close' action (Escape or a click on the X icon). |
| 247 * @private | 282 * @private |
| 248 */ | 283 */ |
| 249 Gallery.prototype.onClose_ = function() { | 284 Gallery.prototype.onClose_ = function() { |
| 250 this.executeWhenReady(this.close_.bind(this)); | 285 this.executeWhenReady(this.close_.bind(this)); |
| 251 }; | 286 }; |
| 252 | 287 |
| 253 /** | 288 /** |
| 254 * Execute a function when the editor is done with the modifications. | 289 * Execute a function when the editor is done with the modifications. |
| 255 * @param {function} callback Function to execute. | 290 * @param {function} callback Function to execute. |
| 256 */ | 291 */ |
| 257 Gallery.prototype.executeWhenReady = function(callback) { | 292 Gallery.prototype.executeWhenReady = function(callback) { |
| 258 //TODO(kaznacheev): Execute directly when in grid mode. | 293 if (this.currentMode_ == this.slideMode_) |
| 259 this.slideMode_.editor_.executeWhenReady(callback); | 294 this.slideMode_.editor_.executeWhenReady(callback); |
| 295 else |
| 296 callback(); |
| 260 }; | 297 }; |
| 261 | 298 |
| 262 /** | 299 /** |
| 263 * @return {Object} File browser private API. | 300 * @return {Object} File browser private API. |
| 264 */ | 301 */ |
| 265 Gallery.getFileBrowserPrivate = function() { | 302 Gallery.getFileBrowserPrivate = function() { |
| 266 return chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate; | 303 return chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate; |
| 267 }; | 304 }; |
| 268 | 305 |
| 269 /** | 306 /** |
| 270 * Switches gallery to fullscreen mode and back. | 307 * Switches gallery to fullscreen mode and back. |
| 271 */ | 308 */ |
| 272 Gallery.toggleFullscreen = function() { | 309 Gallery.toggleFullscreen = function() { |
| 273 Gallery.getFileBrowserPrivate().toggleFullscreen(); | 310 Gallery.getFileBrowserPrivate().toggleFullscreen(); |
| 274 }; | 311 }; |
| 275 | 312 |
| 276 /** | 313 /** |
| 277 * @return {boolean} True if some tool is currently active. | 314 * @return {boolean} True if some tool is currently active. |
| 278 */ | 315 */ |
| 279 Gallery.prototype.hasActiveTool = function() { | 316 Gallery.prototype.hasActiveTool = function() { |
| 280 return this.slideMode_.isEditing() || this.isSharing_() || this.isRenaming_(); | 317 return this.currentMode_.hasActiveTool() || |
| 318 this.isSharing_() || this.isRenaming_(); |
| 281 }; | 319 }; |
| 282 | 320 |
| 283 /** | 321 /** |
| 284 * Check if the tools are active and notify the inactivity watcher. | 322 * Check if the tools are active and notify the inactivity watcher. |
| 285 * @private | 323 * @private |
| 286 */ | 324 */ |
| 287 Gallery.prototype.checkActivity_ = function() { | 325 Gallery.prototype.checkActivity_ = function() { |
| 288 if (this.hasActiveTool()) | 326 if (this.hasActiveTool()) |
| 289 this.inactivityWatcher_.startActivity(); | 327 this.inactivityWatcher_.startActivity(); |
| 290 else | 328 else |
| 291 this.inactivityWatcher_.stopActivity(); | 329 this.inactivityWatcher_.stopActivity(); |
| 292 }; | 330 }; |
| 293 | 331 |
| 294 /** | 332 /** |
| 295 * Edit toggle event handler. | 333 * External user action event handler. |
| 296 * @private | 334 * @private |
| 297 */ | 335 */ |
| 298 Gallery.prototype.onEdit_ = function() { | 336 Gallery.prototype.onUserAction_ = function() { |
| 299 // The user has just clicked on the Edit button. Dismiss the Share menu. | 337 this.closeShareMenu_(); |
| 300 if (this.isSharing_()) | |
| 301 this.onShare_(); | |
| 302 this.checkActivity_(); | 338 this.checkActivity_(); |
| 303 }; | 339 }; |
| 304 | 340 |
| 305 /** | 341 /** |
| 342 * Mode toggle event handler. |
| 343 * @param {function} opt_callback Callback. |
| 344 * @private |
| 345 */ |
| 346 Gallery.prototype.toggleMode_ = function(opt_callback) { |
| 347 this.currentMode_.leave(function() { |
| 348 if (this.currentMode_ == this.gridMode_) { |
| 349 this.currentMode_ = this.slideMode_; |
| 350 this.modeButton_.title = this.displayStringFunction_('mosaic'); |
| 351 } else { |
| 352 this.currentMode_ = this.gridMode_; |
| 353 this.modeButton_.title = this.displayStringFunction_('slide'); |
| 354 } |
| 355 this.currentMode_.enter(opt_callback); |
| 356 this.updateFilename_(); |
| 357 }.bind(this)); |
| 358 }; |
| 359 |
| 360 /** |
| 361 * Delete event handler. |
| 362 * @private |
| 363 */ |
| 364 Gallery.prototype.onDelete_ = function() { |
| 365 var indexes = this.selectionModel_.selectedIndexes; |
| 366 for (var i = 0; i != indexes.length; i++) |
| 367 this.dataModel_.splice(indexes[i], 1); |
| 368 |
| 369 // TODO: delete actual files. |
| 370 }; |
| 371 |
| 372 /** |
| 306 * @return {Array.<Gallery.Item>} Current selection. | 373 * @return {Array.<Gallery.Item>} Current selection. |
| 307 */ | 374 */ |
| 308 Gallery.prototype.getSelectedItems = function() { | 375 Gallery.prototype.getSelectedItems = function() { |
| 309 // TODO(kaznacheev) support multiple selection grid/mosaic mode. | 376 return this.selectionModel_.selectedIndexes.map( |
| 310 return [this.slideMode_.getSelectedItem()]; | 377 this.dataModel_.item.bind(this.dataModel_)); |
| 311 }; | 378 }; |
| 312 | 379 |
| 313 /** | 380 /** |
| 314 * @return {Gallery.Item} Current single selection. | 381 * @return {Gallery.Item} Current single selection. |
| 315 */ | 382 */ |
| 316 Gallery.prototype.getSingleSelectedItem = function() { | 383 Gallery.prototype.getSingleSelectedItem = function() { |
| 317 var items = this.getSelectedItems(); | 384 var items = this.getSelectedItems(); |
| 318 if (items.length > 1) | 385 if (items.length > 1) |
| 319 throw new Error('Unexpected multiple selection'); | 386 throw new Error('Unexpected multiple selection'); |
| 320 return items[0]; | 387 return items[0]; |
| 321 }; | 388 }; |
| 322 | 389 |
| 323 /** | 390 /** |
| 324 * Selection change event handler. | 391 * Selection change event handler. |
| 325 * @private | 392 * @private |
| 326 */ | 393 */ |
| 327 Gallery.prototype.onSelection_ = function() { | 394 Gallery.prototype.onSelection_ = function() { |
| 328 this.updateFilename_(); | 395 this.updateFilename_(); |
| 329 this.shareMode_.updateMenu( | 396 this.updateShareMenu_(); |
| 330 this.getSelectedItems().map(function(item) { return item.getUrl() })); | |
| 331 }; | 397 }; |
| 332 | 398 |
| 333 /** | 399 /** |
| 400 * Content change event handler. |
| 401 * @private |
| 402 */ |
| 403 Gallery.prototype.onContentChange_ = function() { |
| 404 this.updateFilename_(); |
| 405 this.gridMode_.updateThumbnail(this.getSingleSelectedItem()); |
| 406 }; |
| 407 |
| 408 /** |
| 334 * Keydown handler. | 409 * Keydown handler. |
| 335 * @param {Event} event Event. | 410 * @param {Event} event Event. |
| 336 * @private | 411 * @private |
| 337 */ | 412 */ |
| 338 Gallery.prototype.onKeyDown_ = function(event) { | 413 Gallery.prototype.onKeyDown_ = function(event) { |
| 339 if (this.slideMode_.onKeyDown(event)) | 414 var wasSharing = this.isSharing_(); |
| 415 this.closeShareMenu_(); |
| 416 |
| 417 if (this.currentMode_.onKeyDown(event)) |
| 340 return; | 418 return; |
| 341 | 419 |
| 342 switch (util.getKeyModifiers(event) + event.keyIdentifier) { | 420 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
| 343 case 'U+0008': // Backspace. | 421 case 'U+0008': // Backspace. |
| 344 // The default handler would call history.back and close the Gallery. | 422 // The default handler would call history.back and close the Gallery. |
| 345 event.preventDefault(); | 423 event.preventDefault(); |
| 346 break; | 424 break; |
| 347 | 425 |
| 348 case 'U+001B': // Escape | 426 case 'U+001B': // Escape |
| 349 if (this.isSharing_()) | 427 // Swallow Esc if it closed the Share menu, otherwise close the Gallery. |
| 350 this.onShare_(); | 428 if (!wasSharing) |
| 351 else | |
| 352 this.onClose_(); | 429 this.onClose_(); |
| 353 break; | 430 break; |
| 354 } | 431 } |
| 355 }; | 432 }; |
| 356 | 433 |
| 357 // Name box and rename support. | 434 // Name box and rename support. |
| 358 | 435 |
| 359 /** | 436 /** |
| 360 * Update the displayed current item file name. | 437 * Update the displayed current item file name. |
| 361 * | 438 * |
| 362 * @private | 439 * @private |
| 363 */ | 440 */ |
| 364 Gallery.prototype.updateFilename_ = function() { | 441 Gallery.prototype.updateFilename_ = function() { |
| 365 var fullName = this.getSingleSelectedItem().getFileName(); | 442 var displayName = ''; |
| 443 var fullName = ''; |
| 366 | 444 |
| 367 this.context_.onNameChange(fullName); | 445 var selectedItems = this.getSelectedItems(); |
| 446 if (selectedItems.length == 1) { |
| 447 fullName = selectedItems[0].getFileName(); |
| 448 displayName = ImageUtil.getFileNameFromFullName(fullName); |
| 449 } else if (selectedItems.length > 1) { |
| 450 displayName = |
| 451 this.displayStringFunction_('ITEMS_SELECTED', selectedItems.length); |
| 452 } |
| 368 | 453 |
| 369 var displayName = ImageUtil.getFileNameFromFullName(fullName); | 454 this.context_.onNameChange( |
| 455 this.currentMode_ == this.slideMode_ ? fullName : ''); |
| 456 |
| 370 this.filenameEdit_.value = displayName; | 457 this.filenameEdit_.value = displayName; |
| 371 this.filenameText_.textContent = displayName; | 458 this.filenameText_.textContent = displayName; |
| 372 }; | 459 }; |
| 373 | 460 |
| 374 /** | 461 /** |
| 375 * Click event handler on filename edit box | 462 * Click event handler on filename edit box |
| 376 * @private | 463 * @private |
| 377 */ | 464 */ |
| 378 Gallery.prototype.onFilenameClick_ = function() { | 465 Gallery.prototype.onFilenameClick_ = function() { |
| 379 // We can't rename files in readonly directory. | 466 // We can't rename files in readonly directory. |
| 380 if (this.context_.readonlyDirName) | 467 if (this.context_.readonlyDirName) |
| 381 return; | 468 return; |
| 382 | 469 |
| 470 // We can only rename a single file. |
| 471 if (this.getSelectedItems().length != 1) |
| 472 return; |
| 473 |
| 383 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); | 474 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); |
| 384 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); | 475 setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); |
| 385 this.inactivityWatcher_.startActivity(); | 476 this.inactivityWatcher_.startActivity(); |
| 386 }; | 477 }; |
| 387 | 478 |
| 388 /** | 479 /** |
| 389 * Blur event handler on filename edit box | 480 * Blur event handler on filename edit box |
| 390 * @private | 481 * @private |
| 391 */ | 482 */ |
| 392 Gallery.prototype.onFilenameEditBlur_ = function() { | 483 Gallery.prototype.onFilenameEditBlur_ = function() { |
| 393 if (this.filenameEdit_.value && this.filenameEdit_.value[0] == '.') { | 484 if (this.filenameEdit_.value && this.filenameEdit_.value[0] == '.') { |
| 394 this.prompt_.show('file_hidden_name', 5000); | 485 this.prompt_.show('file_hidden_name', 5000); |
| 395 this.filenameEdit_.focus(); | 486 this.filenameEdit_.focus(); |
| 396 return; | 487 return; |
| 397 } | 488 } |
| 398 | 489 |
| 399 var item = this.getSingleSelectedItem(); | 490 var item = this.getSingleSelectedItem(); |
| 400 var oldUrl = item.getUrl(); | 491 var oldUrl = item.getUrl(); |
| 401 | 492 |
| 402 var onFileExists = function() { | 493 var onFileExists = function() { |
| 403 this.prompt_.show('file_exists', 3000); | 494 this.prompt_.show('file_exists', 3000); |
| 404 this.filenameEdit_.value = name; | 495 this.filenameEdit_.value = name; |
| 405 this.onFilenameClick_(); | 496 this.onFilenameClick_(); |
| 406 }.bind(this); | 497 }.bind(this); |
| 407 | 498 |
| 408 var onSuccess = function() { | 499 var onSuccess = function() { |
| 409 this.slideMode_.updateSelectedUrl_(oldUrl, item.getUrl()); | 500 this.slideMode_.updateSelectedUrl_(oldUrl, item.getUrl()); |
| 501 this.updateFilename_(); |
| 410 }.bind(this); | 502 }.bind(this); |
| 411 | 503 |
| 412 if (this.filenameEdit_.value) { | 504 if (this.filenameEdit_.value) { |
| 413 this.getSingleSelectedItem().rename(this.context_.saveDirEntry, | 505 this.getSingleSelectedItem().rename(this.context_.saveDirEntry, |
| 414 this.filenameEdit_.value, onSuccess, onFileExists); | 506 this.filenameEdit_.value, onSuccess, onFileExists); |
| 415 } | 507 } |
| 416 | 508 |
| 417 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); | 509 ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); |
| 418 this.checkActivity_(); | 510 this.checkActivity_(); |
| 419 }; | 511 }; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 442 */ | 534 */ |
| 443 Gallery.prototype.isRenaming_ = function() { | 535 Gallery.prototype.isRenaming_ = function() { |
| 444 return this.filenameSpacer_.hasAttribute('renaming'); | 536 return this.filenameSpacer_.hasAttribute('renaming'); |
| 445 }; | 537 }; |
| 446 | 538 |
| 447 /** | 539 /** |
| 448 * Content area click handler. | 540 * Content area click handler. |
| 449 * @private | 541 * @private |
| 450 */ | 542 */ |
| 451 Gallery.prototype.onContentClick_ = function() { | 543 Gallery.prototype.onContentClick_ = function() { |
| 544 this.closeShareMenu_(); |
| 452 this.filenameEdit_.blur(); | 545 this.filenameEdit_.blur(); |
| 453 }; | 546 }; |
| 454 | 547 |
| 455 // Share button support. | 548 // Share button support. |
| 456 | 549 |
| 457 /** | 550 /** |
| 458 * @return {boolean} True if the Share mode is active. | 551 * @return {boolean} True if the Share menu is active. |
| 459 * @private | 552 * @private |
| 460 */ | 553 */ |
| 461 Gallery.prototype.isSharing_ = function() { | 554 Gallery.prototype.isSharing_ = function() { |
| 462 return this.shareMode_.isActive(); | 555 return !this.shareMenu_.hidden; |
| 556 }; |
| 557 |
| 558 /** |
| 559 * Close Share menu if it is open. |
| 560 * @private |
| 561 */ |
| 562 Gallery.prototype.closeShareMenu_ = function() { |
| 563 if (this.isSharing_()) |
| 564 this.toggleShare_(); |
| 463 }; | 565 }; |
| 464 | 566 |
| 465 /** | 567 /** |
| 466 * Share button handler. | 568 * Share button handler. |
| 467 * @param {Event} event Event. | 569 * @private |
| 468 * @private | 570 */ |
| 469 */ | 571 Gallery.prototype.toggleShare_ = function() { |
| 470 Gallery.prototype.onShare_ = function(event) { | 572 if (!this.shareButton_.hasAttribute('disabled')) |
| 471 this.shareMode_.toggle(event); | 573 this.shareMenu_.hidden = !this.shareMenu_.hidden; |
| 472 this.checkActivity_(); | 574 this.checkActivity_(); |
| 473 }; | 575 }; |
| 474 | 576 |
| 475 /** | 577 /** |
| 476 * | |
| 477 * @param {ImageEditor} editor Editor. | |
| 478 * @param {Element} container Container element. | |
| 479 * @param {Element} toolbar Toolbar element. | |
| 480 * @param {function} onClick Click handler. | |
| 481 * @param {function(function())} actionCallback Function to execute the action. | |
| 482 * @param {function(string):string} displayStringFunction String formatting | |
| 483 * function. | |
| 484 * @constructor | |
| 485 */ | |
| 486 function ShareMode(editor, container, toolbar, | |
| 487 onClick, actionCallback, displayStringFunction) { | |
| 488 ImageEditor.Mode.call(this, 'share'); | |
| 489 | |
| 490 this.message_ = null; | |
| 491 | |
| 492 var button = util.createChild(toolbar, 'button share'); | |
| 493 button.textContent = displayStringFunction('share'); | |
| 494 button.addEventListener('click', onClick); | |
| 495 this.bind(editor, button); | |
| 496 | |
| 497 this.actionCallback_ = actionCallback; | |
| 498 | |
| 499 this.menu_ = util.createChild(container, 'share-menu'); | |
| 500 this.menu_.hidden = true; | |
| 501 | |
| 502 util.createChild(this.menu_, 'bubble-point'); | |
| 503 } | |
| 504 | |
| 505 ShareMode.prototype = { __proto__: ImageEditor.Mode.prototype }; | |
| 506 | |
| 507 /** | |
| 508 * Shows share mode UI. | |
| 509 */ | |
| 510 ShareMode.prototype.setUp = function() { | |
| 511 ImageEditor.Mode.prototype.setUp.apply(this, arguments); | |
| 512 this.menu_.hidden = false; | |
| 513 ImageUtil.setAttribute(this.button_, 'pressed', false); | |
| 514 }; | |
| 515 | |
| 516 /** | |
| 517 * Hides share mode UI. | |
| 518 */ | |
| 519 ShareMode.prototype.cleanUpUI = function() { | |
| 520 ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); | |
| 521 this.menu_.hidden = true; | |
| 522 }; | |
| 523 | |
| 524 /** | |
| 525 * @return {boolean} True if the menu is currently open. | |
| 526 */ | |
| 527 ShareMode.prototype.isActive = function() { | |
| 528 return !this.menu_.hidden; | |
| 529 }; | |
| 530 | |
| 531 /** | |
| 532 * Show/hide the menu. | |
| 533 * @param {Event} event Event. | |
| 534 */ | |
| 535 ShareMode.prototype.toggle = function(event) { | |
| 536 this.editor_.enterMode(this, event); | |
| 537 }; | |
| 538 | |
| 539 /** | |
| 540 * Update available actions list based on the currently selected urls. | 578 * Update available actions list based on the currently selected urls. |
| 541 * | 579 * @private. |
| 542 * @param {Array.<string>} urls Array of urls. | 580 */ |
| 543 */ | 581 Gallery.prototype.updateShareMenu_ = function() { |
| 544 ShareMode.prototype.updateMenu = function(urls) { | 582 var urls = |
| 583 this.getSelectedItems().map(function(item) { return item.getUrl() }); |
| 584 |
| 545 var internalId = util.getExtensionId(); | 585 var internalId = util.getExtensionId(); |
| 546 function isShareAction(task) { | 586 function isShareAction(task) { |
| 547 var task_parts = task.taskId.split('|'); | 587 var task_parts = task.taskId.split('|'); |
| 548 return task_parts[0] != internalId; | 588 return task_parts[0] != internalId; |
| 549 } | 589 } |
| 550 | 590 |
| 551 var items = this.menu_.querySelectorAll('.item'); | |
| 552 for (var i = 0; i != items.length; i++) { | |
| 553 items[i].parentNode.removeChild(items[i]); | |
| 554 } | |
| 555 | |
| 556 var api = Gallery.getFileBrowserPrivate(); | 591 var api = Gallery.getFileBrowserPrivate(); |
| 557 var mimeTypes = []; // TODO(kaznacheev) Collect mime types properly. | 592 var mimeTypes = []; // TODO(kaznacheev) Collect mime types properly. |
| 558 api.getFileTasks(urls, mimeTypes, function(tasks) { | 593 api.getFileTasks(urls, mimeTypes, function(tasks) { |
| 559 for (var i = 0; i != tasks.length; i++) { | 594 var wasHidden = this.shareMenu_.hidden; |
| 560 var task = tasks[i]; | 595 this.shareMenu_.hidden = true; |
| 596 var items = this.shareMenu_.querySelectorAll('.item'); |
| 597 for (var i = 0; i != items.length; i++) { |
| 598 items[i].parentNode.removeChild(items[i]); |
| 599 } |
| 600 |
| 601 for (var t = 0; t != tasks.length; t++) { |
| 602 var task = tasks[t]; |
| 561 if (!isShareAction(task)) continue; | 603 if (!isShareAction(task)) continue; |
| 562 | 604 |
| 563 var item = document.createElement('div'); | 605 var item = util.createChild(this.shareMenu_, 'item'); |
| 564 item.className = 'item'; | |
| 565 this.menu_.appendChild(item); | |
| 566 | |
| 567 item.textContent = task.title; | 606 item.textContent = task.title; |
| 568 item.style.backgroundImage = 'url(' + task.iconUrl + ')'; | 607 item.style.backgroundImage = 'url(' + task.iconUrl + ')'; |
| 569 item.addEventListener('click', this.actionCallback_.bind(null, | 608 item.addEventListener('click', function(taskId) { |
| 570 api.executeTask.bind(api, task.taskId, urls))); | 609 this.toggleShare_(); // Hide the menu. |
| 610 this.executeWhenReady(api.executeTask.bind(api, taskId, urls)); |
| 611 }.bind(this, task.taskId)); |
| 571 } | 612 } |
| 572 | 613 |
| 573 if (this.menu_.firstChild) | 614 var empty = this.shareMenu_.querySelector('.item') == null; |
| 574 this.button_.removeAttribute('disabled'); | 615 ImageUtil.setAttribute(this.shareButton_, 'disabled', empty); |
| 575 else | 616 this.shareMenu_.hidden = wasHidden || empty; |
| 576 this.button_.setAttribute('disabled', 'true'); | |
| 577 }.bind(this)); | 617 }.bind(this)); |
| 578 }; | 618 }; |
| 619 |
| 620 /** |
| 621 * @param {Element} container Main container. |
| 622 * @param {Element} content Content container. |
| 623 * @param {cr.ui.ArrayDataModel} dataModel Data model. |
| 624 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. |
| 625 * @param {MetadataCache} metadataCache Metadata cache. |
| 626 * @param {function} openSelectedItem Function to open the selected item in the |
| 627 * slide mode. |
| 628 * @constructor |
| 629 */ |
| 630 function GridMode(container, content, dataModel, selectionModel, |
| 631 metadataCache, openSelectedItem) { |
| 632 this.container_ = container; |
| 633 this.metadataCache_ = metadataCache; |
| 634 this.grid_ = util.createChild(content, 'thumbnail-grid', 'grid'); |
| 635 cr.ui.Grid.decorate(this.grid_); |
| 636 |
| 637 this.grid_.dataModel = dataModel; |
| 638 this.grid_.selectionModel = selectionModel; |
| 639 this.grid_.itemConstructor = |
| 640 GridMode.Item.bind(null, container.ownerDocument, metadataCache); |
| 641 |
| 642 this.container_.ownerDocument.defaultView.addEventListener( |
| 643 'resize', this.redraw_.bind(this)); |
| 644 |
| 645 this.openSelectedItem_ = openSelectedItem; |
| 646 this.grid_.addEventListener('dblclick', this.openSelectedItem_); |
| 647 } |
| 648 |
| 649 /** |
| 650 * Enter the mode. |
| 651 * @param {function} opt_callback Callback. |
| 652 */ |
| 653 GridMode.prototype.enter = function(opt_callback) { |
| 654 this.container_.setAttribute('mode', 'grid'); |
| 655 this.redraw_(); |
| 656 if (opt_callback) opt_callback(); |
| 657 }; |
| 658 |
| 659 /** |
| 660 * Leave the mode. |
| 661 * @param {function} opt_callback Callback. |
| 662 */ |
| 663 GridMode.prototype.leave = function(opt_callback) { |
| 664 if (opt_callback) opt_callback(); |
| 665 }; |
| 666 |
| 667 /** |
| 668 * Redraw the grid. |
| 669 * @private |
| 670 */ |
| 671 GridMode.prototype.redraw_ = function() { |
| 672 this.grid_.startBatchUpdates(); |
| 673 setTimeout(function() { |
| 674 this.grid_.columns = 0; |
| 675 this.grid_.redraw(); |
| 676 this.grid_.endBatchUpdates(); |
| 677 }.bind(this), 0); |
| 678 }; |
| 679 |
| 680 /** |
| 681 * @param {Gallery.Item} item The updated item. |
| 682 */ |
| 683 GridMode.prototype.updateThumbnail = function(item) { |
| 684 var listItems = this.grid_.querySelectorAll('li'); |
| 685 for (var i = 0; i != listItems.length; i++) { |
| 686 GridMode.Item.updateThumbnail(listItems[i], this.metadataCache_, item); |
| 687 } |
| 688 }; |
| 689 |
| 690 /** |
| 691 * @param {Event} event Event. |
| 692 * @return {boolean} True if handled. |
| 693 */ |
| 694 GridMode.prototype.onKeyDown = function(event) { |
| 695 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
| 696 case 'Enter': |
| 697 this.openSelectedItem_(); |
| 698 return true; |
| 699 } |
| 700 |
| 701 return false; |
| 702 }; |
| 703 |
| 704 /** |
| 705 * @return {boolean} Always true (no tools fading in the Grid mode). |
| 706 */ |
| 707 GridMode.prototype.hasActiveTool = function() { |
| 708 return true; |
| 709 }; |
| 710 |
| 711 /** |
| 712 * @param {Document} document Document. |
| 713 * @param {MetadataCache} metadataCache Metadata cache. |
| 714 * @param {Gallery.Item} item Item. |
| 715 * @return {Element} Newly created grid item. |
| 716 * @constructor |
| 717 */ |
| 718 GridMode.Item = function(document, metadataCache, item) { |
| 719 var li = document.createElement('li'); |
| 720 li.__proto__ = GridMode.Item.prototype; |
| 721 li.className = 'thumbnail-item'; |
| 722 li.item = item; |
| 723 |
| 724 var box = util.createChild(li, 'img-container'); |
| 725 |
| 726 GridMode.Item.updateThumbnail(li, metadataCache, item); |
| 727 return li; |
| 728 }; |
| 729 |
| 730 /** |
| 731 * @param {Element} li Grid item. |
| 732 * @param {MetadataCache} metadataCache Metadata cache. |
| 733 * @param {Gallery.Item} item Gallery item. |
| 734 */ |
| 735 GridMode.Item.updateThumbnail = function(li, metadataCache, item) { |
| 736 if (item != li.item) |
| 737 return; |
| 738 |
| 739 var box = li.querySelector('.img-container'); |
| 740 var url = item.getUrl(); |
| 741 metadataCache.get(url, Gallery.METADATA_TYPE, |
| 742 function(metadata) { |
| 743 new ThumbnailLoader(url, metadata).load(box, false /* fit */); |
| 744 }); |
| 745 }; |
| 746 |
| 747 GridMode.Item.prototype = { |
| 748 __proto__: cr.ui.ListItem.prototype, |
| 749 get label() {}, |
| 750 set label(value) {} |
| 751 }; |
| OLD | NEW |