15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict';
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Slide mode displays a single image and has a set of controls to navigate
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * between the images and to edit an image.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} container Main container element.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} content Content container element.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} toolbar Toolbar element.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {ImageEditor.Prompt} prompt Prompt.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {cr.ui.ArrayDataModel} dataModel Data model.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} context Context.
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {VolumeManager} volumeManager Volume manager.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(function())} toggleMode Function to toggle the Gallery mode.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function(string):string} displayStringFunction String formatting
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     function.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction SlideMode(container, content, toolbar, prompt, dataModel,
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    selectionModel, context, volumeManager, toggleMode, displayStringFunction) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_ = container;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.document_ = container.ownerDocument;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.content = content;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.toolbar_ = toolbar;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.prompt_ = prompt;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.dataModel_ = dataModel;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.selectionModel_ = selectionModel;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.context_ = context;
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  this.volumeManager_ = volumeManager;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.metadataCache_ = context.metadataCache;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.toggleMode_ = toggleMode;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.displayStringFunction_ = displayStringFunction;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.onSelectionBound_ = this.onSelection_.bind(this);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.onSpliceBound_ = this.onSplice_.bind(this);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Unique numeric key, incremented per each load attempt used to discard
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // old attempts. This can happen especially when changing selection fast or
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Internet connection is slow.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.currentUniqueKey_ = 0;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.initListeners_();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.initDom_();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * List of available editor modes.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {Array.<ImageEditor.Mode>}
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @const
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
56116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSlideMode.EDITOR_MODES = Object.freeze([
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new ImageEditor.Mode.InstantAutofix(),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new ImageEditor.Mode.Crop(),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new ImageEditor.Mode.Exposure(),
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  new ImageEditor.Mode.OneClick(
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      'rotate_left', 'GALLERY_ROTATE_LEFT', new Command.Rotate(-1)),
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  new ImageEditor.Mode.OneClick(
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      'rotate_right', 'GALLERY_ROTATE_RIGHT', new Command.Rotate(1))
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch]);
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/**
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * Map of the key identifier and offset delta.
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @type {Object.<string, Array.<number>})
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @const
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */
71116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSlideMode.KEY_OFFSET_MAP = Object.freeze({
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  'Up': Object.freeze([0, 20]),
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  'Down': Object.freeze([0, -20]),
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  'Left': Object.freeze([20, 0]),
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  'Right': Object.freeze([-20, 0])
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch});
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/**
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * SlideMode extends cr.EventTarget.
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */
81116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSlideMode.prototype.__proto__ = cr.EventTarget.prototype;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string} Mode name.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
86116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSlideMode.prototype.getName = function() { return 'slide'; };
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @return {string} Mode title.
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
91116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSlideMode.prototype.getTitle = function() { return 'GALLERY_SLIDE'; };
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/**
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @return {Viewport} Viewport.
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SlideMode.prototype.getViewport = function() { return this.viewport_; };
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the listeners.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.initListeners_ = function() {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  window.addEventListener('resize', this.onResize_.bind(this));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Initialize the UI.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.initDom_ = function() {
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Container for displayed image.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.imageContainer_ = util.createChild(
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.document_.querySelector('.content'), 'image-container');
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.imageContainer_.addEventListener('click', this.onClick_.bind(this));
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.document_.addEventListener('click', this.onDocumentClick_.bind(this));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overwrite options and info bubble.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.options_ = util.createChild(
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.toolbar_.querySelector('.filename-spacer'), 'options');
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.savedLabel_ = util.createChild(this.options_, 'saved');
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED');
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var overwriteOriginalBox =
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      util.createChild(this.options_, 'overwrite-original');
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.overwriteOriginal_ = util.createChild(
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      overwriteOriginalBox, '', 'input');
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.overwriteOriginal_.type = 'checkbox';
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.overwriteOriginal_.id = 'overwrite-checkbox';
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  chrome.storage.local.get(SlideMode.OVERWRITE_KEY, function(values) {
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    var value = values[SlideMode.OVERWRITE_KEY];
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Out-of-the box default is 'true'
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.overwriteOriginal_.checked =
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        (value === 'false' || value === false) ? false : true;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }.bind(this));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.overwriteOriginal_.addEventListener('click',
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.onOverwriteOriginalClick_.bind(this));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var overwriteLabel = util.createChild(overwriteOriginalBox, '', 'label');
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overwriteLabel.textContent =
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL');
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overwriteLabel.setAttribute('for', 'overwrite-checkbox');
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.bubble_ = util.createChild(this.toolbar_, 'bubble');
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.bubble_.hidden = true;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var bubbleContent = util.createChild(this.bubble_);
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bubbleContent.innerHTML = this.displayStringFunction_(
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      'GALLERY_OVERWRITE_BUBBLE');
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(this.bubble_, 'pointer bottom', 'span');
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var bubbleClose = util.createChild(this.bubble_, 'close-x');
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubbleClose.addEventListener('click', this.onCloseBubble_.bind(this));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ribbon and related controls.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.arrowBox_ = util.createChild(this.container_, 'arrow-box');
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.arrowLeft_ =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      util.createChild(this.arrowBox_, 'arrow left tool dimmable');
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.arrowLeft_.addEventListener('click',
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.advanceManually.bind(this, -1));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(this.arrowLeft_);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(this.arrowBox_, 'arrow-spacer');
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.arrowRight_ =
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      util.createChild(this.arrowBox_, 'arrow right tool dimmable');
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.arrowRight_.addEventListener('click',
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.advanceManually.bind(this, 1));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(this.arrowRight_);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.ribbonSpacer_ = this.toolbar_.querySelector('.ribbon-spacer');
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.ribbon_ = new Ribbon(
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.document_, this.dataModel_, this.selectionModel_);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.ribbonSpacer_.appendChild(this.ribbon_);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Error indicator.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var errorWrapper = util.createChild(this.container_, 'prompt-wrapper');
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  errorWrapper.setAttribute('pos', 'center');
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.errorBanner_ = util.createChild(errorWrapper, 'error-banner');
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(this.container_, 'spinner');
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var slideShowButton = this.toolbar_.querySelector('button.slideshow');
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  slideShowButton.addEventListener('click',
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var slideShowToolbar =
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      util.createChild(this.container_, 'tool slideshow-toolbar');
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(slideShowToolbar, 'slideshow-play').
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      addEventListener('click', this.toggleSlideshowPause_.bind(this));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util.createChild(slideShowToolbar, 'slideshow-end').
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      addEventListener('click', this.stopSlideshow_.bind(this));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Editor.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.editButton_ = this.toolbar_.querySelector('button.edit');
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
20468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.editButton_.setAttribute('disabled', '');  // Disabled by default.
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.printButton_ = this.toolbar_.querySelector('button.print');
20868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT');
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.printButton_.setAttribute('disabled', '');  // Disabled by default.
21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.printButton_.addEventListener('click', this.print_.bind(this));
21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.editBarSpacer_ = this.toolbar_.querySelector('.edit-bar-spacer');
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.editBarMain_ = util.createChild(this.editBarSpacer_, 'edit-main');
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editBarMode_ = util.createChild(this.container_, 'edit-modal');
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editBarModeWrapper_ = util.createChild(
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.editBarMode_, 'edit-modal-wrapper dimmable');
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editBarModeWrapper_.hidden = true;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Objects supporting image display and editing.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.viewport_ = new Viewport();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.imageView_ = new ImageView(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.imageContainer_,
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.viewport_);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editor_ = new ImageEditor(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.viewport_,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.imageView_,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.prompt_,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        root: this.container_,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        image: this.imageContainer_,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        toolbar: this.editBarMain_,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mode: this.editBarModeWrapper_
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      },
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      SlideMode.EDITOR_MODES,
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      this.displayStringFunction_,
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      this.onToolsVisibilityChanged_.bind(this));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchHandlers_ = new TouchHandler(this.imageContainer_, this);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Load items, display the selected item.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} zoomFromRect Rectangle for zoom effect.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} displayCallback Called when the image is displayed.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} loadCallback Called when the image is displayed.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.enter = function(
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zoomFromRect, displayCallback, loadCallback) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.sequenceDirection_ = 0;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.sequenceLength_ = 0;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var loadDone = function(loadType, delay) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.active_ = true;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.selectionModel_.addEventListener('change', this.onSelectionBound_);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.dataModel_.addEventListener('splice', this.onSpliceBound_);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.ribbon_.enable();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 1000ms after the animation is done, then prefetch the next image.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.requestPrefetch(1, delay + 1000);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (loadCallback) loadCallback();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }.bind(this);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The latest |leave| call might have left the image animating. Remove it.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.unloadImage_();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  new Promise(function(fulfill) {
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // If the items are empty, just show the error message.
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (this.getItemCount_() === 0) {
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.displayedIndex_ = -1;
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      //TODO(hirono) Show this message in the grid mode too.
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.showErrorBanner_('GALLERY_NO_IMAGES');
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      fulfill();
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Remember the selection if it is empty or multiple. It will be restored
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in |leave| if the user did not changing the selection manually.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var currentSelection = this.selectionModel_.selectedIndexes;
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (currentSelection.length === 1)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.savedSelection_ = null;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.savedSelection_ = currentSelection;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure valid single selection.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note that the SlideMode object is not listening to selection change yet.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.select(Math.max(0, this.getSelectedIndex()));
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.displayedIndex_ = this.getSelectedIndex();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Show the selected item ASAP, then complete the initialization
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (loading the ribbon thumbnails can take some time).
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var selectedItem = this.getSelectedItem();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Load the image of the item.
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.loadItem_(
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        selectedItem,
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        zoomFromRect && this.imageView_.createZoomEffect(zoomFromRect),
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        displayCallback,
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        function(loadType, delay) {
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          fulfill(delay);
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        });
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }.bind(this)).then(function(delay) {
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Turn the mode active.
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.active_ = true;
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.ribbon_.enable();
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Register handlers.
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.selectionModel_.addEventListener('change', this.onSelectionBound_);
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.dataModel_.addEventListener('splice', this.onSpliceBound_);
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.touchHandlers_.enabled = true;
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Wait 1000ms after the animation is done, then prefetch the next image.
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.requestPrefetch(1, delay + 1000);
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Call load callback.
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (loadCallback)
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      loadCallback();
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }.bind(this)).catch(function(error) {
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    console.error(error.stack, error);
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  });
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Leave the mode.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} zoomToRect Rectangle for zoom effect.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} callback Called when the image is committed and
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   the zoom-out animation has started.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.leave = function(zoomToRect, callback) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var commitDone = function() {
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.stopEditing_();
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.stopSlideshow_();
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ImageUtil.setAttribute(this.arrowBox_, 'active', false);
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.selectionModel_.removeEventListener(
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        'change', this.onSelectionBound_);
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.dataModel_.removeEventListener('splice', this.onSpliceBound_);
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.ribbon_.disable();
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.active_ = false;
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (this.savedSelection_)
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.selectionModel_.selectedIndexes = this.savedSelection_;
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.unloadImage_(zoomToRect);
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback();
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }.bind(this);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.viewport_.resetView();
353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (this.getItemCount_() === 0) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.showErrorBanner_(false);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commitDone();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.commitItem_(commitDone);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
35968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
36068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Disable the slide-mode only buttons when leaving.
36168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.editButton_.setAttribute('disabled', '');
36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.printButton_.setAttribute('disabled', '');
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Disable touch operation.
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchHandlers_.enabled = false;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Execute an action when the editor is not busy.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {function} action Function to execute.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.executeWhenReady = function(action) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editor_.executeWhenReady(action);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the mode has active tools (that should not fade).
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.hasActiveTool = function() {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.isEditing();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {number} Item count.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getItemCount_ = function() {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.dataModel_.length;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} index Index.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Gallery.Item} Item.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getItem = function(index) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.dataModel_.item(index);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Gallery.Item} Selected index.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getSelectedIndex = function() {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.selectionModel_.selectedIndex;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Rect} Screen rectangle of the selected image.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getSelectedImageRect = function() {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.getSelectedIndex() < 0)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return null;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return this.viewport_.getImageBoundsOnScreen();
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Gallery.Item} Selected item.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getSelectedItem = function() {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.getItem(this.getSelectedIndex());
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Toggles the full screen mode.
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SlideMode.prototype.toggleFullScreen_ = function() {
430a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  util.toggleFullScreen(this.context_.appWindow,
431a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                        !util.isFullScreen(this.context_.appWindow));
432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Selection change handler.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Commits the current image and displays the newly selected image.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onSelection_ = function() {
441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (this.selectionModel_.selectedIndexes.length === 0)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Temporary empty selection.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forget the saved selection if the user changed the selection manually.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!this.isSlideshowOn_())
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.savedSelection_ = null;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (this.getSelectedIndex() === this.displayedIndex_)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Do not reselect.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.commitItem_(this.loadSelectedItem_.bind(this));
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * Handles changes in tools visibility, and if the header is dimmed, then
4561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * requests disabling the draggable app region.
4571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *
4581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @private
4591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) */
4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SlideMode.prototype.onToolsVisibilityChanged_ = function() {
4611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  var headerDimmed =
4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      this.document_.querySelector('.header').hasAttribute('dimmed');
4631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  this.context_.onAppRegionChanged(!headerDimmed);
4641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
4651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)/**
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Change the selection.
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} index New selected index.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_slideHint Slide animation direction (-1|1).
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.select = function(index, opt_slideHint) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.slideHint_ = opt_slideHint;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.selectionModel_.selectedIndex = index;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.selectionModel_.leadIndex = index;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Load the selected item.
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.loadSelectedItem_ = function() {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var slideHint = this.slideHint_;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.slideHint_ = undefined;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var index = this.getSelectedIndex();
488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (index === this.displayedIndex_)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Do not reselect.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var step = slideHint || (index - this.displayedIndex_);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Math.abs(step) != 1) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Long leap, the sequence is broken, we have no good prefetch candidate.
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.sequenceDirection_ = 0;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.sequenceLength_ = 0;
497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else if (this.sequenceDirection_ === step) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Keeping going in sequence.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.sequenceLength_++;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reversed the direction. Reset the counter.
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.sequenceDirection_ = step;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.sequenceLength_ = 1;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
506116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.displayedIndex_ = index;
507116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var selectedItem = this.getSelectedItem();
508116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.sequenceLength_ <= 1) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have just broke the sequence. Touch the current image so that it stays
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in the cache longer.
512116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.imageView_.prefetch(selectedItem);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function shouldPrefetch(loadType, step, sequenceLength) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Never prefetch when selecting out of sequence.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (Math.abs(step) != 1)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Always prefetch if the previous load was from cache.
521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (loadType === ImageView.LOAD_TYPE_CACHED_FULL)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prefetch if we have been going in the same direction for long enough.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sequenceLength >= 3;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.currentUniqueKey_++;
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var selectedUniqueKey = this.currentUniqueKey_;
530116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
531116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Discard, since another load has been invoked after this one.
532116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (selectedUniqueKey != this.currentUniqueKey_)
533116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
534116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
535116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.loadItem_(
536116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      selectedItem,
537116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new ImageView.Effect.Slide(step, this.isSlideshowPlaying_()),
538116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      function() {} /* no displayCallback */,
539116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      function(loadType, delay) {
540116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // Discard, since another load has been invoked after this one.
541116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (selectedUniqueKey != this.currentUniqueKey_)
542116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return;
543116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (shouldPrefetch(loadType, step, this.sequenceLength_))
544116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          this.requestPrefetch(step, delay);
545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (this.isSlideshowPlaying_())
546116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          this.scheduleNextSlide_();
547116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }.bind(this));
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unload the current image.
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Rect} zoomToRect Rectangle for zoom effect.
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.unloadImage_ = function(zoomToRect) {
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.imageView_.unload(zoomToRect);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Data model 'splice' event handler.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} event Event.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onSplice_ = function(event) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Splice invalidates saved indices, drop the saved selection.
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.savedSelection_ = null;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.removed.length != 1)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delay the selection to let the ribbon splice handler work first.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setTimeout(function() {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (event.index < this.dataModel_.length) {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is the next item, select it.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The next item is now at the same index as the removed one, so we need
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to correct displayIndex_ so that loadSelectedItem_ does not think
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we are re-selecting the same item (and does right-to-left slide-in
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // animation).
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.displayedIndex_ = event.index - 1;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.select(event.index);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (this.dataModel_.length) {
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Removed item is the rightmost, but there are more items.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.select(event.index - 1);  // Select the new last index.
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No items left. Unload the image and show the banner.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.commitItem_(function() {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.unloadImage_();
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        this.showErrorBanner_('GALLERY_NO_IMAGES');
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }.bind(this));
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }.bind(this), 0);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} direction -1 for left, 1 for right.
5994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @return {number} Next index in the given direction, with wrapping.
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.getNextSelectedIndex_ = function(direction) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function advance(index, limit) {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index += (direction > 0 ? 1 : -1);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index < 0)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return limit - 1;
607a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (index === limit)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return index;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the saved selection is multiple the Slideshow should cycle through
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the saved selection.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.isSlideshowOn_() &&
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.savedSelection_ && this.savedSelection_.length > 1) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var pos = advance(this.savedSelection_.indexOf(this.getSelectedIndex()),
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.savedSelection_.length);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return this.savedSelection_[pos];
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return advance(this.getSelectedIndex(), this.getItemCount_());
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Advance the selection based on the pressed key ID.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} keyID Key identifier.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.advanceWithKeyboard = function(keyID) {
629116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var prev = (keyID === 'Up' ||
630116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              keyID === 'Left' ||
631116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              keyID === 'MediaPreviousTrack');
632116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.advanceManually(prev ? -1 : 1);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Advance the selection as a result of a user action (as opposed to an
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * automatic change in the slideshow mode).
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} direction -1 for left, 1 for right.
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.advanceManually = function(direction) {
641116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (this.isSlideshowPlaying_())
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.pauseSlideshow_();
643116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cr.dispatchSimpleEvent(this, 'useraction');
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.selectNext(direction);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Select the next item.
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} direction -1 for left, 1 for right.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.selectNext = function(direction) {
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.select(this.getNextSelectedIndex_(direction), direction);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Select the first item.
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.selectFirst = function() {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.select(0);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Select the last item.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.selectLast = function() {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.select(this.getItemCount_() - 1);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Loading/unloading
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Load and display an item.
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
674116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {Gallery.Item} item Item.
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} effect Transition effect object.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} displayCallback Called when the image is displayed
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     (which can happen before the image load due to caching).
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} loadCallback Called when the image is fully loaded.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.loadItem_ = function(
682116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    item, effect, displayCallback, loadCallback) {
683116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var entry = item.getEntry();
684116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var metadata = item.getMetadata();
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.showSpinner_(true);
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var loadDone = function(loadType, delay, error) {
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.showSpinner_(false);
689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (loadType === ImageView.LOAD_TYPE_ERROR) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if we have a specific error, then display it
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error) {
692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        this.showErrorBanner_(error);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // otherwise try to infer general error
695116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.showErrorBanner_('GALLERY_IMAGE_ERROR');
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (loadType === ImageView.LOAD_TYPE_OFFLINE) {
698116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.showErrorBanner_('GALLERY_IMAGE_OFFLINE');
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
701116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View'));
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var toMillions = function(number) {
704116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return Math.round(number / (1000 * 1000));
705116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    };
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
707116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'),
708116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        toMillions(metadata.filesystem.size));
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
710116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var canvas = this.imageView_.getCanvas();
711116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'),
712116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        toMillions(canvas.width * canvas.height));
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
714116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var extIndex = entry.name.lastIndexOf('.');
715116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var ext = extIndex < 0 ? '' :
716116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        entry.name.substr(extIndex + 1).toLowerCase();
717116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (ext === 'jpeg') ext = 'jpg';
718116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.metrics.recordEnum(
719116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES);
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Enable or disable buttons for editing and printing.
722116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (error) {
72368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      this.editButton_.setAttribute('disabled', '');
72468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      this.printButton_.setAttribute('disabled', '');
72568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
72668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      this.editButton_.removeAttribute('disabled');
72768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      this.printButton_.removeAttribute('disabled');
72868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
72968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For once edited image, disallow the 'overwrite' setting change.
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ImageUtil.setAttribute(this.options_, 'saved',
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !this.getSelectedItem().isOriginal());
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    chrome.storage.local.get(SlideMode.OVERWRITE_BUBBLE_KEY,
7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        function(values) {
7361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          var times = values[SlideMode.OVERWRITE_BUBBLE_KEY] || 0;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            this.bubble_.hidden = false;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (this.isEditing()) {
7401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              var items = {};
7411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              items[SlideMode.OVERWRITE_BUBBLE_KEY] = times + 1;
7421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              chrome.storage.local.set(items);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }.bind(this));
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    loadCallback(loadType, delay);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }.bind(this);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var displayDone = function() {
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cr.dispatchSimpleEvent(this, 'image-displayed');
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    displayCallback();
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }.bind(this);
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
755116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.editor_.openSession(
7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      item,
7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      effect,
7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.saveCurrentImage_.bind(this, item),
7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      displayDone,
7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      loadDone);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Commit changes to the current item and reset all messages/indicators.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} callback Callback.
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.commitItem_ = function(callback) {
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.showSpinner_(false);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.showErrorBanner_(false);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editor_.getPrompt().hide();
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.editor_.closeSession(callback);
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Request a prefetch for the next image.
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} direction -1 or 1.
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} delay Delay in ms. Used to prevent the CPU-heavy image
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   loading from disrupting the animation that might be still in progress.
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.requestPrefetch = function(direction, delay) {
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.getItemCount_() <= 1) return;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var index = this.getNextSelectedIndex_(direction);
787116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.imageView_.prefetch(this.getItem(index), delay);
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Event handlers.
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Unload handler, to be called from the top frame.
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} exiting True if the app is exiting.
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SlideMode.prototype.onUnload = function(exiting) {
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Click handler for the image container.
801eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
802eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @param {Event} event Mouse click event.
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
805eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochSlideMode.prototype.onClick_ = function(event) {
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Click handler for the entire document.
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event} e Mouse click event.
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SlideMode.prototype.onDocumentClick_ = function(e) {
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Close the bubble if clicked outside of it and if it is visible.
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!this.bubble_.contains(e.target) &&
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !this.editButton_.contains(e.target) &&
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !this.arrowLeft_.contains(e.target) &&
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !this.arrowRight_.contains(e.target) &&
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !this.bubble_.hidden) {
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.bubble_.hidden = true;
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Keydown handler.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} event Event.
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if handled.
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onKeyDown = function(event) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var keyID = util.getKeyModifiers(event) + event.keyIdentifier;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.isSlideshowOn_()) {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (keyID) {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'U+001B':  // Escape exits the slideshow.
836116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      case 'MediaStop':
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.stopSlideshow_(event);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'U+0020':  // Space pauses/resumes the slideshow.
841116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      case 'MediaPlayPause':
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.toggleSlideshowPause_();
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'Up':
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'Down':
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'Left':
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case 'Right':
849116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      case 'MediaNextTrack':
850116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      case 'MediaPreviousTrack':
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.advanceWithKeyboard(keyID);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Consume all keystrokes in the slideshow mode.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.isEditing() && this.editor_.onKeyDown(event))
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (keyID) {
86168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    case 'Ctrl-U+0050':  // Ctrl+'p' prints the current image.
86268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (!this.printButton_.hasAttribute('disabled'))
86368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        this.print_();
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
866eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case 'U+0045':  // 'e' toggles the editor.
86768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (!this.editButton_.hasAttribute('disabled'))
86868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        this.toggleEditor(event);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'U+001B':  // Escape
872116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (this.isEditing()) {
873116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.toggleEditor(event);
8745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else if (this.viewport_.isZoomed()) {
875116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.viewport_.resetView();
8765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.touchHandlers_.stopOperation();
877116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.imageView_.applyViewportChange();
878116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else {
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;  // Not handled.
880116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'Home':
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.selectFirst();
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'End':
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.selectLast();
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'Up':
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'Down':
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'Left':
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'Right':
8935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!this.isEditing() && this.viewport_.isZoomed()) {
894116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        var delta = SlideMode.KEY_OFFSET_MAP[keyID];
895116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.viewport_.setOffset(
896116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            ~~(this.viewport_.getOffsetX() +
897116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch               delta[0] * this.viewport_.getZoom()),
898116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            ~~(this.viewport_.getOffsetY() +
8995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               delta[1] * this.viewport_.getZoom()));
9005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.touchHandlers_.stopOperation();
901116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.imageView_.applyViewportChange();
902116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else {
903116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.advanceWithKeyboard(keyID);
904116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
905116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
906116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 'MediaNextTrack':
907116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 'MediaPreviousTrack':
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.advanceWithKeyboard(keyID);
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
911116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 'Ctrl-U+00BB':  // Ctrl+'=' zoom in.
912116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!this.isEditing()) {
9135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.viewport_.zoomIn();
9145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.touchHandlers_.stopOperation();
915116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.imageView_.applyViewportChange();
916116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
917116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
918116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
919116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 'Ctrl-U+00BD':  // Ctrl+'-' zoom out.
920116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!this.isEditing()) {
9215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.viewport_.zoomOut();
9225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.touchHandlers_.stopOperation();
923116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.imageView_.applyViewportChange();
924116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
925116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
926116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
927116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 'Ctrl-U+0030': // Ctrl+'0' zoom reset.
928116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!this.isEditing()) {
9295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.viewport_.setZoom(1.0);
9305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.touchHandlers_.stopOperation();
931116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        this.imageView_.applyViewportChange();
932116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
933116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Resize handler.
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onResize_ = function() {
944116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.viewport_.setScreenSize(
945116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.container_.clientWidth, this.container_.clientHeight);
9465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchHandlers_.stopOperation();
947116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.editor_.getBuffer().draw();
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Update thumbnails.
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.updateThumbnails = function() {
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.ribbon_.reset();
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.active_)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.ribbon_.redraw();
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Saving
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Save the current image to a file.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
9645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {Gallery.Item} item Item to save the image.
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function} callback Callback.
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
9685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SlideMode.prototype.saveCurrentImage_ = function(item, callback) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.showSpinner_(true);
970116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
971116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var savedPromise = this.dataModel_.saveItem(
9721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.volumeManager_,
973116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      item,
974116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.imageView_.getCanvas(),
975116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      this.shouldOverwriteOriginal_());
976116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
977116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  savedPromise.catch(function(error) {
978116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // TODO(hirono): Implement write error handling.
979116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Until then pretend that the save succeeded.
980116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    console.error(error.stack || error);
981116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }).then(function() {
982116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.showSpinner_(false);
983116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.flashSavedLabel_();
984116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
985116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Allow changing the 'Overwrite original' setting only if the user
986116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // used Undo to restore the original image AND it is not a copy.
987116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Otherwise lock the setting in its current state.
988116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    var mayChangeOverwrite = !this.editor_.canUndo() && item.isOriginal();
989116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ImageUtil.setAttribute(this.options_, 'saved', !mayChangeOverwrite);
990116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
991116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Record UMA for the first edit.
992116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (this.imageView_.getContentRevision() === 1)
993116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit'));
994116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
995116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    callback();
996116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    cr.dispatchSimpleEvent(this, 'image-saved');
997116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }.bind(this)).catch(function(error) {
998116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    console.error(error.stack || error);
999116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  });
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Flash 'Saved' label briefly to indicate that the image has been saved.
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.flashSavedLabel_ = function() {
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var setLabelHighlighted =
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted');
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setTimeout(setLabelHighlighted.bind(null, true), 0);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setTimeout(setLabelHighlighted.bind(null, false), 300);
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Local storage key for the 'Overwrite original' setting.
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {string}
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.OVERWRITE_KEY = 'gallery-overwrite-original';
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Local storage key for the number of times that
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the overwrite info bubble has been displayed.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {string}
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.OVERWRITE_BUBBLE_KEY = 'gallery-overwrite-bubble';
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Max number that the overwrite info bubble is shown.
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {number}
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.OVERWRITE_BUBBLE_MAX_TIMES = 5;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if 'Overwrite original' is set.
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.shouldOverwriteOriginal_ = function() {
10371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return this.overwriteOriginal_.checked;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 'Overwrite original' checkbox handler.
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} event Event.
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onOverwriteOriginalClick_ = function(event) {
10461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var items = {};
10471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  items[SlideMode.OVERWRITE_KEY] = event.target.checked;
10481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  chrome.storage.local.set(items);
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Overwrite info bubble close handler.
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.onCloseBubble_ = function() {
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.bubble_.hidden = true;
10571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var items = {};
10581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  items[SlideMode.OVERWRITE_BUBBLE_KEY] =
10591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SlideMode.OVERWRITE_BUBBLE_MAX_TIMES;
10601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  chrome.storage.local.set(items);
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Slideshow
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Slideshow interval in ms.
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.SLIDESHOW_INTERVAL = 5000;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * First slideshow interval in ms. It should be shorter so that the user
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * is not guessing whether the button worked.
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.SLIDESHOW_INTERVAL_FIRST = 1000;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Empirically determined duration of the fullscreen toggle animation.
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.FULLSCREEN_TOGGLE_DELAY = 500;
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the slideshow is on.
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.isSlideshowOn_ = function() {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.container_.hasAttribute('slideshow');
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
10905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Starts the slideshow.
10912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_interval First interval in ms.
10922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event=} opt_event Event.
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.startSlideshow = function(opt_interval, opt_event) {
1095116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Reset zoom.
1096116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.viewport_.resetView();
1097116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.imageView_.applyViewportChange();
1098116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Disable touch operation.
11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchHandlers_.enabled = false;
11015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the attribute early to prevent the toolbar from flashing when
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the slideshow is being started from the mosaic view.
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_.setAttribute('slideshow', 'playing');
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.active_) {
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.stopEditing_();
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We are in the Mosaic mode. Toggle the mode but remember to return.
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.leaveAfterSlideshow_ = true;
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.toggleMode_(this.startSlideshow.bind(
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, SlideMode.SLIDESHOW_INTERVAL, opt_event));
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (opt_event)  // Caused by user action, notify the Gallery.
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cr.dispatchSimpleEvent(this, 'useraction');
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  this.fullscreenBeforeSlideshow_ = util.isFullScreen(this.context_.appWindow);
1120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!this.fullscreenBeforeSlideshow_) {
1121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Wait until the zoom animation from the mosaic mode is done.
1122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    setTimeout(this.toggleFullScreen_.bind(this),
1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               ImageView.ZOOM_ANIMATION_DURATION);
1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    opt_interval = (opt_interval || SlideMode.SLIDESHOW_INTERVAL) +
1125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SlideMode.FULLSCREEN_TOGGLE_DELAY;
1126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.resumeSlideshow_(opt_interval);
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
11325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Stops the slideshow.
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event=} opt_event Event.
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.stopSlideshow_ = function(opt_event) {
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!this.isSlideshowOn_())
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (opt_event)  // Caused by user action, notify the Gallery.
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cr.dispatchSimpleEvent(this, 'useraction');
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pauseSlideshow_();
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_.removeAttribute('slideshow');
1145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Do not restore fullscreen if we exited fullscreen while in slideshow.
1147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  var fullscreen = util.isFullScreen(this.context_.appWindow);
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var toggleModeDelay = 0;
1149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!this.fullscreenBeforeSlideshow_ && fullscreen) {
1150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    this.toggleFullScreen_();
1151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    toggleModeDelay = SlideMode.FULLSCREEN_TOGGLE_DELAY;
1152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (this.leaveAfterSlideshow_) {
1154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    this.leaveAfterSlideshow_ = false;
1155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    setTimeout(this.toggleMode_.bind(this), toggleModeDelay);
1156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
11575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Re-enable touch operation.
11595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchHandlers_.enabled = true;
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the slideshow is playing (not paused).
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.isSlideshowPlaying_ = function() {
1167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return this.container_.getAttribute('slideshow') === 'playing';
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
11715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Pauses/resumes the slideshow.
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.toggleSlideshowPause_ = function() {
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cr.dispatchSimpleEvent(this, 'useraction');  // Show the tools.
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.isSlideshowPlaying_()) {
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.pauseSlideshow_();
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.resumeSlideshow_(SlideMode.SLIDESHOW_INTERVAL_FIRST);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_interval Slideshow interval in ms.
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.scheduleNextSlide_ = function(opt_interval) {
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  console.assert(this.isSlideshowPlaying_(), 'Inconsistent slideshow state');
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.slideShowTimeout_)
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clearTimeout(this.slideShowTimeout_);
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.slideShowTimeout_ = setTimeout(function() {
11941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.slideShowTimeout_ = null;
11951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.selectNext(1);
11961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }.bind(this), opt_interval || SlideMode.SLIDESHOW_INTERVAL);
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Resumes the slideshow.
12012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_interval Slideshow interval in ms.
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.resumeSlideshow_ = function(opt_interval) {
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_.setAttribute('slideshow', 'playing');
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.scheduleNextSlide_(opt_interval);
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Pauses the slideshow.
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.pauseSlideshow_ = function() {
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_.setAttribute('slideshow', 'paused');
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.slideShowTimeout_) {
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clearTimeout(this.slideShowTimeout_);
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.slideShowTimeout_ = null;
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the editor is active.
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.isEditing = function() {
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.container_.hasAttribute('editing');
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Stops editing.
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.stopEditing_ = function() {
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.isEditing())
12342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.toggleEditor();
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Activate/deactivate editor.
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event=} opt_event Event.
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SlideMode.prototype.toggleEditor = function(opt_event) {
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (opt_event)  // Caused by user action, notify the Gallery.
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cr.dispatchSimpleEvent(this, 'useraction');
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!this.active_) {
12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.toggleMode_(this.toggleEditor.bind(this));
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.stopSlideshow_();
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing());
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.isEditing()) { // isEditing has just been flipped to a new value.
1255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Reset zoom.
1256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.viewport_.resetView();
1257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    this.imageView_.applyViewportChange();
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (this.context_.readonlyDirName) {
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.editor_.getPrompt().showAt(
1260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          'top', 'GALLERY_READONLY_WARNING', 0, this.context_.readonlyDirName);
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.touchHandlers_.enabled = false;
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.editor_.getPrompt().hide();
12652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.editor_.leaveModeGently();
12665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.touchHandlers_.enabled = true;
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
127168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Prints the current item.
127268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * @private
127368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */
127468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)SlideMode.prototype.print_ = function() {
127568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  cr.dispatchSimpleEvent(this, 'useraction');
127668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  window.print();
127768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
127868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
127968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/**
12805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Displays the error banner.
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} message Message.
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.showErrorBanner_ = function(message) {
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.errorBanner_.textContent = this.displayStringFunction_(message);
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ImageUtil.setAttribute(this.container_, 'error', !!message);
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
12925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Shows/hides the busy spinner.
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} on True if show, false if hide.
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideMode.prototype.showSpinner_ = function(on) {
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.spinnerTimer_) {
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clearTimeout(this.spinnerTimer_);
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.spinnerTimer_ = null;
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (on) {
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.spinnerTimer_ = setTimeout(function() {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.spinnerTimer_ = null;
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ImageUtil.setAttribute(this.container_, 'spinner', true);
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }.bind(this), 1000);
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ImageUtil.setAttribute(this.container_, 'spinner', false);
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
13145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Apply the change of viewport.
13155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
13165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SlideMode.prototype.applyViewportChange = function() {
13175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.imageView_.applyViewportChange();
13185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
13195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
13215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Touch handlers of the slide mode.
13225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {DOMElement} targetElement Event source.
13235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {SlideMode} slideMode Slide mode to be operated by the handler.
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
13265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function TouchHandler(targetElement, slideMode) {
13275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Event source.
13295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {DOMElement}
13301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @private
13315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.targetElement_ = targetElement;
13335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Target of touch operations.
13365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {SlideMode}
13375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.slideMode_ = slideMode;
13405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Flag to enable/disable touch operation.
13435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
13441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @private
13455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.enabled_ = true;
13475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Whether it is in a touch operation that is started from targetElement or
13505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * not.
13515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
13525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchStarted_ = false;
13555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The swipe action that should happen only once in an operation is already
13585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * done or not.
13595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {boolean}
13605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.done_ = false;
13635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Event on beginning of the current gesture.
13665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * The variable is updated when the number of touch finger changed.
13675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {TouchEvent}
13685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.gestureStartEvent_ = null;
13715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Rotation value on beginning of the current gesture.
13745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {number}
13755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.gestureStartRotation_ = 0;
13785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Last touch event.
13815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {TouchEvent}
13825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastEvent_ = null;
13855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
13875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Zoom value just after last touch event.
13885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @type {number}
13895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @private
13905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
13915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastZoom_ = 1.0;
13925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  targetElement.addEventListener('touchstart', this.onTouchStart_.bind(this));
13945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var onTouchEventBound = this.onTouchEvent_.bind(this);
13955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  targetElement.ownerDocument.addEventListener('touchmove', onTouchEventBound);
13965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  targetElement.ownerDocument.addEventListener('touchend', onTouchEventBound);
13976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
13986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  targetElement.addEventListener('mousewheel', this.onMouseWheel_.bind(this));
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
14025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * If the user touched the image and moved the finger more than SWIPE_THRESHOLD
14035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * horizontally it's considered as a swipe gesture (change the current image).
14045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @type {number}
14055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @const
14065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
14075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.SWIPE_THRESHOLD = 100;
14085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
14105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Rotation threshold in degrees.
14115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @type {number}
14125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @const
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
14145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.ROTATION_THRESHOLD = 25;
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
14175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Obtains distance between fingers.
14185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {TouchEvent} event Touch event. It should include more than two
14195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *     touches.
14205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @return {boolean} Distance between touch[0] and touch[1].
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
14225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.getDistance = function(event) {
14235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var touch1 = event.touches[0];
14245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var touch2 = event.touches[1];
14255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dx = touch1.clientX - touch2.clientX;
14265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dy = touch1.clientY - touch2.clientY;
14275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Math.sqrt(dx * dx + dy * dy);
14285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
14295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
14315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Obtains the degrees of the pinch twist angle.
14325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {TouchEvent} event1 Start touch event. It should include more than two
14335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *     touches.
14345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {TouchEvent} event2 Current touch event. It should include more than
14355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *     two touches.
14365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @return {number} Degrees of the pinch twist angle.
14375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
14385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.getTwistAngle = function(event1, event2) {
14395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dx1 = event1.touches[1].clientX - event1.touches[0].clientX;
14405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dy1 = event1.touches[1].clientY - event1.touches[0].clientY;
14415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dx2 = event2.touches[1].clientX - event2.touches[0].clientX;
14425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var dy2 = event2.touches[1].clientY - event2.touches[0].clientY;
14435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var innerProduct = dx1 * dx2 + dy1 * dy2;  // |v1| * |v2| * cos(t) = x / r
14445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var outerProduct = dx1 * dy2 - dy1 * dx2;  // |v1| * |v2| * sin(t) = y / r
14455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Math.atan2(outerProduct, innerProduct) * 180 / Math.PI;  // atan(y / x)
14465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
14475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TouchHandler.prototype = {
14496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  /**
14506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)   * @param {boolean} flag New value.
14516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)   */
14526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  set enabled(flag) {
14536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    this.enabled_ = flag;
14546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!this.enabled_)
14556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      this.stopOperation();
14566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
14576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
14586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
14595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
14605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Stops the current touch operation.
14615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */
14625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.prototype.stopOperation = function() {
14635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.touchStarted_ = false;
14645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.done_ = false;
14655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.gestureStartEvent_ = null;
14665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastEvent_ = null;
14675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastZoom_ = 1.0;
14685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
14695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/**
14716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Handles touch start events.
14726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {TouchEvent} event Touch event.
14736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private
14746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */
14755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.prototype.onTouchStart_ = function(event) {
14765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (this.enabled_ && event.touches.length === 1)
14775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.touchStarted_ = true;
14785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
14795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/**
14816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Handles touch move and touch end events.
14826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {TouchEvent} event Touch event.
14836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
14855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TouchHandler.prototype.onTouchEvent_ = function(event) {
14865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Check if the current touch operation started from the target element or
14875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // not.
14885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!this.touchStarted_)
14895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
14905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Check if the current touch operation ends with the event.
14925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (event.touches.length === 0) {
14935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.stopOperation();
14945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
14955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
14965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Check if a new gesture started or not.
14985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var viewport = this.slideMode_.getViewport();
14995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!this.lastEvent_ ||
15005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.lastEvent_.touches.length !== event.touches.length) {
15015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (event.touches.length === 2 ||
15025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        event.touches.length === 1) {
15035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.gestureStartEvent_ = event;
15045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.gestureStartRotation_ = viewport.getRotation();
15055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.lastEvent_ = event;
15065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.lastZoom_ = viewport.getZoom();
15075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
15085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.gestureStartEvent_ = null;
15095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.gestureStartRotation_ = 0;
15105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.lastEvent_ = null;
15115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.lastZoom_ = 1.0;
15125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
15135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
15145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
15155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Handle the gesture movement.
15175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  switch (event.touches.length) {
15185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case 1:
15195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (viewport.isZoomed()) {
15205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // Scrolling an image by swipe.
15215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var dx = event.touches[0].screenX - this.lastEvent_.touches[0].screenX;
15225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var dy = event.touches[0].screenY - this.lastEvent_.touches[0].screenY;
15235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        viewport.setOffset(
15245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            viewport.getOffsetX() + dx, viewport.getOffsetY() + dy);
15255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.slideMode_.applyViewportChange();
15265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
15275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // Traversing images by swipe.
15285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (this.done_)
15295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          break;
15305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var dx =
15315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            event.touches[0].clientX -
15325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this.gestureStartEvent_.touches[0].clientX;
15335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (dx > TouchHandler.SWIPE_THRESHOLD) {
15345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.slideMode_.advanceManually(-1);
15355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.done_ = true;
15365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        } else if (dx < -TouchHandler.SWIPE_THRESHOLD) {
15375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.slideMode_.advanceManually(1);
15385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.done_ = true;
15395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
15405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
15415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
15425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case 2:
15445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Pinch zoom.
15455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var distance1 = TouchHandler.getDistance(this.lastEvent_);
15465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var distance2 = TouchHandler.getDistance(event);
15475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (distance1 === 0)
15485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
15495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var zoom = distance2 / distance1 * this.lastZoom_;
15505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      viewport.setZoom(zoom);
15515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Pinch rotation.
15535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var angle = TouchHandler.getTwistAngle(this.gestureStartEvent_, event);
15545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (angle > TouchHandler.ROTATION_THRESHOLD)
15555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        viewport.setRotation(this.gestureStartRotation_ + 1);
15565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      else if (angle < -TouchHandler.ROTATION_THRESHOLD)
15575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        viewport.setRotation(this.gestureStartRotation_ - 1);
15585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      else
15595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        viewport.setRotation(this.gestureStartRotation_);
15605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.slideMode_.applyViewportChange();
15615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
15625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
15635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Update the last event.
15655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastEvent_ = event;
15665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  this.lastZoom_ = viewport.getZoom();
15675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
15686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
15696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/**
15706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Handles mouse wheel events.
15716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {MouseEvent} event Wheel event.
15726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private
15736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */
15746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TouchHandler.prototype.onMouseWheel_ = function(event) {
15756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  var viewport = this.slideMode_.getViewport();
15766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!this.enabled_ || !viewport.isZoomed())
15776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
15786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  this.stopOperation();
15796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  viewport.setOffset(
15806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      viewport.getOffsetX() + event.wheelDeltaX,
15816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      viewport.getOffsetY() + event.wheelDeltaY);
15826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  this.slideMode_.applyViewportChange();
15836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
1584