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 |