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 /** | 5 /** |
6 * Slide mode displays a single image and has a set of controls to navigate | 6 * Slide mode displays a single image and has a set of controls to navigate |
7 * between the images and to edit an image. | 7 * between the images and to edit an image. |
8 * | 8 * |
9 * @param {Element} container Container element. | 9 * TODO(kaznacheev): Introduce a parameter object. |
10 * | |
11 * @param {Element} container Main container element. | |
12 * @param {Element} content Content container element. | |
10 * @param {Element} toolbar Toolbar element. | 13 * @param {Element} toolbar Toolbar element. |
11 * @param {ImageEditor.Prompt} prompt Prompt. | 14 * @param {ImageEditor.Prompt} prompt Prompt. |
15 * @param {cr.ui.ArrayDataModel} dataModel Data model. | |
16 * @param {cr.ui.ListSelectionModel} selectionModel Selection model. | |
12 * @param {Object} context Context. | 17 * @param {Object} context Context. |
13 * @param {function(string):string} displayStringFunction String formatting | 18 * @param {function(string):string} displayStringFunction String formatting |
14 * function. | 19 * function. |
15 * @constructor | 20 * @constructor |
16 */ | 21 */ |
17 function SlideMode(container, toolbar, prompt, context, displayStringFunction) { | 22 function SlideMode(container, content, toolbar, prompt, |
23 dataModel, selectionModel, | |
24 context, displayStringFunction) { | |
18 this.container_ = container; | 25 this.container_ = container; |
26 this.document_ = container.ownerDocument; | |
27 this.content = content; | |
19 this.toolbar_ = toolbar; | 28 this.toolbar_ = toolbar; |
20 this.document_ = container.ownerDocument; | |
21 this.prompt_ = prompt; | 29 this.prompt_ = prompt; |
30 this.dataModel_ = dataModel; | |
31 this.selectionModel_ = selectionModel; | |
22 this.context_ = context; | 32 this.context_ = context; |
23 this.metadataCache_ = context.metadataCache; | 33 this.metadataCache_ = context.metadataCache; |
24 this.displayStringFunction_ = displayStringFunction; | 34 this.displayStringFunction_ = displayStringFunction; |
25 | 35 |
36 this.onSelectionBound_ = this.onSelection_.bind(this); | |
37 this.onSpliceBound_ = this.onSplice_.bind(this); | |
38 | |
26 this.initListeners_(); | 39 this.initListeners_(); |
27 this.initDom_(); | 40 this.initDom_(); |
28 } | 41 } |
29 | 42 |
30 /** | 43 /** |
31 * SlideMode extends cr.EventTarget. | 44 * SlideMode extends cr.EventTarget. |
32 */ | 45 */ |
33 SlideMode.prototype.__proto__ = cr.EventTarget.prototype; | 46 SlideMode.prototype.__proto__ = cr.EventTarget.prototype; |
34 | 47 |
35 /** | 48 /** |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 | 142 |
130 util.createChild(this.arrowBox_, 'arrow-spacer'); | 143 util.createChild(this.arrowBox_, 'arrow-spacer'); |
131 | 144 |
132 this.arrowRight_ = | 145 this.arrowRight_ = |
133 util.createChild(this.arrowBox_, 'arrow right tool dimmable'); | 146 util.createChild(this.arrowBox_, 'arrow right tool dimmable'); |
134 this.arrowRight_.addEventListener('click', | 147 this.arrowRight_.addEventListener('click', |
135 this.selectNext.bind(this, 1, null)); | 148 this.selectNext.bind(this, 1, null)); |
136 util.createChild(this.arrowRight_); | 149 util.createChild(this.arrowRight_); |
137 | 150 |
138 this.ribbonSpacer_ = util.createChild(this.toolbar_, 'ribbon-spacer'); | 151 this.ribbonSpacer_ = util.createChild(this.toolbar_, 'ribbon-spacer'); |
152 this.ribbon_ = new Ribbon(this.document_, | |
153 this.metadataCache_, this.dataModel_, this.selectionModel_); | |
154 this.ribbonSpacer_.appendChild(this.ribbon_); | |
139 | 155 |
140 // Error indicator. | 156 // Error indicator. |
141 var errorWrapper = util.createChild(this.container_, 'prompt-wrapper'); | 157 var errorWrapper = util.createChild(this.container_, 'prompt-wrapper'); |
142 errorWrapper.setAttribute('pos', 'center'); | 158 errorWrapper.setAttribute('pos', 'center'); |
143 | 159 |
144 this.errorBanner_ = util.createChild(errorWrapper, 'error-banner'); | 160 this.errorBanner_ = util.createChild(errorWrapper, 'error-banner'); |
145 | 161 |
146 util.createChild(this.container_, 'spinner'); | 162 util.createChild(this.container_, 'spinner'); |
147 | 163 |
164 this.slideShowButton_ = util.createChild(this.toolbar_, 'button slideshow'); | |
165 this.slideShowButton_.title = this.displayStringFunction_('slideshow'); | |
166 this.slideShowButton_.addEventListener('click', | |
167 this.toggleSlideshow_.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST)); | |
168 | |
169 // Editor. | |
148 | 170 |
149 this.editButton_ = util.createChild(this.toolbar_, 'button edit'); | 171 this.editButton_ = util.createChild(this.toolbar_, 'button edit'); |
150 this.editButton_.textContent = this.displayStringFunction_('edit'); | 172 this.editButton_.title = this.displayStringFunction_('edit'); |
151 this.editButton_.addEventListener('click', this.onEdit_.bind(this)); | 173 this.editButton_.addEventListener('click', this.toggleEditor_.bind(this)); |
152 | |
153 // Editor toolbar. | |
154 | 174 |
155 this.editBar_ = util.createChild(this.toolbar_, 'edit-bar'); | 175 this.editBar_ = util.createChild(this.toolbar_, 'edit-bar'); |
156 this.editBarMain_ = util.createChild(this.editBar_, 'edit-main'); | 176 this.editBarMain_ = util.createChild(this.editBar_, 'edit-main'); |
157 | 177 |
158 this.editBarMode_ = util.createChild(this.container_, 'edit-modal'); | 178 this.editBarMode_ = util.createChild(this.container_, 'edit-modal'); |
159 this.editBarModeWrapper_ = util.createChild( | 179 this.editBarModeWrapper_ = util.createChild( |
160 this.editBarMode_, 'edit-modal-wrapper'); | 180 this.editBarMode_, 'edit-modal-wrapper'); |
161 this.editBarModeWrapper_.hidden = true; | 181 this.editBarModeWrapper_.hidden = true; |
162 | 182 |
163 // Objects supporting image display and editing. | 183 // Objects supporting image display and editing. |
164 this.viewport_ = new Viewport(); | 184 this.viewport_ = new Viewport(); |
165 | 185 |
166 this.imageView_ = new ImageView( | 186 this.imageView_ = new ImageView( |
167 this.imageContainer_, | 187 this.imageContainer_, |
168 this.viewport_, | 188 this.viewport_, |
169 this.metadataCache_); | 189 this.metadataCache_); |
170 | 190 |
171 this.imageView_.addContentCallback(this.onImageContentChanged_.bind(this)); | |
172 | |
173 this.editor_ = new ImageEditor( | 191 this.editor_ = new ImageEditor( |
174 this.viewport_, | 192 this.viewport_, |
175 this.imageView_, | 193 this.imageView_, |
176 this.prompt_, | 194 this.prompt_, |
177 { | 195 { |
178 root: this.container_, | 196 root: this.container_, |
179 image: this.imageContainer_, | 197 image: this.imageContainer_, |
180 toolbar: this.editBarMain_, | 198 toolbar: this.editBarMain_, |
181 mode: this.editBarModeWrapper_ | 199 mode: this.editBarModeWrapper_ |
182 }, | 200 }, |
183 SlideMode.editorModes, | 201 SlideMode.editorModes, |
184 this.displayStringFunction_); | 202 this.displayStringFunction_); |
185 | 203 |
186 this.editor_.getBuffer().addOverlay( | 204 this.editor_.getBuffer().addOverlay( |
187 new SwipeOverlay(this.selectNext.bind(this))); | 205 new SwipeOverlay(this.selectNext.bind(this))); |
188 }; | 206 }; |
189 | 207 |
190 /** | 208 /** |
191 * Load items, display the selected item. | 209 * Load items, display the selected item. |
192 * | 210 * |
193 * @param {Array.<Gallery.Item>} items Array of items. | 211 * @param {function} opt_callback Callback. |
194 * @param {number} selectedIndex Selected index. | |
195 * @param {function} callback Callback. | |
196 */ | 212 */ |
197 SlideMode.prototype.load = function(items, selectedIndex, callback) { | 213 SlideMode.prototype.enter = function(opt_callback) { |
198 var selectedItem = items[selectedIndex]; | 214 this.container_.setAttribute('mode', 'slide'); |
199 if (!selectedItem) { | 215 |
200 this.showErrorBanner_('IMAGE_ERROR'); | 216 this.sequenceDirection_ = 0; |
201 return; | 217 this.sequenceLength_ = 0; |
202 } | |
203 | 218 |
204 var loadDone = function() { | 219 var loadDone = function() { |
205 this.items_ = items; | 220 this.active_ = true; |
206 this.setSelectedIndex_(selectedIndex); | 221 |
207 this.setupNavigation_(); | 222 this.selectionModel_.addEventListener('change', this.onSelectionBound_); |
208 setTimeout(this.requestPrefetch.bind(this, 1 /* Next item */), 1000); | 223 this.dataModel_.addEventListener('splice', this.onSpliceBound_); |
209 callback(); | 224 |
225 this.ribbon_.enable(); | |
226 | |
227 this.prefetchTimer_ = setTimeout(function() { | |
228 this.prefetchTimer_ = null; | |
229 this.requestPrefetch(1); // Prefetch the next image. | |
230 }.bind(this), 1000); | |
231 if (opt_callback) opt_callback(); | |
210 }.bind(this); | 232 }.bind(this); |
211 | 233 |
212 var selectedUrl = selectedItem.getUrl(); | 234 if (this.getItemCount_() == 0) { |
213 // Show the selected item ASAP, then complete the initialization | 235 this.displayedIndex_ = -1; |
214 // (loading the ribbon thumbnails can take some time). | 236 //TODO(kaznacheev) Show this message in the grid mode too. |
215 this.metadataCache_.get(selectedUrl, Gallery.METADATA_TYPE, | 237 this.showErrorBanner_('NO_IMAGES'); |
216 function(metadata) { | 238 loadDone(); |
217 this.loadItem_(selectedUrl, metadata, 0, loadDone); | 239 } else { |
218 }.bind(this)); | 240 // Force single selection (SlideMode is not listening to selection yet). |
241 this.select(this.getSelectedIndex() || 0); | |
dgozman
2012/08/27 13:23:42
getSelectedIndex may be undefined? In this case -1
Vladislav Kaznacheev
2012/08/27 14:49:08
Rewrote.
On 2012/08/27 13:23:42, dgozman wrote:
| |
242 cr.dispatchSimpleEvent(this, 'rename'); // Update name in the UI. | |
dgozman
2012/08/27 13:23:42
maybe rename -> namechange ?
Vladislav Kaznacheev
2012/08/27 14:49:08
Done.
| |
243 this.displayedIndex_ = this.getSelectedIndex(); | |
244 | |
245 var selectedItem = this.getSelectedItem(); | |
246 var selectedUrl = selectedItem.getUrl(); | |
247 // Show the selected item ASAP, then complete the initialization | |
248 // (loading the ribbon thumbnails can take some time). | |
249 this.metadataCache_.get(selectedUrl, Gallery.METADATA_TYPE, | |
250 function(metadata) { | |
251 this.loadItem_(selectedUrl, metadata, 0, loadDone); | |
252 }.bind(this)); | |
253 | |
254 } | |
219 }; | 255 }; |
220 | 256 |
221 /** | 257 /** |
222 * Setup navigation controls. | 258 * Leave the mode. |
259 * @param {function} opt_callback Callback. | |
260 */ | |
261 SlideMode.prototype.leave = function(opt_callback) { | |
262 if (this.prefetchTimer_) { | |
263 clearTimeout(this.prefetchTimer_); | |
264 this.prefetchTimer_ = null; | |
265 } | |
266 | |
267 var commitDone = function() { | |
268 this.stopEditing_(); | |
269 this.stopSlideshow_(); | |
270 this.unloadImage_(); | |
271 this.selectionModel_.removeEventListener( | |
272 'change', this.onSelectionBound_); | |
273 this.dataModel_.removeEventListener('splice', this.onSpliceBound_); | |
274 this.ribbon_.disable(); | |
275 this.active_ = false; | |
276 if (opt_callback) opt_callback(); | |
277 }.bind(this); | |
278 | |
279 if (this.getItemCount_() == 0) { | |
280 this.showErrorBanner_(false); | |
281 commitDone(); | |
282 } else { | |
283 this.commitItem_(commitDone); | |
284 } | |
285 }; | |
286 | |
287 /** | |
288 * @return {boolean} True if the mode has active tools (that should not fade). | |
289 */ | |
290 SlideMode.prototype.hasActiveTool = function() { | |
291 return this.isEditing(); | |
292 }; | |
293 | |
294 /** | |
295 * @return {number} Item count. | |
223 * @private | 296 * @private |
224 */ | 297 */ |
225 SlideMode.prototype.setupNavigation_ = function() { | 298 SlideMode.prototype.getItemCount_ = function() { |
226 this.sequenceDirection_ = 0; | 299 return this.dataModel_.length; |
227 this.sequenceLength_ = 0; | 300 }; |
228 | 301 |
229 ImageUtil.setAttribute(this.arrowLeft_, 'active', this.items_.length > 1); | 302 /** |
230 ImageUtil.setAttribute(this.arrowRight_, 'active', this.items_.length > 1); | 303 * @param {number} index Index. |
304 * @return {Gallery.Item} Item. | |
305 */ | |
306 SlideMode.prototype.getItem = function(index) { | |
307 return this.dataModel_.item(index); | |
308 }; | |
231 | 309 |
232 this.ribbon_ = new Ribbon( | 310 /** |
233 this.document_, this.metadataCache_, this.select.bind(this)); | 311 * @return {Gallery.Item} Selected index. |
234 this.ribbonSpacer_.appendChild(this.ribbon_); | 312 */ |
235 this.ribbon_.update(this.items_, this.selectedIndex_); | 313 SlideMode.prototype.getSelectedIndex = function() { |
314 // return this.selectedIndex_; | |
dgozman
2012/08/27 13:23:42
Commented code.
Vladislav Kaznacheev
2012/08/27 14:49:08
Done.
| |
315 return this.selectionModel_.selectedIndexes[0]; | |
236 }; | 316 }; |
237 | 317 |
238 /** | 318 /** |
239 * @return {Gallery.Item} Selected item | 319 * @return {Gallery.Item} Selected item |
240 */ | 320 */ |
241 SlideMode.prototype.getSelectedItem = function() { | 321 SlideMode.prototype.getSelectedItem = function() { |
242 return this.items_ && this.items_[this.selectedIndex_]; | 322 return this.getItem(this.getSelectedIndex()); |
323 }; | |
324 | |
325 /** | |
326 * Selection change handler. | |
327 * | |
328 * Commits the current image and displays the newly selected image. | |
329 * @private | |
330 */ | |
331 SlideMode.prototype.onSelection_ = function() { | |
332 if (this.selectionModel_.selectedIndexes.length == 0) | |
333 return; // Temporary empty selection. | |
334 | |
335 if (this.getSelectedIndex() == this.displayedIndex_) | |
336 return; // Do not reselect. | |
337 | |
338 this.commitItem_(this.loadSelectedItem_.bind(this)); | |
243 }; | 339 }; |
244 | 340 |
245 /** | 341 /** |
246 * Change the selection. | 342 * Change the selection. |
247 * | 343 * |
248 * Commits the current image and changes the selection. | |
249 * | |
250 * @param {number} index New selected index. | 344 * @param {number} index New selected index. |
251 * @param {number} opt_slideDir Slide animation direction (-1|0|1). | 345 * @param {number} opt_slideHint Slide animation direction (-1|1). |
252 * Derived from the new and the old selected indices if omitted. | |
253 * @param {function} opt_callback Callback. | |
254 */ | 346 */ |
255 SlideMode.prototype.select = function(index, opt_slideDir, opt_callback) { | 347 SlideMode.prototype.select = function(index, opt_slideHint) { |
256 if (!this.items_) | 348 this.slideHint_ = opt_slideHint; |
257 return; // Not fully initialized, still loading the first image. | 349 this.selectionModel_.unselectAll(); |
258 | 350 this.selectionModel_.setIndexSelected(index, true); |
259 if (index == this.selectedIndex_) | |
260 return; // Do not reselect. | |
261 | |
262 this.commitItem_( | |
263 this.doSelect_.bind(this, index, opt_slideDir, opt_callback)); | |
264 }; | 351 }; |
265 | 352 |
266 /** | 353 /** |
267 * Set the new selected index value. | 354 * Load the selected item. |
268 * @param {number} index New selected index. | 355 * |
269 * @private | 356 * @private |
270 */ | 357 */ |
271 SlideMode.prototype.setSelectedIndex_ = function(index) { | 358 SlideMode.prototype.loadSelectedItem_ = function() { |
272 this.selectedIndex_ = index; | 359 var slideHint = this.slideHint_; |
273 cr.dispatchSimpleEvent(this, 'selection'); | 360 this.slideHint_ = undefined; |
dgozman
2012/08/27 13:23:42
null
Vladislav Kaznacheev
2012/08/27 14:49:08
I can do that but this field can be set to undefi
| |
274 | 361 |
275 // For once edited image, disallow the 'overwrite' setting change. | 362 var index = this.getSelectedIndex(); |
276 ImageUtil.setAttribute(this.options_, 'saved', | 363 if (index == this.displayedIndex_) |
277 !this.getSelectedItem().isOriginal()); | 364 return; // Do not reselect. |
278 }; | |
279 | 365 |
280 /** | 366 var step = slideHint || (index - this.displayedIndex_); |
281 * Perform the actual selection change. | |
282 * | |
283 * @param {number} index New selected index. | |
284 * @param {number} opt_slideDir Slide animation direction (-1|0|1). | |
285 * Derived from the new and the old selected indices if omitted. | |
286 * @param {function} opt_callback Callback. | |
287 * @private | |
288 */ | |
289 SlideMode.prototype.doSelect_ = function(index, opt_slideDir, opt_callback) { | |
290 if (index == this.selectedIndex_) | |
291 return; // Do not reselect | |
292 | |
293 var step = opt_slideDir != undefined ? | |
294 opt_slideDir : | |
295 (index - this.selectedIndex_); | |
296 | 367 |
297 if (Math.abs(step) != 1) { | 368 if (Math.abs(step) != 1) { |
298 // Long leap, the sequence is broken, we have no good prefetch candidate. | 369 // Long leap, the sequence is broken, we have no good prefetch candidate. |
299 this.sequenceDirection_ = 0; | 370 this.sequenceDirection_ = 0; |
300 this.sequenceLength_ = 0; | 371 this.sequenceLength_ = 0; |
301 } else if (this.sequenceDirection_ == step) { | 372 } else if (this.sequenceDirection_ == step) { |
302 // Keeping going in sequence. | 373 // Keeping going in sequence. |
303 this.sequenceLength_++; | 374 this.sequenceLength_++; |
304 } else { | 375 } else { |
305 // Reversed the direction. Reset the counter. | 376 // Reversed the direction. Reset the counter. |
306 this.sequenceDirection_ = step; | 377 this.sequenceDirection_ = step; |
307 this.sequenceLength_ = 1; | 378 this.sequenceLength_ = 1; |
308 } | 379 } |
309 | 380 |
310 if (this.sequenceLength_ <= 1) { | 381 if (this.sequenceLength_ <= 1) { |
311 // We have just broke the sequence. Touch the current image so that it stays | 382 // We have just broke the sequence. Touch the current image so that it stays |
312 // in the cache longer. | 383 // in the cache longer. |
313 this.editor_.prefetchImage(this.getSelectedItem().getUrl()); | 384 this.imageView_.prefetch(this.imageView_.contentID_); |
314 } | 385 } |
315 | 386 |
316 this.setSelectedIndex_(index); | 387 this.displayedIndex_ = index; |
317 | |
318 if (this.ribbon_) | |
319 this.ribbon_.update(this.items_, this.selectedIndex_); | |
320 | 388 |
321 function shouldPrefetch(loadType, step, sequenceLength) { | 389 function shouldPrefetch(loadType, step, sequenceLength) { |
322 // Never prefetch when selecting out of sequence. | 390 // Never prefetch when selecting out of sequence. |
323 if (Math.abs(step) != 1) | 391 if (Math.abs(step) != 1) |
324 return false; | 392 return false; |
325 | 393 |
326 // Never prefetch after a video load (decoding the next image can freeze | 394 // Never prefetch after a video load (decoding the next image can freeze |
327 // the UI for a second or two). | 395 // the UI for a second or two). |
328 if (loadType == ImageView.LOAD_TYPE_VIDEO_FILE) | 396 if (loadType == ImageView.LOAD_TYPE_VIDEO_FILE) |
329 return false; | 397 return false; |
330 | 398 |
331 // Always prefetch if the previous load was from cache. | 399 // Always prefetch if the previous load was from cache. |
332 if (loadType == ImageView.LOAD_TYPE_CACHED_FULL) | 400 if (loadType == ImageView.LOAD_TYPE_CACHED_FULL) |
333 return true; | 401 return true; |
334 | 402 |
335 // Prefetch if we have been going in the same direction for long enough. | 403 // Prefetch if we have been going in the same direction for long enough. |
336 return sequenceLength >= 3; | 404 return sequenceLength >= 3; |
337 } | 405 } |
338 | 406 |
339 var selectedItem = this.getSelectedItem(); | 407 var selectedItem = this.getSelectedItem(); |
340 var onMetadata = function(metadata) { | 408 var onMetadata = function(metadata) { |
341 if (selectedItem != this.getSelectedItem()) return; | 409 if (selectedItem != this.getSelectedItem()) return; |
342 this.loadItem_(selectedItem.getUrl(), metadata, step, | 410 this.loadItem_(selectedItem.getUrl(), metadata, step, |
343 function(loadType) { | 411 function(loadType) { |
344 if (selectedItem != this.getSelectedItem()) return; | 412 if (selectedItem != this.getSelectedItem()) return; |
345 if (shouldPrefetch(loadType, step, this.sequenceLength_)) { | 413 if (shouldPrefetch(loadType, step, this.sequenceLength_)) { |
346 this.requestPrefetch(step); | 414 this.requestPrefetch(step); |
347 } | 415 } |
348 if (opt_callback) opt_callback(); | 416 if (this.isSlideshowOn_()) |
417 this.scheduleNextSlide_(); | |
349 }.bind(this)); | 418 }.bind(this)); |
350 }.bind(this); | 419 }.bind(this); |
351 this.metadataCache_.get( | 420 this.metadataCache_.get( |
352 selectedItem.getUrl(), Gallery.METADATA_TYPE, onMetadata); | 421 selectedItem.getUrl(), Gallery.METADATA_TYPE, onMetadata); |
353 }; | 422 }; |
354 | 423 |
355 /** | 424 /** |
425 * Unload the current image. | |
426 * @private | |
427 */ | |
428 SlideMode.prototype.unloadImage_ = function() { | |
429 this.imageView_.unload(); | |
430 this.container_.removeAttribute('video'); | |
431 }; | |
432 | |
433 /** | |
434 * Data model 'splice' event handler. | |
435 * @param {Event} event Event. | |
436 * @private | |
437 */ | |
438 SlideMode.prototype.onSplice_ = function(event) { | |
439 ImageUtil.setAttribute(this.arrowLeft_, 'active', this.getItemCount_() > 1); | |
440 ImageUtil.setAttribute(this.arrowRight_, 'active', this.getItemCount_() > 1); | |
441 | |
442 if (event.removed.length != 1) | |
443 return; | |
444 | |
445 // Delay the selection to let the ribbon splice handler work first. | |
446 setTimeout(function() { | |
447 if (event.index < this.dataModel_.length) { | |
448 // There is the next item, select it. | |
449 // The next item is not at the same index as the removed one, so we need | |
dgozman
2012/08/27 13:23:42
How is this? If we remove currently displayed 3rd
Vladislav Kaznacheev
2012/08/27 14:49:08
not -> now
On 2012/08/27 13:23:42, dgozman wrote:
| |
450 // to correct displayIndex_. | |
451 this.displayedIndex_ = event.index - 1; | |
452 this.select(event.index); | |
453 } else if (this.dataModel_.length) { | |
454 // Removed item is the rightmost, but there are more items. | |
455 this.select(event.index - 1); // Select the new last index. | |
456 } else { | |
457 // No items left. Unload the image and show the banner. | |
458 this.commitItem_(function() { | |
459 this.unloadImage_(); | |
460 this.showErrorBanner_('NO_IMAGES'); | |
461 }.bind(this)); | |
462 } | |
463 }.bind(this), 0); | |
464 }; | |
465 | |
466 /** | |
356 * @param {number} direction -1 for left, 1 for right. | 467 * @param {number} direction -1 for left, 1 for right. |
357 * @return {number} Next index in the gived direction, with wrapping. | 468 * @return {number} Next index in the gived direction, with wrapping. |
358 * @private | 469 * @private |
359 */ | 470 */ |
360 SlideMode.prototype.getNextSelectedIndex_ = function(direction) { | 471 SlideMode.prototype.getNextSelectedIndex_ = function(direction) { |
361 var index = this.selectedIndex_ + (direction > 0 ? 1 : -1); | 472 var index = this.getSelectedIndex() + (direction > 0 ? 1 : -1); |
362 if (index == -1) return this.items_.length - 1; | 473 if (index == -1) return this.getItemCount_() - 1; |
363 if (index == this.items_.length) return 0; | 474 if (index == this.getItemCount_()) return 0; |
364 return index; | 475 return index; |
365 }; | 476 }; |
366 | 477 |
367 /** | 478 /** |
368 * Select the next item. | 479 * Select the next item. |
369 * @param {number} direction -1 for left, 1 for right. | 480 * @param {number} direction -1 for left, 1 for right. |
370 * @param {function} opt_callback Callback. | |
371 */ | 481 */ |
372 SlideMode.prototype.selectNext = function(direction, opt_callback) { | 482 SlideMode.prototype.selectNext = function(direction) { |
373 this.select(this.getNextSelectedIndex_(direction), direction, opt_callback); | 483 this.select(this.getNextSelectedIndex_(direction), direction); |
374 }; | 484 }; |
375 | 485 |
376 /** | 486 /** |
377 * Select the first item. | 487 * Select the first item. |
378 */ | 488 */ |
379 SlideMode.prototype.selectFirst = function() { | 489 SlideMode.prototype.selectFirst = function() { |
380 this.select(0); | 490 this.select(0); |
381 }; | 491 }; |
382 | 492 |
383 /** | 493 /** |
384 * Select the last item. | 494 * Select the last item. |
385 */ | 495 */ |
386 SlideMode.prototype.selectLast = function() { | 496 SlideMode.prototype.selectLast = function() { |
387 this.select(this.items_.length - 1); | 497 this.select(this.getItemCount_() - 1); |
388 }; | 498 }; |
389 | 499 |
390 // Loading/unloading | 500 // Loading/unloading |
391 | 501 |
392 /** | 502 /** |
393 * Load and display an item. | 503 * Load and display an item. |
394 * | 504 * |
395 * @param {string} url Item url. | 505 * @param {string} url Item url. |
396 * @param {Object} metadata Item metadata. | 506 * @param {Object} metadata Item metadata. |
397 * @param {number} slide Slide animation direction (-1|0|1). | 507 * @param {number} slide Slide animation direction (-1|0|1). |
(...skipping 10 matching lines...) Expand all Loading... | |
408 ImageUtil.setAttribute(this.container_, 'video', video); | 518 ImageUtil.setAttribute(this.container_, 'video', video); |
409 | 519 |
410 this.showSpinner_(false); | 520 this.showSpinner_(false); |
411 if (loadType == ImageView.LOAD_TYPE_ERROR) { | 521 if (loadType == ImageView.LOAD_TYPE_ERROR) { |
412 this.showErrorBanner_(video ? 'VIDEO_ERROR' : 'IMAGE_ERROR'); | 522 this.showErrorBanner_(video ? 'VIDEO_ERROR' : 'IMAGE_ERROR'); |
413 } else if (loadType == ImageView.LOAD_TYPE_OFFLINE) { | 523 } else if (loadType == ImageView.LOAD_TYPE_OFFLINE) { |
414 this.showErrorBanner_(video ? 'VIDEO_OFFLINE' : 'IMAGE_OFFLINE'); | 524 this.showErrorBanner_(video ? 'VIDEO_OFFLINE' : 'IMAGE_OFFLINE'); |
415 } | 525 } |
416 | 526 |
417 if (video) { | 527 if (video) { |
418 if (this.isEditing()) { | 528 // The editor toolbar does not make sense for video, hide it. |
419 // The editor toolbar does not make sense for video, hide it. | 529 this.stopEditing_(); |
420 this.onEdit_(); | |
421 } | |
422 this.mediaControls_.attachMedia(this.imageView_.getVideo()); | 530 this.mediaControls_.attachMedia(this.imageView_.getVideo()); |
423 //TODO(kaznacheev): Add metrics for video playback. | 531 //TODO(kaznacheev): Add metrics for video playback. |
424 } else { | 532 } else { |
425 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View')); | 533 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View')); |
426 | 534 |
427 function toMillions(number) { return Math.round(number / (1000 * 1000)) } | 535 function toMillions(number) { return Math.round(number / (1000 * 1000)) } |
428 | 536 |
429 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'), | 537 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'), |
430 toMillions(metadata.filesystem.size)); | 538 toMillions(metadata.filesystem.size)); |
431 | 539 |
432 var canvas = this.imageView_.getCanvas(); | 540 var canvas = this.imageView_.getCanvas(); |
433 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'), | 541 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'), |
434 toMillions(canvas.width * canvas.height)); | 542 toMillions(canvas.width * canvas.height)); |
435 | 543 |
436 var extIndex = url.lastIndexOf('.'); | 544 var extIndex = url.lastIndexOf('.'); |
437 var ext = extIndex < 0 ? '' : url.substr(extIndex + 1).toLowerCase(); | 545 var ext = extIndex < 0 ? '' : url.substr(extIndex + 1).toLowerCase(); |
438 if (ext == 'jpeg') ext = 'jpg'; | 546 if (ext == 'jpeg') ext = 'jpg'; |
439 ImageUtil.metrics.recordEnum( | 547 ImageUtil.metrics.recordEnum( |
440 ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES); | 548 ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES); |
441 } | 549 } |
442 | 550 |
551 // For once edited image, disallow the 'overwrite' setting change. | |
552 ImageUtil.setAttribute(this.options_, 'saved', | |
553 !this.getSelectedItem().isOriginal()); | |
554 | |
555 var times = SlideMode.OVERWRITE_BUBBLE_KEY in localStorage ? | |
556 parseInt(localStorage[SlideMode.OVERWRITE_BUBBLE_KEY], 10) : 0; | |
557 if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) { | |
558 this.bubble_.hidden = false; | |
559 if (this.isEditing()) { | |
560 localStorage[SlideMode.OVERWRITE_BUBBLE_KEY] = times + 1; | |
561 } | |
562 } | |
563 | |
443 callback(loadType); | 564 callback(loadType); |
444 }.bind(this); | 565 }.bind(this); |
445 | 566 |
446 this.editor_.openSession( | 567 this.editor_.openSession( |
447 url, metadata, slide, this.saveCurrentImage_.bind(this), loadDone); | 568 url, metadata, slide, this.saveCurrentImage_.bind(this), loadDone); |
448 }; | 569 }; |
449 | 570 |
450 /** | 571 /** |
451 * Commit changes to the current item and reset all messages/indicators. | 572 * Commit changes to the current item and reset all messages/indicators. |
452 * | 573 * |
(...skipping 10 matching lines...) Expand all Loading... | |
463 } | 584 } |
464 this.editor_.closeSession(callback); | 585 this.editor_.closeSession(callback); |
465 }; | 586 }; |
466 | 587 |
467 /** | 588 /** |
468 * Request a prefetch for the next image. | 589 * Request a prefetch for the next image. |
469 * | 590 * |
470 * @param {number} direction -1 or 1. | 591 * @param {number} direction -1 or 1. |
471 */ | 592 */ |
472 SlideMode.prototype.requestPrefetch = function(direction) { | 593 SlideMode.prototype.requestPrefetch = function(direction) { |
473 if (this.items_.length <= 1) return; | 594 if (this.getItemCount_() <= 1) return; |
474 | 595 |
475 var index = this.getNextSelectedIndex_(direction); | 596 var index = this.getNextSelectedIndex_(direction); |
476 var nextItemUrl = this.items_[index].getUrl(); | 597 var nextItemUrl = this.getItem(index).getUrl(); |
477 | 598 |
478 var selectedItem = this.getSelectedItem(); | 599 var selectedItem = this.getSelectedItem(); |
479 this.metadataCache_.get(nextItemUrl, Gallery.METADATA_TYPE, | 600 this.metadataCache_.get(nextItemUrl, Gallery.METADATA_TYPE, |
480 function(metadata) { | 601 function(metadata) { |
481 if (selectedItem != this.getSelectedItem()) return; | 602 if (selectedItem != this.getSelectedItem()) return; |
482 this.editor_.prefetchImage(nextItemUrl); | 603 this.editor_.prefetchImage(nextItemUrl); |
483 }.bind(this)); | 604 }.bind(this)); |
484 }; | 605 }; |
485 | 606 |
486 // Event handlers. | 607 // Event handlers. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
534 return true; | 655 return true; |
535 | 656 |
536 switch (util.getKeyModifiers(event) + event.keyIdentifier) { | 657 switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
537 case 'U+0020': // Space toggles the video playback. | 658 case 'U+0020': // Space toggles the video playback. |
538 if (this.isShowingVideo_()) { | 659 if (this.isShowingVideo_()) { |
539 this.mediaControls_.togglePlayStateWithFeedback(); | 660 this.mediaControls_.togglePlayStateWithFeedback(); |
540 } | 661 } |
541 break; | 662 break; |
542 | 663 |
543 case 'U+0045': // 'e' toggles the editor | 664 case 'U+0045': // 'e' toggles the editor |
544 this.onEdit_(); | 665 this.toggleEditor_(); |
545 break; | 666 break; |
546 | 667 |
547 case 'U+001B': // Escape | 668 case 'U+001B': // Escape |
548 if (!this.isEditing()) | 669 if (!this.isEditing()) |
549 return false; // Not handled. | 670 return false; // Not handled. |
550 this.onEdit_(); | 671 this.toggleEditor_(); |
551 break; | 672 break; |
552 | 673 |
553 case 'Ctrl-U+00DD': // Ctrl+] (cryptic on purpose). | 674 case 'Ctrl-U+00DD': // Ctrl+]. TODO(kaznacheev): Find a non-cryptic key. |
554 this.toggleSlideshow_(); | 675 this.toggleSlideshow_(SlideMode.SLIDESHOW_INTERVAL_FIRST); |
555 break; | 676 break; |
556 | 677 |
557 case 'Home': | 678 case 'Home': |
558 this.selectFirst(); | 679 this.selectFirst(); |
559 break; | 680 break; |
560 case 'End': | 681 case 'End': |
561 this.selectLast(); | 682 this.selectLast(); |
562 break; | 683 break; |
563 case 'Left': | 684 case 'Left': |
564 this.selectNext(-1); | 685 this.selectNext(-1); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
607 this.shouldOverwriteOriginal_(), | 728 this.shouldOverwriteOriginal_(), |
608 canvas, | 729 canvas, |
609 metadataEncoder, | 730 metadataEncoder, |
610 function(success) { | 731 function(success) { |
611 // TODO(kaznacheev): Implement write error handling. | 732 // TODO(kaznacheev): Implement write error handling. |
612 // Until then pretend that the save succeeded. | 733 // Until then pretend that the save succeeded. |
613 this.showSpinner_(false); | 734 this.showSpinner_(false); |
614 this.flashSavedLabel_(); | 735 this.flashSavedLabel_(); |
615 var newUrl = item.getUrl(); | 736 var newUrl = item.getUrl(); |
616 this.updateSelectedUrl_(oldUrl, newUrl); | 737 this.updateSelectedUrl_(oldUrl, newUrl); |
617 this.ribbon_.updateThumbnail( | 738 this.ribbon_.updateThumbnail(newUrl, this.selectedImageMetadata_); |
618 this.selectedIndex_, newUrl, this.selectedImageMetadata_); | 739 cr.dispatchSimpleEvent(this, 'content'); |
740 | |
741 if (this.imageView_.getContentRevision() == 1) { // First edit. | |
742 // Lock the 'Overwrite original' checkbox for this item. | |
743 ImageUtil.setAttribute(this.options_, 'saved', true); | |
744 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit')); | |
745 } | |
746 | |
747 if (oldUrl != newUrl) { | |
748 this.displayedIndex_++; | |
749 // This splice call will change the selection change event. SlideMode | |
750 // will ignore it as the selected item is the same. | |
751 // The ribbon will redraw while being obscured by the Editor toolbar, | |
752 // so there is no need for nice animation here. | |
753 this.dataModel_.splice( | |
754 this.getSelectedIndex(), 0, new Gallery.Item(oldUrl)); | |
755 } | |
619 callback(); | 756 callback(); |
620 }.bind(this)); | 757 }.bind(this)); |
621 }; | 758 }; |
622 | 759 |
623 /** | 760 /** |
624 * Update caches when the selected item url has changed. | 761 * Update caches when the selected item url has changed. |
625 * | 762 * |
626 * @param {string} oldUrl Old url. | 763 * @param {string} oldUrl Old url. |
627 * @param {string} newUrl New url. | 764 * @param {string} newUrl New url. |
628 * @private | 765 * @private |
629 */ | 766 */ |
630 SlideMode.prototype.updateSelectedUrl_ = function(oldUrl, newUrl) { | 767 SlideMode.prototype.updateSelectedUrl_ = function(oldUrl, newUrl) { |
631 this.metadataCache_.clear(oldUrl, Gallery.METADATA_TYPE); | 768 this.metadataCache_.clear(oldUrl, Gallery.METADATA_TYPE); |
632 | 769 |
633 if (oldUrl == newUrl) | 770 if (oldUrl == newUrl) |
634 return; | 771 return; |
635 | 772 |
636 this.imageView_.changeUrl(newUrl); | 773 this.imageView_.changeUrl(newUrl); |
637 this.ribbon_.remapCache(oldUrl, newUrl); | 774 this.ribbon_.remapCache(oldUrl, newUrl); |
638 | |
639 // Let the gallery know that the selected item url has changed. | |
640 cr.dispatchSimpleEvent(this, 'selection'); | |
641 }; | 775 }; |
642 | 776 |
643 /** | 777 /** |
644 * Flash 'Saved' label briefly to indicate that the image has been saved. | 778 * Flash 'Saved' label briefly to indicate that the image has been saved. |
645 * @private | 779 * @private |
646 */ | 780 */ |
647 SlideMode.prototype.flashSavedLabel_ = function() { | 781 SlideMode.prototype.flashSavedLabel_ = function() { |
648 var setLabelHighlighted = | 782 var setLabelHighlighted = |
649 ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted'); | 783 ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted'); |
650 setTimeout(setLabelHighlighted.bind(null, true), 0); | 784 setTimeout(setLabelHighlighted.bind(null, true), 0); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
691 /** | 825 /** |
692 * Overwrite info bubble close handler. | 826 * Overwrite info bubble close handler. |
693 * @private | 827 * @private |
694 */ | 828 */ |
695 SlideMode.prototype.onCloseBubble_ = function() { | 829 SlideMode.prototype.onCloseBubble_ = function() { |
696 this.bubble_.hidden = true; | 830 this.bubble_.hidden = true; |
697 localStorage[SlideMode.OVERWRITE_BUBBLE_KEY] = | 831 localStorage[SlideMode.OVERWRITE_BUBBLE_KEY] = |
698 SlideMode.OVERWRITE_BUBBLE_MAX_TIMES; | 832 SlideMode.OVERWRITE_BUBBLE_MAX_TIMES; |
699 }; | 833 }; |
700 | 834 |
835 // Slideshow | |
836 | |
701 /** | 837 /** |
702 * Callback called when the image is edited. | 838 * Slideshow interval in ms. |
839 */ | |
840 SlideMode.SLIDESHOW_INTERVAL = 5000; | |
841 | |
842 /** | |
843 * First slideshow interval in ms. It should be shorter so that the user | |
844 * is not guessing whether the button worked. | |
845 */ | |
846 SlideMode.SLIDESHOW_INTERVAL_FIRST = 1000; | |
847 | |
848 /** | |
849 * @return {boolean} True if the slideshow is on. | |
703 * @private | 850 * @private |
704 */ | 851 */ |
705 SlideMode.prototype.onImageContentChanged_ = function() { | 852 SlideMode.prototype.isSlideshowOn_ = function() { |
706 var revision = this.imageView_.getContentRevision(); | 853 return this.container_.hasAttribute('slideshow'); |
707 if (revision == 0) { | 854 }; |
708 // Just loaded. | 855 |
709 var times = SlideMode.OVERWRITE_BUBBLE_KEY in localStorage ? | 856 /** |
710 parseInt(localStorage[SlideMode.OVERWRITE_BUBBLE_KEY], 10) : 0; | 857 * Stop the slideshow if it is on. |
711 if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) { | 858 * @private |
712 this.bubble_.hidden = false; | 859 */ |
713 if (this.isEditing()) { | 860 SlideMode.prototype.stopSlideshow_ = function() { |
714 localStorage[SlideMode.OVERWRITE_BUBBLE_KEY] = times + 1; | 861 if (this.isSlideshowOn_()) |
715 } | 862 this.toggleSlideshow_(); |
716 } | 863 }; |
864 | |
865 /** | |
866 * Start/stop the slideshow. | |
867 * | |
868 * @param {number} opt_interval First interval in ms. | |
869 * @param {Event} opt_event Event. | |
870 * @private | |
871 */ | |
872 | |
873 SlideMode.prototype.toggleSlideshow_ = function(opt_interval, opt_event) { | |
874 if (opt_event) // Caused by user action. | |
875 cr.dispatchSimpleEvent(this, 'button'); | |
876 | |
877 if (!this.active_) { | |
878 // Enter the slide mode. Show the first image for the full interval. | |
879 this.enter(this.toggleSlideshow_.bind(this, SlideMode.SLIDESHOW_INTERVAL)); | |
880 return; | |
717 } | 881 } |
718 | 882 |
719 if (revision == 1) { | 883 this.stopEditing_(); |
720 // First edit. | 884 ImageUtil.setAttribute(this.container_, 'slideshow', !this.isSlideshowOn_()); |
721 ImageUtil.setAttribute(this.options_, 'saved', true); | 885 ImageUtil.setAttribute( |
722 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit')); | 886 this.slideShowButton_, 'pressed', this.isSlideshowOn_()); |
887 | |
888 if (this.isSlideshowOn_()) { | |
889 this.scheduleNextSlide_(opt_interval); | |
890 } else { | |
891 if (this.slideShowTimeout_) { | |
892 clearInterval(this.slideShowTimeout_); | |
893 this.slideShowTimeout_ = null; | |
894 } | |
723 } | 895 } |
724 }; | 896 }; |
725 | 897 |
726 // Misc | |
727 | |
728 /** | 898 /** |
729 * Start/stop the slide show. | 899 * @param {number} opt_interval Slideshow interval in ms. |
730 * @private | 900 * @private |
731 */ | 901 */ |
732 SlideMode.prototype.toggleSlideshow_ = function() { | 902 SlideMode.prototype.scheduleNextSlide_ = function(opt_interval) { |
733 if (this.slideShowTimeout_) { | 903 if (this.slideShowTimeout_) |
734 clearInterval(this.slideShowTimeout_); | 904 clearTimeout(this.slideShowTimeout_); |
735 this.slideShowTimeout_ = null; | 905 |
736 } else { | 906 this.slideShowTimeout_ = setTimeout(function() { |
737 var self = this; | 907 this.slideShowTimeout_ = null; |
738 function nextSlide() { | 908 this.selectNext(1); |
739 self.selectNext(1, | 909 }.bind(this), |
740 function() { self.slideShowTimeout_ = setTimeout(nextSlide, 5000) }); | 910 opt_interval || SlideMode.SLIDESHOW_INTERVAL); |
741 } | |
742 nextSlide(); | |
743 } | |
744 }; | 911 }; |
745 | 912 |
746 /** | 913 /** |
747 * @return {boolean} True if the editor is active. | 914 * @return {boolean} True if the editor is active. |
748 */ | 915 */ |
749 SlideMode.prototype.isEditing = function() { | 916 SlideMode.prototype.isEditing = function() { |
750 return this.container_.hasAttribute('editing'); | 917 return this.container_.hasAttribute('editing'); |
751 }; | 918 }; |
752 | 919 |
753 /** | 920 /** |
921 * Stop editing. | |
922 * @private | |
923 */ | |
924 SlideMode.prototype.stopEditing_ = function() { | |
925 if (this.isEditing()) | |
926 this.toggleEditor_(); | |
927 }; | |
928 | |
929 /** | |
754 * Activate/deactivate editor. | 930 * Activate/deactivate editor. |
931 * @param {Event} opt_event Event. | |
755 * @private | 932 * @private |
756 */ | 933 */ |
757 SlideMode.prototype.onEdit_ = function() { | 934 SlideMode.prototype.toggleEditor_ = function(opt_event) { |
935 if (opt_event) // Caused by user action. | |
936 cr.dispatchSimpleEvent(this, 'button'); | |
dgozman
2012/08/27 13:23:42
'button' ?
Vladislav Kaznacheev
2012/08/27 14:49:08
renamed to 'useraction', expanded the comment
On 2
| |
937 | |
938 if (!this.active_) { | |
939 this.enter(this.toggleEditor_.bind(this)); | |
940 return; | |
941 } | |
942 | |
943 this.stopSlideshow_(); | |
758 if (!this.isEditing() && this.isShowingVideo_()) | 944 if (!this.isEditing() && this.isShowingVideo_()) |
759 return; // No editing for videos. | 945 return; // No editing for videos. |
760 | 946 |
761 ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing()); | 947 ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing()); |
762 | 948 |
763 if (this.isEditing()) { // isEditing_ has just been flipped to a new value. | 949 if (this.isEditing()) { // isEditing_ has just been flipped to a new value. |
764 if (this.context_.readonlyDirName) { | 950 if (this.context_.readonlyDirName) { |
765 this.editor_.getPrompt().showAt( | 951 this.editor_.getPrompt().showAt( |
766 'top', 'readonly_warning', 0, this.context_.readonlyDirName); | 952 'top', 'readonly_warning', 0, this.context_.readonlyDirName); |
767 } | 953 } |
768 } else { | 954 } else { |
769 this.editor_.getPrompt().hide(); | 955 this.editor_.getPrompt().hide(); |
770 } | 956 } |
771 | 957 |
772 ImageUtil.setAttribute(this.editButton_, 'pressed', this.isEditing()); | 958 ImageUtil.setAttribute(this.editButton_, 'pressed', this.isEditing()); |
773 | |
774 cr.dispatchSimpleEvent(this, 'edit'); | |
775 }; | 959 }; |
776 | 960 |
777 /** | 961 /** |
778 * Display the error banner. | 962 * Display the error banner. |
779 * @param {string} message Message. | 963 * @param {string} message Message. |
780 * @private | 964 * @private |
781 */ | 965 */ |
782 SlideMode.prototype.showErrorBanner_ = function(message) { | 966 SlideMode.prototype.showErrorBanner_ = function(message) { |
783 if (message) { | 967 if (message) { |
784 this.errorBanner_.textContent = this.displayStringFunction_(message); | 968 this.errorBanner_.textContent = this.displayStringFunction_(message); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
862 done = true; | 1046 done = true; |
863 } | 1047 } |
864 }.bind(this); | 1048 }.bind(this); |
865 }; | 1049 }; |
866 | 1050 |
867 /** | 1051 /** |
868 * If the user touched the image and moved the finger more than SWIPE_THRESHOLD | 1052 * If the user touched the image and moved the finger more than SWIPE_THRESHOLD |
869 * horizontally it's considered as a swipe gesture (change the current image). | 1053 * horizontally it's considered as a swipe gesture (change the current image). |
870 */ | 1054 */ |
871 SwipeOverlay.SWIPE_THRESHOLD = 100; | 1055 SwipeOverlay.SWIPE_THRESHOLD = 100; |
OLD | NEW |