Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: chrome/browser/resources/file_manager/js/photo/gallery.js

Issue 10829421: First cut of the updated Photo Editor UI (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698