Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Image gallery for viewing and editing image files. | 6 * Image gallery for viewing and editing image files. |
| 7 * | 7 * |
| 8 * @param {HTMLDivElement} container | 8 * @param {HTMLDivElement} container |
| 9 * @param {function} closeCallback | 9 * @param {function} closeCallback |
| 10 * @param {MetadataProvider} metadataProvider | 10 * @param {MetadataProvider} metadataProvider |
| 11 * @param {Array.<Object>} shareActions | |
| 11 */ | 12 */ |
| 12 function Gallery(container, closeCallback, metadataProvider) { | 13 function Gallery(container, closeCallback, metadataProvider, shareActions) { |
| 13 this.container_ = container; | 14 this.container_ = container; |
| 14 this.document_ = container.ownerDocument; | 15 this.document_ = container.ownerDocument; |
| 15 this.editing_ = false; | 16 this.editing_ = false; |
| 17 this.sharing_ = false; | |
| 16 this.closeCallback_ = closeCallback; | 18 this.closeCallback_ = closeCallback; |
| 17 this.metadataProvider_ = metadataProvider; | 19 this.metadataProvider_ = metadataProvider; |
| 18 this.onFadeTimeoutBound_ = this.onFadeTimeout_.bind(this); | 20 this.onFadeTimeoutBound_ = this.onFadeTimeout_.bind(this); |
| 19 this.fadeTimeoutId_ = null; | 21 this.fadeTimeoutId_ = null; |
| 20 | 22 |
| 21 this.initDom_(); | 23 this.initDom_(shareActions); |
| 22 } | 24 } |
| 23 | 25 |
| 24 Gallery.open = function( | 26 Gallery.open = function( |
| 25 parentDirEntry, urls, closeCallback, metadataProvider) { | 27 parentDirEntry, urls, closeCallback, metadataProvider, shareActions) { |
| 26 var container = document.querySelector('.gallery'); | 28 var container = document.querySelector('.gallery'); |
| 27 container.innerHTML = ''; | 29 container.innerHTML = ''; |
| 28 var gallery = new Gallery(container, closeCallback, metadataProvider); | 30 var gallery = new Gallery(container, closeCallback, metadataProvider, |
| 31 shareActions); | |
| 29 gallery.load(parentDirEntry, urls); | 32 gallery.load(parentDirEntry, urls); |
| 30 }; | 33 }; |
| 31 | 34 |
| 32 // TODO(kaznacheev): localization. | 35 // TODO(kaznacheev): localization. |
| 33 Gallery.displayStrings = { | 36 Gallery.displayStrings = { |
| 34 close: 'Close', | 37 close: 'Close', |
| 35 edit: 'Edit', | 38 edit: 'Edit', |
| 36 share: 'Share', | 39 share: 'Share', |
| 37 autofix: 'Auto-fix', | 40 autofix: 'Auto-fix', |
| 38 crop: 'Crop', | 41 crop: 'Crop', |
| 39 exposure: 'Brightness / contrast', | 42 exposure: 'Brightness / contrast', |
| 40 brightness: 'Brightness', | 43 brightness: 'Brightness', |
| 41 contrast: 'Contrast', | 44 contrast: 'Contrast', |
| 42 rotate: 'Rotate', | 45 rotate: 'Rotate', |
| 43 undo: 'Undo' | 46 undo: 'Undo' |
| 44 }; | 47 }; |
| 45 | 48 |
| 46 | 49 |
| 47 Gallery.editorModes = [ | 50 Gallery.editorModes = [ |
| 48 ImageEditor.Mode.InstantAutofix, | 51 ImageEditor.Mode.InstantAutofix, |
| 49 ImageEditor.Mode.Crop, | 52 ImageEditor.Mode.Crop, |
| 50 ImageEditor.Mode.Exposure, | 53 ImageEditor.Mode.Exposure, |
| 51 ImageEditor.Mode.InstantRotate | 54 ImageEditor.Mode.InstantRotate |
| 52 ]; | 55 ]; |
| 53 | 56 |
| 54 Gallery.FADE_TIMEOUT = 5000; | 57 Gallery.FADE_TIMEOUT = 5000; |
| 55 | 58 |
| 56 Gallery.prototype.initDom_ = function() { | 59 Gallery.prototype.initDom_ = function(shareActions) { |
| 57 var doc = this.document_; | 60 var doc = this.document_; |
| 58 this.container_.addEventListener('keydown', this.onKeyDown_.bind(this)); | 61 this.container_.addEventListener('keydown', this.onKeyDown_.bind(this)); |
| 59 this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this)); | 62 this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this)); |
| 60 | 63 |
| 61 this.closeButton_ = doc.createElement('div'); | 64 this.closeButton_ = doc.createElement('div'); |
| 62 this.closeButton_.className = 'close'; | 65 this.closeButton_.className = 'close'; |
| 63 this.closeButton_.textContent = Gallery.displayStrings['close']; | 66 this.closeButton_.textContent = Gallery.displayStrings['close']; |
| 64 this.closeButton_.addEventListener('click', this.onClose_.bind(this)); | 67 this.closeButton_.addEventListener('click', this.onClose_.bind(this)); |
| 65 this.container_.appendChild(this.closeButton_); | 68 this.container_.appendChild(this.closeButton_); |
| 66 | 69 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 82 this.editButton_ = doc.createElement('div'); | 85 this.editButton_ = doc.createElement('div'); |
| 83 this.editButton_.className = 'button edit'; | 86 this.editButton_.className = 'button edit'; |
| 84 this.editButton_.textContent = Gallery.displayStrings['edit']; | 87 this.editButton_.textContent = Gallery.displayStrings['edit']; |
| 85 this.editButton_.addEventListener('click', this.onEdit_.bind(this)); | 88 this.editButton_.addEventListener('click', this.onEdit_.bind(this)); |
| 86 this.toolbar_.appendChild(this.editButton_); | 89 this.toolbar_.appendChild(this.editButton_); |
| 87 | 90 |
| 88 this.shareButton_ = doc.createElement('div'); | 91 this.shareButton_ = doc.createElement('div'); |
| 89 this.shareButton_.className = 'button share'; | 92 this.shareButton_.className = 'button share'; |
| 90 this.shareButton_.textContent = Gallery.displayStrings['share']; | 93 this.shareButton_.textContent = Gallery.displayStrings['share']; |
| 91 this.shareButton_.addEventListener('click', this.onShare_.bind(this)); | 94 this.shareButton_.addEventListener('click', this.onShare_.bind(this)); |
| 92 this.toolbar_.appendChild(this.shareButton_); | 95 if (shareActions.length > 0) { |
|
Vladislav Kaznacheev
2011/09/27 08:31:07
Why not hide everything the above 4 lines behind t
dgozman
2011/09/27 12:36:28
this.shareButton_ is referenced through the code,
| |
| 96 this.toolbar_.appendChild(this.shareButton_); | |
| 97 } | |
| 93 | 98 |
| 94 this.editBarMain_ = doc.createElement('div'); | 99 this.editBarMain_ = doc.createElement('div'); |
| 95 this.editBarMain_.className = 'edit-main'; | 100 this.editBarMain_.className = 'edit-main'; |
| 96 this.editBarMain_.setAttribute('hidden', 'hidden'); | 101 this.editBarMain_.setAttribute('hidden', 'hidden'); |
| 97 this.editBar_.appendChild(this.editBarMain_); | 102 this.editBar_.appendChild(this.editBarMain_); |
| 98 | 103 |
| 99 this.editBarMode_ = doc.createElement('div'); | 104 this.editBarMode_ = doc.createElement('div'); |
| 100 this.editBarMode_.className = 'edit-modal'; | 105 this.editBarMode_.className = 'edit-modal'; |
| 101 this.editBarMode_.setAttribute('hidden', 'hidden'); | 106 this.editBarMode_.setAttribute('hidden', 'hidden'); |
| 102 this.editBar_.appendChild(this.editBarMode_); | 107 this.editBar_.appendChild(this.editBarMode_); |
| 103 | 108 |
| 109 this.shareMenu_ = doc.createElement('div'); | |
|
Vladislav Kaznacheev
2011/09/27 08:31:07
Why create a menu if shareActions is empty?
dgozman
2011/09/27 12:36:28
Same as for shareButton. However, I guard appendin
| |
| 110 this.shareMenu_.className = 'share-menu'; | |
| 111 this.shareMenu_.setAttribute('hidden', 'hidden'); | |
| 112 for (var index = 0; index < shareActions.length; index++) { | |
| 113 var action = shareActions[index]; | |
| 114 var row = doc.createElement('div'); | |
| 115 var img = doc.createElement('img'); | |
| 116 img.src = action.iconUrl; | |
| 117 row.appendChild(img); | |
| 118 row.appendChild(doc.createTextNode(action.title)); | |
| 119 row.addEventListener('click', this.onActionExecute_.bind(this, action)); | |
| 120 this.shareMenu_.appendChild(row); | |
| 121 } | |
| 122 this.container_.appendChild(this.shareMenu_); | |
| 123 | |
| 104 this.editor_ = new ImageEditor( | 124 this.editor_ = new ImageEditor( |
| 105 this.imageContainer_, | 125 this.imageContainer_, |
| 106 this.editBarMain_, | 126 this.editBarMain_, |
| 107 this.editBarMode_, | 127 this.editBarMode_, |
| 108 Gallery.editorModes, | 128 Gallery.editorModes, |
| 109 Gallery.displayStrings); | 129 Gallery.displayStrings); |
| 110 }; | 130 }; |
| 111 | 131 |
| 112 Gallery.prototype.load = function(parentDirEntry, urls) { | 132 Gallery.prototype.load = function(parentDirEntry, urls) { |
| 113 this.editBar_.setAttribute('hidden', 'hidden'); | 133 this.editBar_.setAttribute('hidden', 'hidden'); |
| 114 this.editBarMain_.setAttribute('hidden', 'hidden'); | 134 this.editBarMain_.setAttribute('hidden', 'hidden'); |
| 115 this.editButton_.removeAttribute('pressed'); | 135 this.editButton_.removeAttribute('pressed'); |
| 116 this.shareButton_.removeAttribute('pressed'); | 136 this.shareButton_.removeAttribute('pressed'); |
| 117 this.toolbar_.removeAttribute('hidden'); | 137 this.toolbar_.removeAttribute('hidden'); |
| 138 this.shareMenu_.setAttribute('hidden', 'hidden'); | |
| 118 this.editing_ = false; | 139 this.editing_ = false; |
| 140 this.sharing_ = false; | |
| 119 | 141 |
| 120 if (urls.length == 0) | 142 if (urls.length == 0) |
| 121 return; | 143 return; |
| 122 | 144 |
| 123 // TODO(kaznacheev): instead of always selecting the 0-th url | 145 // TODO(kaznacheev): instead of always selecting the 0-th url |
| 124 // select the url passed from the FileManager. | 146 // select the url passed from the FileManager. |
| 125 this.ribbon_.load(urls, urls[0], this.metadataProvider_); | 147 this.ribbon_.load(urls, urls[0], this.metadataProvider_); |
| 126 this.parentDirEntry_ = parentDirEntry; | 148 this.parentDirEntry_ = parentDirEntry; |
| 127 | 149 |
| 128 this.initiateFading_(); | 150 this.initiateFading_(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 onError); | 201 onError); |
| 180 }, onError); | 202 }, onError); |
| 181 } else { | 203 } else { |
| 182 // This branch is needed only for gallery_demo.js | 204 // This branch is needed only for gallery_demo.js |
| 183 currentItem.onSaveSuccess( | 205 currentItem.onSaveSuccess( |
| 184 canvas.toDataURL(metadataEncoder.getMetadata().mimeType)); | 206 canvas.toDataURL(metadataEncoder.getMetadata().mimeType)); |
| 185 if (opt_callback) opt_callback(); | 207 if (opt_callback) opt_callback(); |
| 186 } | 208 } |
| 187 }; | 209 }; |
| 188 | 210 |
| 211 Gallery.prototype.onActionExecute_ = function(action) { | |
| 212 var item = this.currentItem_; | |
| 213 if (item) { | |
| 214 action.execute([item.getUrl()]); | |
|
Vladislav Kaznacheev
2011/09/27 08:31:07
This would not work if the item has been edited bu
dgozman
2011/09/27 12:36:28
Done.
| |
| 215 this.onShare_(); | |
| 216 } | |
| 217 }; | |
| 189 | 218 |
| 190 Gallery.prototype.onClose_ = function() { | 219 Gallery.prototype.onClose_ = function() { |
| 191 // TODO: handle write errors gracefully (suggest retry or saving elsewhere). | 220 // TODO: handle write errors gracefully (suggest retry or saving elsewhere). |
| 192 this.saveChanges_(this.closeCallback_); | 221 this.saveChanges_(this.closeCallback_); |
| 193 }; | 222 }; |
| 194 | 223 |
| 195 Gallery.prototype.onSelect_ = function(item) { | 224 Gallery.prototype.onSelect_ = function(item) { |
| 196 if (this.currentItem_) { | 225 if (this.currentItem_) { |
| 197 this.saveChanges_(); | 226 this.saveChanges_(); |
| 198 } | 227 } |
| 199 | 228 |
| 200 this.currentItem_ = item; | 229 this.currentItem_ = item; |
| 201 | 230 |
| 202 this.editor_.load(this.currentItem_.getContent(), | 231 this.editor_.load(this.currentItem_.getContent(), |
| 203 ImageUtil.deepCopy(this.currentItem_.getMetadata())); | 232 ImageUtil.deepCopy(this.currentItem_.getMetadata())); |
| 204 }; | 233 }; |
| 205 | 234 |
| 206 Gallery.prototype.onEdit_ = function(event) { | 235 Gallery.prototype.onEdit_ = function(event) { |
| 236 this.toolbar_.removeAttribute('hidden'); | |
| 237 | |
| 207 var self = this; | 238 var self = this; |
| 208 if (this.editing_) { | 239 if (this.editing_) { |
| 209 this.editor_.onModeLeave(); | 240 this.editor_.onModeLeave(); |
| 210 this.editBar_.setAttribute('hidden', 'hidden'); | 241 this.editBar_.setAttribute('hidden', 'hidden'); |
| 211 this.editButton_.removeAttribute('pressed'); | 242 this.editButton_.removeAttribute('pressed'); |
| 212 this.editing_ = false; | 243 this.editing_ = false; |
| 213 this.initiateFading_(); | 244 this.initiateFading_(); |
| 214 window.setTimeout(function() { | 245 window.setTimeout(function() { |
| 215 // Hide the toolbar, so it will not overlap with buttons. | 246 // Hide the toolbar, so it will not overlap with buttons. |
| 216 self.editBarMain_.setAttribute('hidden', 'hidden'); | 247 self.editBarMain_.setAttribute('hidden', 'hidden'); |
| 217 self.ribbon_.redraw(); | 248 self.ribbon_.redraw(); |
| 218 }, 500); | 249 }, 500); |
| 219 } else { | 250 } else { |
| 220 this.cancelFading_(); | 251 this.cancelFading_(); |
| 221 // Show the toolbar. | 252 // Show the toolbar. |
| 222 this.editBarMain_.removeAttribute('hidden'); | 253 this.editBarMain_.removeAttribute('hidden'); |
| 223 // Use setTimeout, so computed style will be recomputed. | 254 // Use setTimeout, so computed style will be recomputed. |
| 224 window.setTimeout(function() { | 255 window.setTimeout(function() { |
| 225 self.editBar_.removeAttribute('hidden'); | 256 self.editBar_.removeAttribute('hidden'); |
| 226 self.editButton_.setAttribute('pressed', 'pressed'); | 257 self.editButton_.setAttribute('pressed', 'pressed'); |
| 227 self.editing_ = true; | 258 self.editing_ = true; |
| 228 self.ribbon_.redraw(); | 259 self.ribbon_.redraw(); |
| 229 }, 0); | 260 }, 0); |
| 230 } | 261 } |
| 231 }; | 262 }; |
| 232 | 263 |
| 233 Gallery.prototype.onShare_ = function(event) { | 264 Gallery.prototype.onShare_ = function(event) { |
| 234 // TODO(dgozman): implement. | 265 this.toolbar_.removeAttribute('hidden'); |
| 266 | |
| 267 if (this.sharing_) { | |
| 268 this.shareMenu_.setAttribute('hidden', 'hidden'); | |
| 269 } else { | |
| 270 this.shareMenu_.removeAttribute('hidden'); | |
| 271 } | |
| 272 this.sharing_ = !this.sharing_; | |
| 235 }; | 273 }; |
| 236 | 274 |
| 237 Gallery.prototype.onKeyDown_ = function(event) { | 275 Gallery.prototype.onKeyDown_ = function(event) { |
| 238 if (this.editing_) | 276 if (this.editing_ || this.sharing_) |
| 239 return; | 277 return; |
| 240 switch (event.keyIdentifier) { | 278 switch (event.keyIdentifier) { |
| 241 case 'Home': | 279 case 'Home': |
| 242 this.ribbon_.scrollToFirst(); | 280 this.ribbon_.scrollToFirst(); |
| 243 break; | 281 break; |
| 244 case 'Left': | 282 case 'Left': |
| 245 this.ribbon_.scrollLeft(); | 283 this.ribbon_.scrollLeft(); |
| 246 break; | 284 break; |
| 247 case 'Right': | 285 case 'Right': |
| 248 this.ribbon_.scrollRight(); | 286 this.ribbon_.scrollRight(); |
| 249 break; | 287 break; |
| 250 case 'End': | 288 case 'End': |
| 251 this.ribbon_.scrollToLast(); | 289 this.ribbon_.scrollToLast(); |
| 252 break; | 290 break; |
| 253 } | 291 } |
| 254 }; | 292 }; |
| 255 | 293 |
| 256 Gallery.prototype.onMouseMove_ = function(e) { | 294 Gallery.prototype.onMouseMove_ = function(e) { |
| 257 this.cancelFading_(); | 295 this.cancelFading_(); |
| 258 this.toolbar_.removeAttribute('hidden'); | 296 this.toolbar_.removeAttribute('hidden'); |
| 259 this.initiateFading_(); | 297 this.initiateFading_(); |
| 260 }; | 298 }; |
| 261 | 299 |
| 262 Gallery.prototype.onFadeTimeout_ = function() { | 300 Gallery.prototype.onFadeTimeout_ = function() { |
| 263 this.fadeTimeoutId_ = null; | 301 this.fadeTimeoutId_ = null; |
| 302 if (this.editing_ || this.sharing_) return; | |
| 264 this.toolbar_.setAttribute('hidden', 'hidden'); | 303 this.toolbar_.setAttribute('hidden', 'hidden'); |
| 265 }; | 304 }; |
| 266 | 305 |
| 267 Gallery.prototype.initiateFading_ = function() { | 306 Gallery.prototype.initiateFading_ = function() { |
| 268 if (this.editing_ || this.fadeTimeoutId_) { | 307 if (this.editing_ || this.sharing_ || this.fadeTimeoutId_) { |
| 269 return; | 308 return; |
| 270 } | 309 } |
| 271 this.fadeTimeoutId_ = window.setTimeout( | 310 this.fadeTimeoutId_ = window.setTimeout( |
| 272 this.onFadeTimeoutBound_, Gallery.FADE_TIMEOUT); | 311 this.onFadeTimeoutBound_, Gallery.FADE_TIMEOUT); |
| 273 }; | 312 }; |
| 274 | 313 |
| 275 Gallery.prototype.cancelFading_ = function() { | 314 Gallery.prototype.cancelFading_ = function() { |
| 276 if (this.fadeTimeoutId_) { | 315 if (this.fadeTimeoutId_) { |
| 277 window.clearTimeout(this.fadeTimeoutId_); | 316 window.clearTimeout(this.fadeTimeoutId_); |
| 278 this.fadeTimeoutId_ = null; | 317 this.fadeTimeoutId_ = null; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 403 this.box_.addEventListener('click', selectClosure.bind(null, this)); | 442 this.box_.addEventListener('click', selectClosure.bind(null, this)); |
| 404 this.box_.appendChild(this.img_); | 443 this.box_.appendChild(this.img_); |
| 405 | 444 |
| 406 this.original_ = true; | 445 this.original_ = true; |
| 407 }; | 446 }; |
| 408 | 447 |
| 409 Ribbon.Item.prototype.getBox = function () { return this.box_ }; | 448 Ribbon.Item.prototype.getBox = function () { return this.box_ }; |
| 410 | 449 |
| 411 Ribbon.Item.prototype.isOriginal = function () { return this.original_ }; | 450 Ribbon.Item.prototype.isOriginal = function () { return this.original_ }; |
| 412 | 451 |
| 452 Ribbon.Item.prototype.getUrl = function () { return this.url_ }; | |
| 453 | |
| 413 Ribbon.Item.prototype.select = function(on) { | 454 Ribbon.Item.prototype.select = function(on) { |
| 414 if (on) | 455 if (on) |
| 415 this.box_.setAttribute('selected', 'selected'); | 456 this.box_.setAttribute('selected', 'selected'); |
| 416 else | 457 else |
| 417 this.box_.removeAttribute('selected'); | 458 this.box_.removeAttribute('selected'); |
| 418 }; | 459 }; |
| 419 | 460 |
| 420 // TODO: Localize? | 461 // TODO: Localize? |
| 421 Ribbon.Item.COPY_SIGNATURE = '_Edited_'; | 462 Ribbon.Item.COPY_SIGNATURE = '_Edited_'; |
| 422 | 463 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 509 metadata.imageTransform; | 550 metadata.imageTransform; |
| 510 | 551 |
| 511 this.box_.style.webkitTransform = transform ? | 552 this.box_.style.webkitTransform = transform ? |
| 512 ('scaleX(' + transform.scaleX + ') ' + | 553 ('scaleX(' + transform.scaleX + ') ' + |
| 513 'scaleY(' + transform.scaleY + ') ' + | 554 'scaleY(' + transform.scaleY + ') ' + |
| 514 'rotate(' + transform.rotate90 * 90 + 'deg)') : | 555 'rotate(' + transform.rotate90 * 90 + 'deg)') : |
| 515 ''; | 556 ''; |
| 516 | 557 |
| 517 this.img_.setAttribute('src', metadata.thumbnailURL || this.url_); | 558 this.img_.setAttribute('src', metadata.thumbnailURL || this.url_); |
| 518 }; | 559 }; |
| OLD | NEW |