text:     start: function (e) {
        var target = e.target;
  
        if ($(target).is('img')) {
          this.target = target;
          this.show();
        }
      },
  
      click: function (e) {
        var $target = $(e.target);
        var action = $target.data('action');
        var image = this.image;
  
        switch (action) {
          case 'mix':
            if (this.isPlayed) {
              this.stop();
            } else {
              if (this.options.inline) {
                if (this.isFulled) {
                  this.exit();
                } else {
                  this.full();
                }
              } else {
                this.hide();
              }
            }
  
            break;
  
          case 'view':
            this.view($target.data('index'));
            break;
  
          case 'zoom-in':
            this.zoom(0.1, true);
            break;
  
          case 'zoom-out':
            this.zoom(-0.1, true);
            break;
  
          case 'one-to-one':
            this.toggle();
            break;
  
          case 'reset':
            this.reset();
            break;
  
          case 'prev':
            this.prev();
            break;
  
          case 'play':
            this.play();
            break;
  
          case 'next':
            this.next();
            break;
  
          case 'rotate-left':
            this.rotate(-90);
            break;
  
          case 'rotate-right':
            this.rotate(90);
            break;
  
          case 'flip-horizontal':
            this.scaleX(-image.scaleX || -1);
            break;
  
          case 'flip-vertical':
            this.scaleY(-image.scaleY || -1);
            break;
  
          default:
            if (this.isPlayed) {
              this.stop();
            }
        }
      },
  
      load: function () {
        var options = this.options;
        var viewer = this.viewer;
        var $image = this.$image;
  
        if (this.timeout) {
          clearTimeout(this.timeout);
          this.timeout = false;
        }
  
        $image.removeClass(CLASS_INVISIBLE).css('cssText', (
          'width:0;' +
          'height:0;' +
          'margin-left:' + viewer.width / 2 + 'px;' +
          'margin-top:' + viewer.height / 2 + 'px;' +
          'max-width:none!important;' +
          'visibility:visible;'
        ));
  
        this.initImage($.proxy(function () {
          $image.
            toggleClass(CLASS_TRANSITION, options.transition).
            toggleClass(CLASS_MOVE, options.movable);
  
          this.renderImage($.proxy(function () {
            this.isViewed = true;
            this.trigger(EVENT_VIEWED);
          }, this));
        }, this));
      },
  
      loadImage: function (e) {
        var image = e.target;
        var $image = $(image);
        var $parent = $image.parent();
        var parentWidth = $parent.width();
        var parentHeight = $parent.height();
        var filled = e.data && e.data.filled;
  
        getImageSize(image, function (naturalWidth, naturalHeight) {
          var aspectRatio = naturalWidth / naturalHeight;
          var width = parentWidth;
          var height = parentHeight;
  
          if (parentHeight * aspectRatio > parentWidth) {
            if (filled) {
              width = parentHeight * aspectRatio;
            } else {
              height = parentWidth / aspectRatio;
            }
          } else {
            if (filled) {
              height = parentWidth / aspectRatio;
            } else {
              width = parentHeight * aspectRatio;
            }
          }
  
          $image.css({
            width: width,
            height: height,
            marginLeft: (parentWidth - width) / 2,
            marginTop: (parentHeight - height) / 2
          });
        });
      },
  
      resize: function () {
        this.initContainer();
        this.initViewer();
        this.renderViewer();
        this.renderList();
  
        if (this.isViewed) {
          this.initImage($.proxy(function () {
            this.renderImage();
          }, this));
        }
  
        if (this.isPlayed) {
          this.$player.
            find(SELECTOR_IMG).
            one(EVENT_LOAD, $.proxy(this.loadImage, this)).
            trigger(EVENT_LOAD);
        }
      },
  
      wheel: function (event) {
        var e = event.originalEvent || event;
        var ratio = num(this.options.zoomRatio) || 0.1;
        var delta = 1;
  
        if (!this.isViewed) {
          return;
        }
  
        event.preventDefault();
  
        // Limit wheel speed to prevent zoom too fast
        if (this.wheeling) {
          return;
        }
  
        this.wheeling = true;
  
        setTimeout($.proxy(function () {
          this.wheeling = false;
        }, this), 50);
  
        if (e.deltaY) {
          delta = e.deltaY > 0 ? 1 : -1;
        } else if (e.wheelDelta) {
          delta = -e.wheelDelta / 120;
        } else if (e.detail) {
          delta = e.detail > 0 ? 1 : -1;
        }
  
        this.zoom(-delta * ratio, true, event);
      },
  
      keydown: function (e) {
        var options = this.options;
        var which = e.which;
  
        if (!this.isFulled || !options.keyboard) {
          return;
        }
  
        switch (which) {
  
          // (Key: Esc)
          case 27:
            if (this.isPlayed) {
              this.stop();
            } else {
              if (options.inline) {
                if (this.isFulled) {
                  this.exit();
                }
              } else {
                this.hide();
              }
            }
  
            break;
  
          // (Key: Space)
          case 32:
            if (this.isPlayed) {
              this.stop();
            }
  
            break;
  
          // View previous (Key: ←)
          case 37:
            this.prev();
            break;
  
          // Zoom in (Key: ↑)
          case 38:
  
            // Prevent scroll on Firefox
            e.preventDefault();
  
            this.zoom(options.zoomRatio, true);
            break;
  
          // View next (Key: →)
          case 39:
            this.next();
            break;
  
          // Zoom out (Key: ↓)
          case 40:
  
            // Prevent scroll on Firefox
            e.preventDefault();
  
            this.zoom(-options.zoomRatio, true);
            break;
  
          // Zoom out to initial size (Key: Ctrl + 0)
          case 48:
            // Go to next
  
          // Zoom in to natural size (Key: Ctrl + 1)
          case 49:
            if (e.ctrlKey || e.shiftKey) {
              e.preventDefault();
              this.toggle();
            }
  
            break;
  
          // No default
        }
      },
  
      mousedown: function (event) {
        var options = this.options;
        var originalEvent = event.originalEvent;
        var touches = originalEvent && originalEvent.touches;
        var e = event;
        var action = options.movable ? 'move' : false;
        var touchesLength;
  
        if (!this.isViewed) {
          return;
        }
  
        if (touches) {
          touchesLength = touches.length;
  
          if (touchesLength > 1) {
            if (options.zoomable && touchesLength === 2) {
              e = touches[1];
              this.startX2 = e.pageX;
              this.startY2 = e.pageY;
              action = 'zoom';
            } else {
              return;
            }
          } else {
            if (this.isSwitchable()) {
              action = 'switch';
            }
          }
  
          e = touches[0];
        }
  
        if (action) {
          event.preventDefault();
          this.action = action;
  
          // IE8  has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
          // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
          this.startX = e.pageX || originalEvent && originalEvent.pageX;
          this.startY = e.pageY || originalEvent && originalEvent.pageY;
        }
      },
  
      mousemove: function (event) {
        var options = this.options;
        var action = this.action;
        var $image = this.$image;
        var originalEvent = event.originalEvent;
        var touches = originalEvent && originalEvent.touches;
        var e = event;
        var touchesLength;
  
        if (!this.isViewed) {
          return;
        }
  
        if (touches) {
          touchesLength = touches.length;
  
          if (touchesLength > 1) {
            if (options.zoomable && touchesLength === 2) {
              e = touches[1];
              this.endX2 = e.pageX;
              this.endY2 = e.pageY;
            } else {
              return;
            }
          }
  
          e = touches[0];
        }
  
        if (action) {
          event.preventDefault();
  
          if (action === 'move' && options.transition && $image.hasClass(CLASS_TRANSITION)) {
            $image.removeClass(CLASS_TRANSITION);
          }
  
          this.endX = e.pageX || originalEvent && originalEvent.pageX;
          this.endY = e.pageY || originalEvent && originalEvent.pageY;
  
          this.change(event);
        }
      },
  
      mouseup: function (event) {
        var action = this.action;
  
        if (action) {
          event.preventDefault();
  
          if (action === 'move' && this.options.transition) {
            this.$image.addClass(CLASS_TRANSITION);
          }
  
          this.action = false;
        }
      },
  