/**
 * Modules in this bundle
 * @license
 *
 * smartphoto:
 *   license: MIT (http://opensource.org/licenses/MIT)
 *   author: appleple
 *   homepage: http://developer.a-blogcms.jp
 *   version: 0.5.9
 *
 * a-template:
 *   license: MIT (http://opensource.org/licenses/MIT)
 *   author: steelydylan
 *   maintainers: steelydylan <ess_president@me.com>
 *   version: 0.2.0
 *
 * delegate:
 *   license: MIT (http://opensource.org/licenses/MIT)
 *   maintainers: zenorocha <zno.rocha@gmail.com>
 *   homepage: https://github.com/zenorocha/delegate#readme
 *   version: 3.1.2
 *
 * morphdom:
 *   license: MIT (http://opensource.org/licenses/MIT)
 *   author: Patrick Steele-Idem <pnidem@gmail.com>
 *   maintainers: mlrawlings <ml.rawlings@gmail.com>, pnidem <pnidem@gmail.com>
 *   homepage: https://github.com/patrick-steele-idem/morphdom#readme
 *   version: 2.3.2
 *
 * This header is generated by licensify (https://github.com/twada/licensify)
 */
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var morphdom = require('morphdom');
var delegate = require('delegate');
var objs = [];
var eventType = "input paste copy click change keydown keyup contextmenu mouseup mousedown mousemove touchstart touchend touchmove compositionstart compositionend";
var dataAction = eventType.replace(/([a-z]+)/g, "[data-action-$1],") + "[data-action]";

if (!Array.prototype.find) {
  Array.prototype.find = function (predicate) {
    if (this === null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value = void 0;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return value;
      }
    }
    return undefined;
  };
}

if (!Element.prototype.matches) {
  Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function (s) {
    var matches = (this.document || this.ownerDocument).querySelectorAll(s),
        i = matches.length;
    while (--i >= 0 && matches.item(i) !== this) {}
    return i > -1;
  };
}

var selector = function selector(_selector) {
  return document.querySelector(_selector);
};
var getObjectById = function getObjectById(id) {
  for (var i = 0, n = objs.length; i < n; i++) {
    var obj = objs[i];
    var templates = obj.templates;
    for (var t = 0, m = templates.length; t < m; t++) {
      if (templates[t] == id) {
        return obj;
      }
    }
  }
  return null;
};

var findAncestor = function findAncestor(element, selector) {
  if (typeof element.closest === 'function') {
    return element.closest(selector) || null;
  }
  while (element) {
    if (element.matches(selector)) {
      return element;
    }
    element = element.parentElement;
  }
  return null;
};

var on = function on(element, query, e, fn) {
  var events = e.split(' ');
  events.forEach(function (event) {
    delegate(element, query, event, fn);
  });
};

if (typeof document !== "undefined") {
  //data binding
  on(document, '[data-bind]', 'input change click', function (e) {
    var target = e.delegateTarget;
    var data = target.getAttribute('data-bind');
    var attr = target.getAttribute('href');
    var id = findAncestor(target, '[data-id]').getAttribute('data-id');
    var value = target.value;
    if (attr) {
      value = value.replace('#', '');
    }
    if (id) {
      var obj = getObjectById(id);
      if (target.getAttribute('type') === 'radio') {} else if (target.getAttribute('type') === 'checkbox') {
        (function () {
          var arr = [];
          var items = document.querySelectorAll('[data-bind="' + data + '"]');
          [].forEach.call(items, function (item) {
            if (item.checked) {
              arr.push(item.value);
            }
          });
        })();
      } else {
        obj.updateDataByString(data, value);
      }
    }
  });

  //action
  on(document, dataAction, eventType, function (e) {
    var target = e.delegateTarget;
    if (e.type === "click" && target.tagName === 'select') {
      return;
    }
    if (e.type === "input" && target.getAttribute("type") === "button") {
      return;
    }
    var events = eventType.split(" ");
    var action = "action";
    events.forEach(function (event) {
      if (target.getAttribute("data-action-" + event)) {
        if (e.type === event) {
          action += "-" + event;
        }
      }
    });
    var string = target.getAttribute('data-' + action);
    if (!string) {
      return;
    }
    var method = string.replace(/\(.*?\);?/, "");
    var parameter = string.replace(/(.*?)\((.*?)\);?/, "$2");
    var pts = parameter.split(","); //引き数
    var id = findAncestor(target, '[data-id]').getAttribute('data-id');
    if (!id) {
      return;
    }
    var obj = getObjectById(id);
    obj.e = e;
    if (obj.method && obj.method[method]) {
      obj.method[method].apply(obj, pts);
    } else if (obj[method]) {
      obj[method].apply(obj, pts);
    }
  });
}

var aTemplate = function () {
  function aTemplate(opt) {
    _classCallCheck(this, aTemplate);

    this.atemplate = [];
    objs.push(this);
    for (var i in opt) {
      this[i] = opt[i];
    }
    if (!this.data) {
      this.data = {};
    }
    if (!this.templates) {
      this.templates = [];
    }
    var templates = this.templates;
    var length = templates.length;
    for (var _i = 0, n = length; _i < n; _i++) {
      var template = this.templates[_i];
      var html = selector('#' + template).innerHTML;
      this.atemplate.push({ id: template, html: html });
    }
    this.setId();
  }

  _createClass(aTemplate, [{
    key: 'addTemplate',
    value: function addTemplate(id, html) {
      this.atemplate.push({ id: id, html: html });
      this.templates.push(id);
    }
  }, {
    key: 'loadHtml',
    value: function loadHtml() {
      var templates = this.templates;
      var promises = [];
      templates.forEach(function (template) {
        var d = new $.Deferred();
        promises.push(d);
        var src = selector('#' + template).getAttribute('src');
        $.ajax({
          url: src,
          type: 'GET',
          dataType: 'text'
        }).success(function (data) {
          selector('#' + template).innerHTML = data;
          d.resolve();
        });
      });
      return $.when.apply($, promises);
    }
  }, {
    key: 'getData',
    value: function getData() {
      return JSON.parse(JSON.stringify(this.data));
    }
  }, {
    key: 'saveData',
    value: function saveData(key) {
      var data = JSON.stringify(this.data);
      localStorage.setItem(key, data);
    }
  }, {
    key: 'setData',
    value: function setData(val) {
      for (var i in val) {
        if (typeof val[i] !== "function") {
          this.data[i] = val[i];
        }
      }
    }
  }, {
    key: 'loadData',
    value: function loadData(key) {
      var data = JSON.parse(localStorage.getItem(key));
      if (data) {
        for (var i in data) {
          if (typeof data[i] !== "function") {
            this.data[i] = data[i];
          }
        }
      }
    }
  }, {
    key: 'getRand',
    value: function getRand(a, b) {
      return ~~(Math.random() * (b - a + 1)) + a;
    }
  }, {
    key: 'getRandText',
    value: function getRandText(limit) {
      var ret = "";
      var strings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      var length = strings.length;
      for (var i = 0; i < limit; i++) {
        ret += strings.charAt(Math.floor(this.getRand(0, length)));
      }
      return ret;
    }
  }, {
    key: 'setId',
    value: function setId() {
      var text = void 0;
      var ids = aTemplate.ids;
      var flag = false;
      while (1) {
        text = this.getRandText(10);
        for (var i = 0, n = aTemplate.ids; i < n; i++) {
          if (aTemplate.ids[i] === text) {
            flag = true;
          }
        }
        if (flag === false) {
          break;
        }
      }
      this.data.aTemplate_id = text;
    }
  }, {
    key: 'getDataFromObj',
    value: function getDataFromObj(s, o) {
      s = s.replace(/\[([a-zA-Z0-9._-]+)\]/g, '.$1'); // convert indexes to properties
      s = s.replace(/^\./, ''); // strip leading dot
      var a = s.split('.');
      while (a.length) {
        var n = a.shift();
        if (n in o) {
          o = o[n];
        } else {
          return;
        }
      }
      return o;
    }
  }, {
    key: 'getDataByString',
    value: function getDataByString(s) {
      var o = this.data;
      return this.getDataFromObj(s, o);
    }
  }, {
    key: 'updateDataByString',
    value: function updateDataByString(path, newValue) {
      var object = this.data;
      var stack = path.split('.');
      while (stack.length > 1) {
        object = object[stack.shift()];
      }
      object[stack.shift()] = newValue;
    }
  }, {
    key: 'removeDataByString',
    value: function removeDataByString(path) {
      var object = this.data;
      var stack = path.split('.');
      while (stack.length > 1) {
        object = object[stack.shift()];
      }
      var shift = stack.shift();
      if (shift.match(/^\d+$/)) {
        object.splice(Number(shift), 1);
      } else {
        delete object[shift];
      }
    }
  }, {
    key: 'resolveBlock',
    value: function resolveBlock(html, item, i) {
      var that = this;
      var touchs = html.match(/<!-- BEGIN ([a-zA-Z0-9._-]+):touch#([a-zA-Z0-9._-]+) -->/g);
      var touchnots = html.match(/<!-- BEGIN ([a-zA-Z0-9._-]+):touchnot#([a-zA-Z0-9._-]+) -->/g);
      var exists = html.match(/<!-- BEGIN ([a-zA-Z0-9._-]+):exist -->/g);
      var empties = html.match(/<!-- BEGIN ([a-zA-Z0-9._-]+):empty -->/g);
      /*タッチブロック解決*/
      if (touchs) {
        for (var k = 0, n = touchs.length; k < n; k++) {
          var start = touchs[k];
          start = start.replace(/([a-zA-Z0-9._-]+):touch#([a-zA-Z0-9._-]+)/, "($1):touch#($2)");
          var end = start.replace(/BEGIN/, "END");
          var reg = new RegExp(start + "(([\\n\\r\\t]|.)*?)" + end, "g");
          html = html.replace(reg, function (m, key2, val, next) {
            var itemkey = typeof item[key2] === "function" ? item[key2].apply(that) : that.getDataFromObj(key2, item);
            if (itemkey == val) {
              return next;
            } else {
              return "";
            }
          });
        }
      }
      /*タッチノットブロック解決*/
      if (touchnots) {
        for (var _k = 0, _n = touchnots.length; _k < _n; _k++) {
          var _start = touchnots[_k];
          _start = _start.replace(/([a-zA-Z0-9._-]+):touchnot#([a-zA-Z0-9._-]+)/, "($1):touchnot#($2)");
          var _end = _start.replace(/BEGIN/, "END");
          var _reg = new RegExp(_start + "(([\\n\\r\\t]|.)*?)" + _end, "g");
          html = html.replace(_reg, function (m, key2, val, next) {
            var itemkey = typeof item[key2] === "function" ? item[key2].apply(that) : that.getDataFromObj(key2, item);
            if (itemkey != val) {
              return next;
            } else {
              return "";
            }
          });
        }
      }
      /*existブロックを解決*/
      if (exists) {
        for (var _k2 = 0, _n2 = exists.length; _k2 < _n2; _k2++) {
          var _start2 = exists[_k2];
          _start2 = _start2.replace(/([a-zA-Z0-9._-]+):exist/, "($1):exist");
          var _end2 = _start2.replace(/BEGIN/, "END");
          var _reg2 = new RegExp(_start2 + "(([\\n\\r\\t]|.)*?)" + _end2, "g");
          html = html.replace(_reg2, function (m, key2, next) {
            var itemkey = typeof item[key2] === "function" ? item[key2].apply(that) : that.getDataFromObj(key2, item);
            if (itemkey || itemkey === 0) {
              return next;
            } else {
              return "";
            }
          });
        }
      }
      /*emptyブロックを解決*/
      if (empties) {
        for (var _k3 = 0, _n3 = empties.length; _k3 < _n3; _k3++) {
          var _start3 = empties[_k3];
          _start3 = _start3.replace(/([a-zA-Z0-9._-]+):empty/, "($1):empty");
          var _end3 = _start3.replace(/BEGIN/, "END");
          var empty = new RegExp(_start3 + "(([\\n\\r\\t]|.)*?)" + _end3, "g");
          html = html.replace(empty, function (m, key2, next) {
            var itemkey = typeof item[key2] === "function" ? item[key2].apply(that) : that.getDataFromObj(key2, item);
            if (!itemkey && itemkey !== 0) {
              return next;
            } else {
              return "";
            }
          });
        }
      }
      /*変数解決*/
      html = html.replace(/{([a-zA-Z0-9._-]+)}(\[([a-zA-Z0-9._-]+)\])*/g, function (n, key3, key4, converter) {
        var data = void 0;
        if (key3 == "i") {
          data = i;
        } else {
          if (item[key3] || item[key3] === 0) {
            if (typeof item[key3] === "function") {
              data = item[key3].apply(that);
            } else {
              data = item[key3];
            }
          } else {
            if (converter && that.convert && that.convert[converter]) {
              return that.convert[converter].call(that, "");
            } else {
              return "";
            }
          }
        }
        if (converter && that.convert && that.convert[converter]) {
          return that.convert[converter].call(that, data);
        } else {
          return data;
        }
      });
      return html;
    }
    /*絶対パス形式の変数を解決*/

  }, {
    key: 'resolveAbsBlock',
    value: function resolveAbsBlock(html) {
      var that = this;
      html = html.replace(/{(.*?)}/g, function (n, key3) {
        var data = that.getDataByString(key3);
        if (typeof data !== "undefined") {
          if (typeof data === "function") {
            return data.apply(that);
          } else {
            return data;
          }
        } else {
          return n;
        }
      });
      return html;
    }
  }, {
    key: 'resolveInclude',
    value: function resolveInclude(html) {
      var include = /<!-- #include id="(.*?)" -->/g;
      html = html.replace(include, function (m, key) {
        return selector('#' + key).innerHTML;
      });
      return html;
    }
  }, {
    key: 'resolveWith',
    value: function resolveWith(html) {
      var width = /<!-- BEGIN ([a-zA-Z0-9._-]+):with -->(([\n\r\t]|.)*?)<!-- END ([a-zA-Z0-9._-]+):with -->/g;
      html = html.replace(width, function (m, key, val) {
        m = m.replace(/data\-bind=['"](.*?)['"]/g, "data-bind='" + key + ".$1'");
        return m;
      });
      return html;
    }
  }, {
    key: 'resolveLoop',
    value: function resolveLoop(html) {
      var loop = /<!-- BEGIN (.+?):loop -->(([\n\r\t]|.)*?)<!-- END (.+?):loop -->/g;
      var that = this;
      /*ループ文解決*/
      html = html.replace(loop, function (m, key, val) {
        var keyItem = that.getDataByString(key);
        var keys = [];
        if (typeof keyItem === "function") {
          keys = keyItem.apply(that);
        } else {
          keys = keyItem;
        }
        var ret = "";
        if (keys instanceof Array) {
          for (var i = 0, n = keys.length; i < n; i++) {
            ret += that.resolveBlock(val, keys[i], i);
          }
        }
        /*エスケープ削除*/
        ret = ret.replace(/\\([^\\])/g, "$1");
        return ret;
      });
      return html;
    }
  }, {
    key: 'removeData',
    value: function removeData(arr) {
      var data = this.data;
      for (var i in data) {
        for (var t = 0, n = arr.length; t < n; t++) {
          if (i === arr[t]) {
            delete data[i];
          }
        }
      }
      return this;
    }
  }, {
    key: 'hasLoop',
    value: function hasLoop(txt) {
      var loop = /<!-- BEGIN (.+?):loop -->(([\n\r\t]|.)*?)<!-- END (.+?):loop -->/g;
      if (txt.match(loop)) {
        return true;
      } else {
        return false;
      }
    }
  }, {
    key: 'getHtml',
    value: function getHtml(selector, row) {
      var template = this.atemplate.find(function (item) {
        return item.id === selector;
      });
      var html = "";
      if (template && template.html) {
        html = template.html;
      }
      if (row) {
        html = selector;
      }
      if (!html) {
        return "";
      }
      var data = this.data;
      /*インクルード解決*/
      html = this.resolveInclude(html);
      /*with解決*/
      html = this.resolveWith(html);
      /*ループ解決*/
      while (this.hasLoop(html)) {
        html = this.resolveLoop(html);
      }
      /*変数解決*/
      html = this.resolveBlock(html, data);
      /*エスケープ削除*/
      html = html.replace(/\\([^\\])/g, "$1");
      /*絶対パスで指定された変数を解決*/
      html = this.resolveAbsBlock(html);
      /*空行削除*/
      return html.replace(/^([\t ])*\n/gm, "");
    }
  }, {
    key: 'update',
    value: function update(txt, part) {
      var html = this.getHtml();
      var templates = this.templates;
      var renderWay = txt || "html";
      if (this.beforeUpdated) {
        this.beforeUpdated();
      }
      for (var i = 0, n = templates.length; i < n; i++) {
        var tem = templates[i];
        var query = "#" + tem;
        var _html = this.getHtml(tem);
        var target = selector('[data-id=\'' + tem + '\']');
        if (!part || part == tem) {
          if (!target) {
            selector(query).insertAdjacentHTML('afterend', '<div data-id="' + tem + '"></div>');
            if (renderWay === 'text') {
              selector('[data-id=\'' + tem + '\']').innerText = _html;
            } else {
              selector('[data-id=\'' + tem + '\']').innerHTML = _html;
            }
          } else {
            if (renderWay === 'text') {
              target.innerText = _html;
            } else {
              morphdom(target, '<div data-id=\'' + tem + '\'>' + _html + '</div>');
            }
          }
          if (part) {
            break;
          }
        }
      }
      this.updateBindingData(part);
      if (this.onUpdated) {
        this.onUpdated(part);
      }
      return this;
    }
  }, {
    key: 'updateBindingData',
    value: function updateBindingData(part) {
      var _this = this;

      var templates = this.templates;
      for (var i = 0, n = templates.length; i < n; i++) {
        var temp = templates[i];
        if (!part || part == temp) {
          var template = selector('[data-id=\'' + temp + '\']');
          var binds = template.querySelectorAll('[data-bind]');
          [].forEach.call(binds, function (item) {
            var data = _this.getDataByString(item.getAttribute("data-bind"));
            if (item.getAttribute("type") === "checkbox" || item.getAttribute("type") === "radio") {
              if (data == item.value) {
                item.checked = true;
              }
            } else {
              item.value = data;
            }
          });
          if (part) {
            break;
          }
        }
      }
      return this;
    }
  }, {
    key: 'applyMethod',
    value: function applyMethod(method) {
      var args = [].splice.call(arguments, 0);
      args.shift();
      return this.method[method].apply(this, args);
    }
  }, {
    key: 'getComputedProp',
    value: function getComputedProp(prop) {
      return this.data[prop].apply(this);
    }
  }, {
    key: 'remove',
    value: function remove(path) {
      var object = this.data;
      var stack = path.split('.');
      while (stack.length > 1) {
        object = object[stack.shift()];
      }
      var shift = stack.shift();
      if (shift.match(/^\d+$/)) {
        object.splice(Number(shift), 1);
      } else {
        delete object[shift];
      }
      return this;
    }
  }]);

  return aTemplate;
}();

module.exports = aTemplate;

},{"delegate":3,"morphdom":4}],2:[function(require,module,exports){
var DOCUMENT_NODE_TYPE = 9;

/**
 * A polyfill for Element.matches()
 */
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
    var proto = Element.prototype;

    proto.matches = proto.matchesSelector ||
                    proto.mozMatchesSelector ||
                    proto.msMatchesSelector ||
                    proto.oMatchesSelector ||
                    proto.webkitMatchesSelector;
}

/**
 * Finds the closest parent that matches a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @return {Function}
 */
function closest (element, selector) {
    while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
        if (element.matches(selector)) return element;
        element = element.parentNode;
    }
}

module.exports = closest;

},{}],3:[function(require,module,exports){
var closest = require('./closest');

/**
 * Delegates event to a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @param {Boolean} useCapture
 * @return {Object}
 */
function delegate(element, selector, type, callback, useCapture) {
    var listenerFn = listener.apply(this, arguments);

    element.addEventListener(type, listenerFn, useCapture);

    return {
        destroy: function() {
            element.removeEventListener(type, listenerFn, useCapture);
        }
    }
}

/**
 * Finds closest match and invokes callback.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @return {Function}
 */
function listener(element, selector, type, callback) {
    return function(e) {
        e.delegateTarget = closest(e.target, selector);

        if (e.delegateTarget) {
            callback.call(element, e);
        }
    }
}

module.exports = delegate;

},{"./closest":2}],4:[function(require,module,exports){
'use strict';

var range; // Create a range object for efficently rendering strings to elements.
var NS_XHTML = 'http://www.w3.org/1999/xhtml';

var doc = typeof document === 'undefined' ? undefined : document;

var testEl = doc ?
    doc.body || doc.createElement('div') :
    {};

// Fixes <https://github.com/patrick-steele-idem/morphdom/issues/32>
// (IE7+ support) <=IE7 does not support el.hasAttribute(name)
var actualHasAttributeNS;

if (testEl.hasAttributeNS) {
    actualHasAttributeNS = function(el, namespaceURI, name) {
        return el.hasAttributeNS(namespaceURI, name);
    };
} else if (testEl.hasAttribute) {
    actualHasAttributeNS = function(el, namespaceURI, name) {
        return el.hasAttribute(name);
    };
} else {
    actualHasAttributeNS = function(el, namespaceURI, name) {
        return el.getAttributeNode(namespaceURI, name) != null;
    };
}

var hasAttributeNS = actualHasAttributeNS;


function toElement(str) {
    if (!range && doc.createRange) {
        range = doc.createRange();
        range.selectNode(doc.body);
    }

    var fragment;
    if (range && range.createContextualFragment) {
        fragment = range.createContextualFragment(str);
    } else {
        fragment = doc.createElement('body');
        fragment.innerHTML = str;
    }
    return fragment.childNodes[0];
}

/**
 * Returns true if two node's names are the same.
 *
 * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same
 *       nodeName and different namespace URIs.
 *
 * @param {Element} a
 * @param {Element} b The target element
 * @return {boolean}
 */
function compareNodeNames(fromEl, toEl) {
    var fromNodeName = fromEl.nodeName;
    var toNodeName = toEl.nodeName;

    if (fromNodeName === toNodeName) {
        return true;
    }

    if (toEl.actualize &&
        fromNodeName.charCodeAt(0) < 91 && /* from tag name is upper case */
        toNodeName.charCodeAt(0) > 90 /* target tag name is lower case */) {
        // If the target element is a virtual DOM node then we may need to normalize the tag name
        // before comparing. Normal HTML elements that are in the "http://www.w3.org/1999/xhtml"
        // are converted to upper case
        return fromNodeName === toNodeName.toUpperCase();
    } else {
        return false;
    }
}

/**
 * Create an element, optionally with a known namespace URI.
 *
 * @param {string} name the element name, e.g. 'div' or 'svg'
 * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of
 * its `xmlns` attribute or its inferred namespace.
 *
 * @return {Element}
 */
function createElementNS(name, namespaceURI) {
    return !namespaceURI || namespaceURI === NS_XHTML ?
        doc.createElement(name) :
        doc.createElementNS(namespaceURI, name);
}

/**
 * Copies the children of one DOM element to another DOM element
 */
function moveChildren(fromEl, toEl) {
    var curChild = fromEl.firstChild;
    while (curChild) {
        var nextChild = curChild.nextSibling;
        toEl.appendChild(curChild);
        curChild = nextChild;
    }
    return toEl;
}

function morphAttrs(fromNode, toNode) {
    var attrs = toNode.attributes;
    var i;
    var attr;
    var attrName;
    var attrNamespaceURI;
    var attrValue;
    var fromValue;

    for (i = attrs.length - 1; i >= 0; --i) {
        attr = attrs[i];
        attrName = attr.name;
        attrNamespaceURI = attr.namespaceURI;
        attrValue = attr.value;

        if (attrNamespaceURI) {
            attrName = attr.localName || attrName;
            fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);

            if (fromValue !== attrValue) {
                fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
            }
        } else {
            fromValue = fromNode.getAttribute(attrName);

            if (fromValue !== attrValue) {
                fromNode.setAttribute(attrName, attrValue);
            }
        }
    }

    // Remove any extra attributes found on the original DOM element that
    // weren't found on the target element.
    attrs = fromNode.attributes;

    for (i = attrs.length - 1; i >= 0; --i) {
        attr = attrs[i];
        if (attr.specified !== false) {
            attrName = attr.name;
            attrNamespaceURI = attr.namespaceURI;

            if (attrNamespaceURI) {
                attrName = attr.localName || attrName;

                if (!hasAttributeNS(toNode, attrNamespaceURI, attrName)) {
                    fromNode.removeAttributeNS(attrNamespaceURI, attrName);
                }
            } else {
                if (!hasAttributeNS(toNode, null, attrName)) {
                    fromNode.removeAttribute(attrName);
                }
            }
        }
    }
}

function syncBooleanAttrProp(fromEl, toEl, name) {
    if (fromEl[name] !== toEl[name]) {
        fromEl[name] = toEl[name];
        if (fromEl[name]) {
            fromEl.setAttribute(name, '');
        } else {
            fromEl.removeAttribute(name, '');
        }
    }
}

var specialElHandlers = {
    /**
     * Needed for IE. Apparently IE doesn't think that "selected" is an
     * attribute when reading over the attributes using selectEl.attributes
     */
    OPTION: function(fromEl, toEl) {
        syncBooleanAttrProp(fromEl, toEl, 'selected');
    },
    /**
     * The "value" attribute is special for the <input> element since it sets
     * the initial value. Changing the "value" attribute without changing the
     * "value" property will have no effect since it is only used to the set the
     * initial value.  Similar for the "checked" attribute, and "disabled".
     */
    INPUT: function(fromEl, toEl) {
        syncBooleanAttrProp(fromEl, toEl, 'checked');
        syncBooleanAttrProp(fromEl, toEl, 'disabled');

        if (fromEl.value !== toEl.value) {
            fromEl.value = toEl.value;
        }

        if (!hasAttributeNS(toEl, null, 'value')) {
            fromEl.removeAttribute('value');
        }
    },

    TEXTAREA: function(fromEl, toEl) {
        var newValue = toEl.value;
        if (fromEl.value !== newValue) {
            fromEl.value = newValue;
        }

        var firstChild = fromEl.firstChild;
        if (firstChild) {
            // Needed for IE. Apparently IE sets the placeholder as the
            // node value and vise versa. This ignores an empty update.
            var oldValue = firstChild.nodeValue;

            if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {
                return;
            }

            firstChild.nodeValue = newValue;
        }
    },
    SELECT: function(fromEl, toEl) {
        if (!hasAttributeNS(toEl, null, 'multiple')) {
            var selectedIndex = -1;
            var i = 0;
            var curChild = toEl.firstChild;
            while(curChild) {
                var nodeName = curChild.nodeName;
                if (nodeName && nodeName.toUpperCase() === 'OPTION') {
                    if (hasAttributeNS(curChild, null, 'selected')) {
                        selectedIndex = i;
                        break;
                    }
                    i++;
                }
                curChild = curChild.nextSibling;
            }

            fromEl.selectedIndex = i;
        }
    }
};

var ELEMENT_NODE = 1;
var TEXT_NODE = 3;
var COMMENT_NODE = 8;

function noop() {}

function defaultGetNodeKey(node) {
    return node.id;
}

function morphdomFactory(morphAttrs) {

    return function morphdom(fromNode, toNode, options) {
        if (!options) {
            options = {};
        }

        if (typeof toNode === 'string') {
            if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML') {
                var toNodeHtml = toNode;
                toNode = doc.createElement('html');
                toNode.innerHTML = toNodeHtml;
            } else {
                toNode = toElement(toNode);
            }
        }

        var getNodeKey = options.getNodeKey || defaultGetNodeKey;
        var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
        var onNodeAdded = options.onNodeAdded || noop;
        var onBeforeElUpdated = options.onBeforeElUpdated || noop;
        var onElUpdated = options.onElUpdated || noop;
        var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
        var onNodeDiscarded = options.onNodeDiscarded || noop;
        var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
        var childrenOnly = options.childrenOnly === true;

        // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.
        var fromNodesLookup = {};
        var keyedRemovalList;

        function addKeyedRemoval(key) {
            if (keyedRemovalList) {
                keyedRemovalList.push(key);
            } else {
                keyedRemovalList = [key];
            }
        }

        function walkDiscardedChildNodes(node, skipKeyedNodes) {
            if (node.nodeType === ELEMENT_NODE) {
                var curChild = node.firstChild;
                while (curChild) {

                    var key = undefined;

                    if (skipKeyedNodes && (key = getNodeKey(curChild))) {
                        // If we are skipping keyed nodes then we add the key
                        // to a list so that it can be handled at the very end.
                        addKeyedRemoval(key);
                    } else {
                        // Only report the node as discarded if it is not keyed. We do this because
                        // at the end we loop through all keyed elements that were unmatched
                        // and then discard them in one final pass.
                        onNodeDiscarded(curChild);
                        if (curChild.firstChild) {
                            walkDiscardedChildNodes(curChild, skipKeyedNodes);
                        }
                    }

                    curChild = curChild.nextSibling;
                }
            }
        }

        /**
         * Removes a DOM node out of the original DOM
         *
         * @param  {Node} node The node to remove
         * @param  {Node} parentNode The nodes parent
         * @param  {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.
         * @return {undefined}
         */
        function removeNode(node, parentNode, skipKeyedNodes) {
            if (onBeforeNodeDiscarded(node) === false) {
                return;
            }

            if (parentNode) {
                parentNode.removeChild(node);
            }

            onNodeDiscarded(node);
            walkDiscardedChildNodes(node, skipKeyedNodes);
        }

        // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future
        // function indexTree(root) {
        //     var treeWalker = document.createTreeWalker(
        //         root,
        //         NodeFilter.SHOW_ELEMENT);
        //
        //     var el;
        //     while((el = treeWalker.nextNode())) {
        //         var key = getNodeKey(el);
        //         if (key) {
        //             fromNodesLookup[key] = el;
        //         }
        //     }
        // }

        // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future
        //
        // function indexTree(node) {
        //     var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);
        //     var el;
        //     while((el = nodeIterator.nextNode())) {
        //         var key = getNodeKey(el);
        //         if (key) {
        //             fromNodesLookup[key] = el;
        //         }
        //     }
        // }

        function indexTree(node) {
            if (node.nodeType === ELEMENT_NODE) {
                var curChild = node.firstChild;
                while (curChild) {
                    var key = getNodeKey(curChild);
                    if (key) {
                        fromNodesLookup[key] = curChild;
                    }

                    // Walk recursively
                    indexTree(curChild);

                    curChild = curChild.nextSibling;
                }
            }
        }

        indexTree(fromNode);

        function handleNodeAdded(el) {
            onNodeAdded(el);

            var curChild = el.firstChild;
            while (curChild) {
                var nextSibling = curChild.nextSibling;

                var key = getNodeKey(curChild);
                if (key) {
                    var unmatchedFromEl = fromNodesLookup[key];
                    if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
                        curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
                        morphEl(unmatchedFromEl, curChild);
                    }
                }

                handleNodeAdded(curChild);
                curChild = nextSibling;
            }
        }

        function morphEl(fromEl, toEl, childrenOnly) {
            var toElKey = getNodeKey(toEl);
            var curFromNodeKey;

            if (toElKey) {
                // If an element with an ID is being morphed then it is will be in the final
                // DOM so clear it out of the saved elements collection
                delete fromNodesLookup[toElKey];
            }

            if (toNode.isSameNode && toNode.isSameNode(fromNode)) {
                return;
            }

            if (!childrenOnly) {
                if (onBeforeElUpdated(fromEl, toEl) === false) {
                    return;
                }

                morphAttrs(fromEl, toEl);
                onElUpdated(fromEl);

                if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
                    return;
                }
            }

            if (fromEl.nodeName !== 'TEXTAREA') {
                var curToNodeChild = toEl.firstChild;
                var curFromNodeChild = fromEl.firstChild;
                var curToNodeKey;

                var fromNextSibling;
                var toNextSibling;
                var matchingFromEl;

                outer: while (curToNodeChild) {
                    toNextSibling = curToNodeChild.nextSibling;
                    curToNodeKey = getNodeKey(curToNodeChild);

                    while (curFromNodeChild) {
                        fromNextSibling = curFromNodeChild.nextSibling;

                        if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
                            curToNodeChild = toNextSibling;
                            curFromNodeChild = fromNextSibling;
                            continue outer;
                        }

                        curFromNodeKey = getNodeKey(curFromNodeChild);

                        var curFromNodeType = curFromNodeChild.nodeType;

                        var isCompatible = undefined;

                        if (curFromNodeType === curToNodeChild.nodeType) {
                            if (curFromNodeType === ELEMENT_NODE) {
                                // Both nodes being compared are Element nodes

                                if (curToNodeKey) {
                                    // The target node has a key so we want to match it up with the correct element
                                    // in the original DOM tree
                                    if (curToNodeKey !== curFromNodeKey) {
                                        // The current element in the original DOM tree does not have a matching key so
                                        // let's check our lookup to see if there is a matching element in the original
                                        // DOM tree
                                        if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {
                                            if (curFromNodeChild.nextSibling === matchingFromEl) {
                                                // Special case for single element removals. To avoid removing the original
                                                // DOM node out of the tree (since that can break CSS transitions, etc.),
                                                // we will instead discard the current node and wait until the next
                                                // iteration to properly match up the keyed target element with its matching
                                                // element in the original tree
                                                isCompatible = false;
                                            } else {
                                                // We found a matching keyed element somewhere in the original DOM tree.
                                                // Let's moving the original DOM node into the current position and morph
                                                // it.

                                                // NOTE: We use insertBefore instead of replaceChild because we want to go through
                                                // the `removeNode()` function for the node that is being discarded so that
                                                // all lifecycle hooks are correctly invoked
                                                fromEl.insertBefore(matchingFromEl, curFromNodeChild);

                                                fromNextSibling = curFromNodeChild.nextSibling;

                                                if (curFromNodeKey) {
                                                    // Since the node is keyed it might be matched up later so we defer
                                                    // the actual removal to later
                                                    addKeyedRemoval(curFromNodeKey);
                                                } else {
                                                    // NOTE: we skip nested keyed nodes from being removed since there is
                                                    //       still a chance they will be matched up later
                                                    removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
                                                }

                                                curFromNodeChild = matchingFromEl;
                                            }
                                        } else {
                                            // The nodes are not compatible since the "to" node has a key and there
                                            // is no matching keyed node in the source tree
                                            isCompatible = false;
                                        }
                                    }
                                } else if (curFromNodeKey) {
                                    // The original has a key
                                    isCompatible = false;
                                }

                                isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
                                if (isCompatible) {
                                    // We found compatible DOM elements so transform
                                    // the current "from" node to match the current
                                    // target DOM node.
                                    morphEl(curFromNodeChild, curToNodeChild);
                                }

                            } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
                                // Both nodes being compared are Text or Comment nodes
                                isCompatible = true;
                                // Simply update nodeValue on the original node to
                                // change the text value
                                curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
                            }
                        }

                        if (isCompatible) {
                            // Advance both the "to" child and the "from" child since we found a match
                            curToNodeChild = toNextSibling;
                            curFromNodeChild = fromNextSibling;
                            continue outer;
                        }

                        // No compatible match so remove the old node from the DOM and continue trying to find a
                        // match in the original DOM. However, we only do this if the from node is not keyed
                        // since it is possible that a keyed node might match up with a node somewhere else in the
                        // target tree and we don't want to discard it just yet since it still might find a
                        // home in the final DOM tree. After everything is done we will remove any keyed nodes
                        // that didn't find a home
                        if (curFromNodeKey) {
                            // Since the node is keyed it might be matched up later so we defer
                            // the actual removal to later
                            addKeyedRemoval(curFromNodeKey);
                        } else {
                            // NOTE: we skip nested keyed nodes from being removed since there is
                            //       still a chance they will be matched up later
                            removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
                        }

                        curFromNodeChild = fromNextSibling;
                    }

                    // If we got this far then we did not find a candidate match for
                    // our "to node" and we exhausted all of the children "from"
                    // nodes. Therefore, we will just append the current "to" node
                    // to the end
                    if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
                        fromEl.appendChild(matchingFromEl);
                        morphEl(matchingFromEl, curToNodeChild);
                    } else {
                        var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
                        if (onBeforeNodeAddedResult !== false) {
                            if (onBeforeNodeAddedResult) {
                                curToNodeChild = onBeforeNodeAddedResult;
                            }

                            if (curToNodeChild.actualize) {
                                curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
                            }
                            fromEl.appendChild(curToNodeChild);
                            handleNodeAdded(curToNodeChild);
                        }
                    }

                    curToNodeChild = toNextSibling;
                    curFromNodeChild = fromNextSibling;
                }

                // We have processed all of the "to nodes". If curFromNodeChild is
                // non-null then we still have some from nodes left over that need
                // to be removed
                while (curFromNodeChild) {
                    fromNextSibling = curFromNodeChild.nextSibling;
                    if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {
                        // Since the node is keyed it might be matched up later so we defer
                        // the actual removal to later
                        addKeyedRemoval(curFromNodeKey);
                    } else {
                        // NOTE: we skip nested keyed nodes from being removed since there is
                        //       still a chance they will be matched up later
                        removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
                    }
                    curFromNodeChild = fromNextSibling;
                }
            }

            var specialElHandler = specialElHandlers[fromEl.nodeName];
            if (specialElHandler) {
                specialElHandler(fromEl, toEl);
            }
        } // END: morphEl(...)

        var morphedNode = fromNode;
        var morphedNodeType = morphedNode.nodeType;
        var toNodeType = toNode.nodeType;

        if (!childrenOnly) {
            // Handle the case where we are given two DOM nodes that are not
            // compatible (e.g. <div> --> <span> or <div> --> TEXT)
            if (morphedNodeType === ELEMENT_NODE) {
                if (toNodeType === ELEMENT_NODE) {
                    if (!compareNodeNames(fromNode, toNode)) {
                        onNodeDiscarded(fromNode);
                        morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
                    }
                } else {
                    // Going from an element node to a text node
                    morphedNode = toNode;
                }
            } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node
                if (toNodeType === morphedNodeType) {
                    morphedNode.nodeValue = toNode.nodeValue;
                    return morphedNode;
                } else {
                    // Text node to something else
                    morphedNode = toNode;
                }
            }
        }

        if (morphedNode === toNode) {
            // The "to node" was not compatible with the "from node" so we had to
            // toss out the "from node" and use the "to node"
            onNodeDiscarded(fromNode);
        } else {
            morphEl(morphedNode, toNode, childrenOnly);

            // We now need to loop over any keyed nodes that might need to be
            // removed. We only do the removal if we know that the keyed node
            // never found a match. When a keyed node is matched up we remove
            // it out of fromNodesLookup and we use fromNodesLookup to determine
            // if a keyed node has been matched up or not
            if (keyedRemovalList) {
                for (var i=0, len=keyedRemovalList.length; i<len; i++) {
                    var elToRemove = fromNodesLookup[keyedRemovalList[i]];
                    if (elToRemove) {
                        removeNode(elToRemove, elToRemove.parentNode, false);
                    }
                }
            }
        }

        if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
            if (morphedNode.actualize) {
                morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
            }
            // If we had to swap out the from node with a new node because the old
            // node was not compatible with the target node then we need to
            // replace the old DOM node in the original DOM tree. This is only
            // possible if the original DOM node was part of a DOM tree which
            // we know is the case if it has a parent node.
            fromNode.parentNode.replaceChild(morphedNode, fromNode);
        }

        return morphedNode;
    };
}

var morphdom = morphdomFactory(morphAttrs);

module.exports = morphdom;

},{}],5:[function(require,module,exports){
'use strict';

var smartPhoto = require('../index');

var applyJQuery = function applyJQuery(jQuery) {
  jQuery.fn.smartPhoto = function (selector,settings) {
    if (typeof settings === 'strings') {} else {
      selector = this.selector?this.selector:selector;
      new smartPhoto(selector, settings);
    }
    return this;
  };
};

if (typeof define === 'function' && define.amd) {
  define(['jquery'], applyJQuery);
} else {
  var jq = window.jQuery ? window.jQuery : window.$;
  if (typeof jq !== 'undefined') {
    applyJQuery(jq);
  }
}

module.exports = applyJQuery;

},{"../index":7}],6:[function(require,module,exports){
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _aTemplate2 = require('a-template');

var _aTemplate3 = _interopRequireDefault(_aTemplate2);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var template = '<div class="\\{classNames.smartPhoto\\}"<!-- BEGIN hide:exist --> aria-hidden="true"<!-- END hide:exist --><!-- BEGIN hide:empty --> aria-hidden="false"<!-- END hide:empty --> role="dialog">\n\t<div class="\\{classNames.smartPhotoBody\\}">\n\t\t<div class="\\{classNames.smartPhotoInner\\}">\n\t\t\t   <div class="\\{classNames.smartPhotoHeader\\}">\n\t\t\t\t\t<span class="\\{classNames.smartPhotoCount\\}">{currentIndex}[increment]/{total}</span>\n\t\t\t\t\t<span class="\\{classNames.smartPhotoCaption\\}" aria-live="polite" tabindex="-1"><!-- BEGIN groupItems:loop --><!-- \\BEGIN currentIndex:touch#{index} -->{caption}<!-- \\END currentIndex:touch#{index} --><!-- END groupItems:loop --></span>\n\t\t\t\t\t<button class="\\{classNames.smartPhotoDismiss\\}" data-action-click="hidePhoto()"><span class="smartphoto-sr-only">\\{message.closeDialog\\}</span></button>\n\t\t\t\t</div>\n\t\t\t\t<div class="\\{classNames.smartPhotoContent\\}"<!-- BEGIN isSmartPhone:exist --> data-action-touchstart="beforeDrag" data-action-touchmove="onDrag" data-action-touchend="afterDrag(false)"<!-- END isSmartPhone:exist -->>\n\t\t\t\t</div>\n\t\t\t\t<ul style="transform:translate({translateX}px,{translateY}px);" class="\\{classNames.smartPhotoList\\}<!-- BEGIN onMoveClass:exist --> \\{classNames.smartPhotoListOnMove\\}<!-- END onMoveClass:exist -->">\n\t\t\t\t\t<!-- BEGIN groupItems:loop -->\n\t\t\t\t\t<li style="transform:translate({translateX}px,{translateY}px);" class="<!-- \\BEGIN currentIndex:touch#{index} -->current<!-- \\END currentIndex:touch#{index} -->">\n\t\t\t\t\t\t<!-- BEGIN processed:exist -->\n\t\t\t\t\t\t<div style="transform:translate({x}px,{y}px) scale({scale});" class="\\\\{classNames.smartPhotoImgWrap\\\\}"<!-- \\BEGIN isSmartPhone:empty --> data-action-mousedown="beforeDrag" data-action-click="onDrag" data-action-mouseup="afterDrag" data-action-mousemove="onDrag"<!-- \\END isSmartPhone:empty --><!-- \\BEGIN isSmartPhone:exist --> data-action-touchstart="beforeDrag" data-action-touchend="afterDrag" data-action-touchmove="onDrag"<!-- \\END isSmartPhone:exist -->>\n\t\t\t\t\t\t\t<img style="<!-- \\BEGIN currentIndex:touch#{index} -->transform:translate(0px,0px) scale(1);<!-- \\END currentIndex:touch#{index} -->" src="{src}" class="\\\\{classNames.smartPhotoImg\\\\}<!-- \\BEGIN scale:exist -->  \\\\{classNames.smartPhotoImgOnMove\\\\}<!-- \\END scale:exist --><!-- \\BEGIN elastic:exist --> \\\\{classNames.smartPhotoImgElasticMove\\\\}<!-- \\END elastic:exist --><!-- \\BEGIN appear:exist --> active<!-- \\END appear:exist -->" onclick="return false;" ondragstart="return false;">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- END processed:exist -->\n\t\t\t\t\t\t<!-- BEGIN processed:empty -->\n\t\t\t\t\t\t<div class="\\\\{classNames.smartPhotoLoaderWrap\\\\}">\n\t\t\t\t\t\t\t<span class="\\\\{classNames.smartPhotoLoader\\\\}"></span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- END processed:empty -->\n\t\t\t\t\t</li>\n\t\t\t\t\t<!-- END groupItems:loop -->\n\t\t\t\t</ul>\n\t\t\t\t<!-- BEGIN arrows:exist -->\n\t\t\t\t<ul class="\\{classNames.smartPhotoArrows\\}"<!-- BEGIN hideUi:exist --> aria-hidden="true"<!-- END hideUi:exist --><!-- BEGIN hideUi:exist --> aria-hidden="false"<!-- END hideUi:exist -->>\n\t\t\t\t\t<li class="\\{classNames.smartPhotoArrowLeft\\}"<!-- BEGIN showPrevArrow:empty --> aria-hidden="true"<!-- END showPrevArrow:empty -->><a href="#" data-action-click="gotoSlide({prev})" role="button"><span class="smartphoto-sr-only">\\{message.gotoPrevImage\\}</span></a></li>\n\t\t\t\t\t<li class="\\{classNames.smartPhotoArrowRight\\}"<!-- BEGIN showNextArrow:empty --> aria-hidden="true"<!-- END showNextArrow:empty -->><a href="#" data-action-click="gotoSlide({next})" role="button"><span class="smartphoto-sr-only">\\{message.gotoNextImage\\}</span></a></li>\n\t\t\t\t</ul>\n\t\t\t\t<!-- END arrows:exist -->\n\t\t\t\t<!-- BEGIN nav:exist -->\n\t\t\t\t<nav class="\\{classNames.smartPhotoNav\\}"<!-- BEGIN hideUi:exist --> aria-hidden="true"<!-- END hideUi:exist --><!-- BEGIN hideUi:exist --> aria-hidden="false"<!-- END hideUi:exist -->>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<!-- BEGIN groupItems:loop -->\n\t\t\t\t\t\t<li><a href="#" data-action-click="gotoSlide({index})" class="<!-- \\BEGIN currentIndex:touch#{index} -->current<!-- \\END currentIndex:touch#{index} -->" style="background-image:url({src});" role="button"><span class="smartphoto-sr-only">go to {caption}</span></a></li>\n\t\t\t\t\t\t<!-- END groupItems:loop -->\n\t\t\t\t\t</ul>\n\t\t\t\t</nav>\n\t\t\t\t<!-- END nav:exist -->\n\t\t</div>\n\t\t<!-- BEGIN appearEffect:exist -->\n\t\t<img src=\\{appearEffect.img\\}\n\t\tclass="\\{classNames.smartPhotoImgClone\\}"\n\t\tstyle="width:\\{appearEffect.width\\}px;height:\\{appearEffect.height\\}px;transform:translate(\\{appearEffect.left\\}px,\\{appearEffect.top\\}px) scale(1)" />\n\t\t<!-- END appearEffect:exist -->\n\t</div>\n</div>\n';


var util = require('../lib/util');

var defaults = {
  classNames: {
    smartPhoto: 'smartphoto',
    smartPhotoClose: 'smartphoto-close',
    smartPhotoBody: 'smartphoto-body',
    smartPhotoInner: 'smartphoto-inner',
    smartPhotoContent: 'smartphoto-content',
    smartPhotoImg: 'smartphoto-img',
    smartPhotoImgOnMove: 'smartphoto-img-onmove',
    smartPhotoImgElasticMove: 'smartphoto-img-elasticmove',
    smartPhotoImgWrap: 'smartphoto-img-wrap',
    smartPhotoArrows: 'smartphoto-arrows',
    smartPhotoNav: 'smartphoto-nav',
    smartPhotoArrowRight: 'smartphoto-arrow-right',
    smartPhotoArrowLeft: 'smartphoto-arrow-left',
    smartPhotoImgLeft: 'smartphoto-img-left',
    smartPhotoImgRight: 'smartphoto-img-right',
    smartPhotoList: 'smartphoto-list',
    smartPhotoListOnMove: 'smartphoto-list-onmove',
    smartPhotoHeader: 'smartphoto-header',
    smartPhotoCount: 'smartphoto-count',
    smartPhotoCaption: 'smartphoto-caption',
    smartPhotoDismiss: 'smartphoto-dismiss',
    smartPhotoLoader: 'smartphoto-loader',
    smartPhotoLoaderWrap: 'smartphoto-loader-wrap',
    smartPhotoImgClone: 'smartphoto-img-clone'
  },
  message: {
    gotoNextImage: 'go to the next image',
    gotoPrevImage: 'go to the previous image',
    closeDialog: 'close the image dialog'
  },
  arrows: true,
  nav: true,
  animationSpeed: 300,
  swipeOffset: 100,
  headerHeight: 60,
  footerHeight: 60,
  forceInterval: 10,
  registance: 0.5,
  resizeStyle: 'fill',
  verticalGravity: false,
  useOrientationApi: true
};

var smartPhoto = function (_aTemplate) {
  _inherits(smartPhoto, _aTemplate);

  function smartPhoto(selector, settings) {
    _classCallCheck(this, smartPhoto);

    var _this = _possibleConstructorReturn(this, (smartPhoto.__proto__ || Object.getPrototypeOf(smartPhoto)).call(this));

    _this.data = util.extend({}, defaults, settings);
    _this.data.currentIndex = 0;
    _this.data.oldIndex = 0;
    _this.data.hide = true;
    _this.data.group = {};
    _this.data.scaleSize = 1;
    _this.data.scale = false;
    _this.pos = { x: 0, y: 0 };
    _this.data.photoPosX = 0;
    _this.data.photoPosY = 0;
    _this.convert = {
      increment: _this.increment,
      virtualPos: _this.virtualPos
    };
    _this.data.groupItems = _this.groupItems;
    _this.elements = document.querySelectorAll(selector);
    var date = new Date();
    _this.tapSecond = date.getTime();
    _this.onListMove = false;
    _this.clicked = false;
    _this.id = _this._getUniqId();
    _this.vx = 0;
    _this.vy = 0;
    _this.data.appearEffect = null;
    _this.addTemplate(_this.id, template);
    _this.data.isSmartPhone = _this._isSmartPhone();
    var body = document.querySelector('body');
    util.append(body, '<div data-id=\'' + _this.id + '\'></div>');
    [].forEach.call(_this.elements, function (element) {
      _this.addNewItem(element);
    });

    var currentItem = _this._getCurrentItemByHash();
    if (currentItem) {
      util.triggerEvent(currentItem.element, 'click');
    }

    _this.update();
    _this._getEachImageSize().then(function () {
      _this._fireEvent('loadall');
    });

    if (!_this.data.isSmartPhone) {
      window.addEventListener('resize', function () {
        _this._resetTranslate();
        _this._setPosByCurrentIndex();
        _this._setSizeByScreen();
        _this.update();
      });

      window.addEventListener('keydown', function (e) {
        var code = e.keyCode || e.which;
        if (_this.data.hide === true) {
          return;
        }
        if (code === 37) {
          _this.gotoSlide(_this.data.prev);
        } else if (code === 39) {
          _this.gotoSlide(_this.data.next);
        } else if (code === 27) {
          _this.hidePhoto();
        }
      });
      return _possibleConstructorReturn(_this);
    }

    window.addEventListener('orientationchange', function () {
      _this._resetTranslate();
      _this._setPosByCurrentIndex();
      _this._setHashByCurrentIndex();
      _this._setSizeByScreen();
      _this.update();
    });

    if (!_this.data.useOrientationApi) {
      return _possibleConstructorReturn(_this);
    }

    return _this;
  }

  _createClass(smartPhoto, [{
    key: 'on',
    value: function on(event, fn) {
      var _this2 = this;

      var photo = this._getElementByClass(this.data.classNames.smartPhoto);
      photo.addEventListener(event, function (e) {
        fn.call(_this2, e);
      });
    }
  }, {
    key: 'increment',
    value: function increment(item) {
      return item + 1;
    }
  }, {
    key: 'virtualPos',
    value: function virtualPos(pos) {
      pos = parseInt(pos, 10);
      var item = this._getSelectedItem();
      // return pos / item.scale / this.data.scaleSize;
      return pos / this.data.scaleSize;
    }
  }, {
    key: 'groupItems',
    value: function groupItems() {
      return this.data.group[this.data.currentGroup];
    }
  }, {
    key: '_getEachImageSize',
    value: function _getEachImageSize() {
      var arr = [];
      var group = this.data.group;
      var loadItems = function loadItems(item) {
        var promise = new Promise(function (resolve, reject) {
          var img = new Image();
          img.onload = function () {
            item.width = img.width;
            item.height = img.height;
            item.loaded = true;
            resolve();
          };
          img.onerror = function () {
            reject();
          };
          img.src = item.src;
        });
        arr.push(promise);
      };
      Object.keys(group).forEach(function (key) {
        group[key].forEach(loadItems);
      });
      return Promise.all(arr);
    }
  }, {
    key: '_resetTranslate',
    value: function _resetTranslate() {
      var _this3 = this;

      var items = this.groupItems();
      items.forEach(function (item, index) {
        item.translateX = _this3._getWindowWidth() * index;
      });
    }
  }, {
    key: 'addNewItem',
    value: function addNewItem(element) {
      var _this4 = this;

      var groupId = element.getAttribute('data-group') || 'nogroup';
      var group = this.data.group;
      if (groupId === 'nogroup') {
        element.setAttribute('data-group', 'nogroup');
      }
      if (!group[groupId]) {
        group[groupId] = [];
      }
      var index = group[groupId].length;
      var item = {
        src: element.getAttribute('href'),
        caption: element.getAttribute('data-caption'),
        groupId: groupId,
        translateX: this._getWindowWidth() * index,
        index: index,
        translateY: 0,
        width: 50,
        height: 50,
        id: element.getAttribute('data-id') || index,
        loaded: false,
        processed: false,
        element: element
      };
      group[groupId].push(item);
      this.data.currentGroup = groupId;
      var id = element.getAttribute('data-id');
      if (!id) {
        element.setAttribute('data-id', index);
      }
      element.setAttribute('data-index', index);
      element.addEventListener('click', function (event) {
        event.preventDefault();
        _this4.data.currentGroup = element.getAttribute('data-group');
        _this4.data.currentIndex = parseInt(element.getAttribute('data-index'), 10);
        _this4._setHashByCurrentIndex();
        var currentItem = _this4._getSelectedItem();
        if (currentItem.loaded) {
          _this4._initPhoto();
          _this4.addAppearEffect(element);
          _this4.clicked = true;
          _this4.update();
          _this4._fireEvent('open');
        } else {
          _this4._loadItem(currentItem).then(function () {
            _this4._initPhoto();
            _this4.addAppearEffect(element);
            _this4.clicked = true;
            _this4.update();
            _this4._fireEvent('open');
          });
        }
      });
    }
  }, {
    key: '_initPhoto',
    value: function _initPhoto() {
      this.data.total = this.groupItems().length;
      this.data.hide = false;
      this.data.photoPosX = 0;
      this.data.photoPosY = 0;
      this._setPosByCurrentIndex();
      this._setSizeByScreen();
      this.setArrow();
      if (this.data.resizeStyle === 'fill' && this.data.isSmartPhone) {
        this.data.scale = true;
        this.data.hideUi = true;
        this.data.scaleSize = this._getScaleBoarder();
      }
    }
  }, {
    key: 'onUpdated',
    value: function onUpdated() {
      var _this5 = this;

      if (this.data.appearEffect && this.data.appearEffect.once) {
        this.data.appearEffect.once = false;
        this.execEffect().then(function () {
          _this5.data.appearEffect = null;
          _this5.data.appear = true;
          _this5.update();
        });
      }
      if (this.clicked) {
        this.clicked = false;
        var classNames = this.data.classNames;
        var caption = this._getElementByClass(classNames.smartPhotoCaption);
        caption.focus();
      }
    }
  }, {
    key: 'execEffect',
    value: function execEffect() {
      var _this6 = this;

      return new Promise(function (resolve) {
        var appearEffect = _this6.data.appearEffect;
        var classNames = _this6.data.classNames;
        var effect = _this6._getElementByClass(classNames.smartPhotoImgClone);
        var handler = function handler() {
          effect.removeEventListener('transitionend', handler, true);
          resolve();
        };
        effect.addEventListener('transitionend', handler, true);
        setTimeout(function () {
          effect.style.transform = 'translate(' + appearEffect.afterX + 'px, ' + appearEffect.afterY + 'px) scale(' + appearEffect.scale + ')';
        }, 10);
      });
    }
  }, {
    key: 'addAppearEffect',
    value: function addAppearEffect(element) {
      var img = element.querySelector('img');
      var pos = util.getViewPos(img);
      var appear = {};
      var scale = 1;
      appear.width = img.offsetWidth;
      appear.height = img.offsetHeight;
      appear.top = pos.top;
      appear.left = pos.left;
      appear.once = true;
      appear.img = img.getAttribute('src');
      var windowX = this._getWindowWidth();
      var windowY = this._getWindowHeight();
      var screenY = windowY - this.data.headerHeight - this.data.footerHeight;
      if (this.data.resizeStyle === 'fill' && this.data.isSmartPhone) {
        if (img.offsetWidth > img.offsetHeight) {
          scale = windowY / img.offsetHeight;
        } else {
          scale = windowX / img.offsetWidth;
        }
      } else {
        scale = screenY / img.offsetHeight;
        if (scale * img.offsetWidth > windowX) {
          scale = windowX / img.offsetWidth;
        }
      }
      var x = (scale - 1) / 2 * img.offsetWidth + (windowX - img.offsetWidth * scale) / 2;
      var y = (scale - 1) / 2 * img.offsetHeight + (windowY - img.offsetHeight * scale) / 2;
      appear.afterX = x;
      appear.afterY = y;
      appear.scale = scale;
      this.data.appearEffect = appear;
    }
  }, {
    key: 'hidePhoto',
    value: function hidePhoto() {
      var _this7 = this;

      this.data.hide = true;
      this.data.appear = false;
      this.data.appearEffect = null;
      this.data.hideUi = false;
      this.data.scale = false;
      this.data.scaleSize = 1;
      var scrollX = window.scrollX;
      var scrollY = window.scrollY;
      if (location.hash) {
        this._setHash('');
      }
      window.scroll(scrollX, scrollY);
      this._doHideEffect().then(function () {
        _this7.update();
        _this7._fireEvent('close');
      });
    }
  }, {
    key: '_doHideEffect',
    value: function _doHideEffect() {
      var _this8 = this;

      return new Promise(function (resolve) {
        var classNames = _this8.data.classNames;
        var photo = _this8._getElementByClass(classNames.smartPhoto);
        var img = _this8._getElementByQuery('.current .' + classNames.smartPhotoImg);
        var height = _this8._getWindowHeight();
        var handler = function handler() {
          photo.removeEventListener('transitionend', handler, true);
          resolve();
        };
        photo.style.opacity = 0;
        img.style.transform = 'translateY(' + height + 'px)';
        photo.addEventListener('transitionend', handler, true);
      });
    }
  }, {
    key: '_getElementByClass',
    value: function _getElementByClass(className) {
      return document.querySelector('[data-id="' + this.id + '"] .' + className);
    }
  }, {
    key: '_getElementByQuery',
    value: function _getElementByQuery(query) {
      return document.querySelector('[data-id="' + this.id + '"] ' + query);
    }
  }, {
    key: '_getTouchPos',
    value: function _getTouchPos() {
      var x = 0;
      var y = 0;
      var e = typeof event === 'undefined' ? this.e : event;
      if (this._isTouched(e)) {
        x = e.touches[0].pageX;
        y = e.touches[0].pageY;
      } else if (e.pageX) {
        x = e.pageX;
        y = e.pageY;
      }
      return { x: x, y: y };
    }
  }, {
    key: '_getGesturePos',
    value: function _getGesturePos(e) {
      var touches = e.touches;
      return [{ x: touches[0].pageX, y: touches[0].pageY }, { x: touches[1].pageX, y: touches[1].pageY }];
    }
  }, {
    key: '_setPosByCurrentIndex',
    value: function _setPosByCurrentIndex() {
      var _this9 = this;

      var items = this.groupItems();
      var moveX = -1 * items[this.data.currentIndex].translateX;
      this.pos.x = moveX;
      setTimeout(function () {
        _this9.data.translateX = moveX;
        _this9.data.translateY = 0;
        _this9._listUpdate();
      }, 1);
    }
  }, {
    key: '_setHashByCurrentIndex',
    value: function _setHashByCurrentIndex() {
      var scrollX = window.scrollX;
      var scrollY = window.scrollY;
      var items = this.groupItems();
      var id = items[this.data.currentIndex].id;
      var group = this.data.currentGroup;
      var hash = 'group=' + group + '&photo=' + id;
      this._setHash(hash);
      window.scroll(scrollX, scrollY);
    }
  }, {
    key: '_setHash',
    value: function _setHash(hash) {
      if (!(window.history && window.history.pushState)) {
        return;
      }
      if (hash) {
        window.history.replaceState(null, null, location.pathname + '#' + hash);
      } else {
        window.history.replaceState(null, null, '' + location.pathname);
      }
    }
  }, {
    key: '_getCurrentItemByHash',
    value: function _getCurrentItemByHash() {
      var group = this.data.group;
      var hash = location.hash.substr(1);
      var hashObj = util.parseQuery(hash);
      var currentItem = null;
      var getCurrentItem = function getCurrentItem(item) {
        if (hashObj.group === item.groupId && hashObj.photo === item.id) {
          currentItem = item;
        }
      };
      Object.keys(group).forEach(function (key) {
        group[key].forEach(getCurrentItem);
      });
      return currentItem;
    }
  }, {
    key: '_loadItem',
    value: function _loadItem(item) {
      return new Promise(function (resolve) {
        var img = new Image();
        img.onload = function () {
          item.width = img.width;
          item.height = img.height;
          item.loaded = true;
          resolve();
        };
        img.onerror = function () {
          resolve();
        };
        img.src = item.src;
      });
    }
  }, {
    key: '_setSizeByScreen',
    value: function _setSizeByScreen() {
      var windowX = this._getWindowWidth();
      var windowY = this._getWindowHeight();
      var headerHeight = this.data.headerHeight;
      var footerHeight = this.data.footerHeight;
      var screenY = windowY - (headerHeight + footerHeight);
      var items = this.groupItems();
      items.forEach(function (item) {
        if (!item.loaded) {
          return;
        }
        item.processed = true;
        item.scale = screenY / item.height;
        item.x = (item.scale - 1) / 2 * item.width + (windowX - item.width * item.scale) / 2;
        item.y = (item.scale - 1) / 2 * item.height + (windowY - item.height * item.scale) / 2;
        if (item.width * item.scale > windowX) {
          item.scale = windowX / item.width;
          item.x = (item.scale - 1) / 2 * item.width;
        }
      });
    }
  }, {
    key: '_slideList',
    value: function _slideList() {
      var _this10 = this;

      this.data.scaleSize = 1;
      this.isBeingZoomed = false;
      this.data.hideUi = false;
      this.data.scale = false;
      this.data.photoPosX = 0;
      this.data.photoPosY = 0;
      this.data.onMoveClass = true;
      this._setPosByCurrentIndex();
      this._setHashByCurrentIndex();
      this._setSizeByScreen();
      setTimeout(function () {
        _this10.data.onMoveClass = false;
        _this10.setArrow();
        _this10.update();
        if (_this10.data.oldIndex !== _this10.data.currentIndex) {
          _this10._fireEvent('change');
        }
        _this10.data.oldIndex = _this10.data.currentIndex;
      }, 200);
    }
  }, {
    key: 'gotoSlide',
    value: function gotoSlide(index) {
      if (this.e && this.e.preventDefault) {
        this.e.preventDefault();
      }
      this.data.currentIndex = parseInt(index, 10);
      if (!this.data.currentIndex) {
        this.data.currentIndex = 0;
      }
      this._slideList();
    }
  }, {
    key: 'setArrow',
    value: function setArrow() {
      var items = this.groupItems();
      var length = items.length;
      var next = this.data.currentIndex + 1;
      var prev = this.data.currentIndex - 1;
      this.data.showNextArrow = false;
      this.data.showPrevArrow = false;
      if (next !== length) {
        this.data.next = next;
        this.data.showNextArrow = true;
      }
      if (prev !== -1) {
        this.data.prev = prev;
        this.data.showPrevArrow = true;
      }
    }
  }, {
    key: 'beforeDrag',
    value: function beforeDrag() {
      if (this._isGestured(this.e)) {
        this.beforeGesture();
        return;
      }
      this.isBeingZoomed = false;
      if (this.data.scale) {
        this.beforePhotoDrag();
        return;
      }
      var pos = this._getTouchPos();
      this.isSwipable = true;
      this.dragStart = true;
      this.firstPos = pos;
      this.oldPos = pos;
    }
  }, {
    key: 'afterDrag',
    value: function afterDrag() {
      var items = this.groupItems();
      var date = new Date();
      var tapSecond = date.getTime();
      var offset = this.tapSecond - tapSecond;
      var swipeWidth = 0;
      var swipeHeight = 0;
      this.isSwipable = false;
      this.onListMove = false;

      if (this.oldPos) {
        swipeWidth = this.oldPos.x - this.firstPos.x;
        swipeHeight = this.oldPos.y - this.firstPos.y;
      }
      if (this.isBeingZoomed) {
        this.afterGesture();
        return;
      }
      if (this.data.scale) {
        this.afterPhotoDrag();
        return;
      } else if (!util.isSmartPhone() && swipeWidth === 0 && swipeHeight === 0) {
        this.zoomPhoto();
        return;
      }
      if (Math.abs(offset) <= 500 && swipeWidth === 0 && swipeHeight === 0) {
        this.e.preventDefault();
        this.zoomPhoto();
        return;
      }
      this.tapSecond = tapSecond;
      this._fireEvent('swipeend');
      if (this.moveDir === 'horizontal') {
        if (swipeWidth >= this.data.swipeOffset && this.data.currentIndex !== 0) {
          this.data.currentIndex -= 1;
        } else if (swipeWidth <= -this.data.swipeOffset && this.data.currentIndex !== items.length - 1) {
          this.data.currentIndex += 1;
        }
        this._slideList();
      }
      if (this.moveDir === 'vertical') {
        if (swipeHeight >= this.data.swipeOffset) {
          this.hidePhoto();
        } else {
          this.data.translateY = 0;
          this._slideList();
        }
      }
    }
  }, {
    key: 'onDrag',
    value: function onDrag() {
			if(this.data.largeScale){
				this.e.preventDefault();
				if (this._isGestured(this.e) && this.onListMove === false) {
					this.onGesture();
					return;
				}
				if (this.isBeingZoomed) {
					return;
				}
				if (this.data.scale) {
					this.onPhotoDrag();
					return;
				}
				if (!this.isSwipable) {
					return;
				}
	
				var pos = this._getTouchPos();
				var x = pos.x - this.oldPos.x;
				var y = pos.y - this.firstPos.y;
	
				if (this.dragStart) {
					this._fireEvent('swipestart');
					this.dragStart = false;
					if (Math.abs(x) > Math.abs(y)) {
						this.moveDir = 'horizontal';
					} else {
						this.moveDir = 'vertical';
					}
				}
	
				if (this.moveDir === 'horizontal') {
					this.pos.x += x;
					this.data.translateX = this.pos.x;
				} else {
					this.data.translateY = y;
				}
				this.onListMove = true;
				this.oldPos = pos;
				this._listUpdate();
			}

    }
  }, {
    key: 'zoomPhoto',
    value: function zoomPhoto() {
      var _this11 = this;
      this.data.hideUi = true;
      this.data.scaleSize = this._getScaleBoarder();
      this.data.photoPosX = 0;
      this.data.photoPosY = 0;
			this.data.largeScale = true;
      this._photoUpdate();
      setTimeout(function () {
        _this11.data.scale = true;
        _this11._photoUpdate();
        _this11._fireEvent('zoomin');
      }, 300);
    }
  }, {
    key: 'zoomOutPhoto',
    value: function zoomOutPhoto() {
      this.data.scaleSize = 1;
      this.isBeingZoomed = false;
      this.data.hideUi = false;
      this.data.scale = false;
			this.data.largeScale = false;
      this.data.photoPosX = 0;
      this.data.photoPosY = 0;
      this._photoUpdate();
      this._fireEvent('zoomout');
    }
  }, {
    key: 'beforePhotoDrag',
    value: function beforePhotoDrag() {
      var pos = this._getTouchPos();
      this.photoSwipable = true;
      if (!this.data.photoPosX) {
        this.data.photoPosX = 0;
      }
      if (!this.data.photoPosY) {
        this.data.photoPosY = 0;
      }
      this.oldPhotoPos = pos;
      this.firstPhotoPos = pos;
    }
  }, {
    key: 'onPhotoDrag',
    value: function onPhotoDrag() {
      if (!this.photoSwipable) {
        return;
      }
      this.e.preventDefault();
      var pos = this._getTouchPos();
      var x = pos.x - this.oldPhotoPos.x;
      var y = pos.y - this.oldPhotoPos.y;
      var moveX = this._round(this.data.scaleSize * x, 6);
      var moveY = this._round(this.data.scaleSize * y, 6);
      if (typeof moveX === 'number') {
        this.data.photoPosX += moveX;
        this.photoVX = moveX;
      }
      if (typeof moveY === 'number') {
        this.data.photoPosY += moveY;
        this.photoVY = moveY;
      }
      this.oldPhotoPos = pos;
      // this._photoUpdate();
    }
  }, {
    key: 'afterPhotoDrag',
    value: function afterPhotoDrag() {
      if (this.oldPhotoPos.x === this.firstPhotoPos.x && this.photoSwipable) {
        this.photoSwipable = false;
        this.zoomOutPhoto();
      } else {
        this.photoSwipable = false;
        var item = this._getSelectedItem();
        var bound = this._makeBound(item);
        var offset = this.data.swipeOffset * this.data.scaleSize;
        var flagX = 0;
        var flagY = 0;
        if (this.data.photoPosX > bound.maxX) {
          flagX = -1;
        } else if (this.data.photoPosX < bound.minX) {
          flagX = 1;
        }
        if (this.data.photoPosY > bound.maxY) {
          flagY = -1;
        } else if (this.data.photoPosY < bound.minY) {
          flagY = 1;
        }

        if (this.data.photoPosX - bound.maxX > offset && this.data.currentIndex !== 0) {
          this.gotoSlide(this.data.prev);
          return;
        }

        if (bound.minX - this.data.photoPosX > offset && this.data.currentIndex + 1 !== this.data.total) {
          this.gotoSlide(this.data.next);
          return;
        }

        // todo
        // if(this.data.photoPosY - bound.maxY > offset) {
        //   this.hidePhoto();
        //   return;
        // }

        if (flagX === 0 && flagY === 0) {
          this.vx = this.photoVX / 5;
          this.vy = this.photoVY / 5;
        } else {
          this._registerElasticForce(flagX, flagY);
        }
      }
    }
  }, {
    key: 'beforeGesture',
    value: function beforeGesture() {
      this._fireEvent('gesturestart');
      var pos = this._getGesturePos(this.e);
      var distance = this._getDistance(pos[0], pos[1]);
      this.isBeingZoomed = true;
      this.oldDistance = distance;
      this.data.scale = true;
      this.e.preventDefault();
    }
  }, {
    key: 'onGesture',
    value: function onGesture() {
      var pos = this._getGesturePos(this.e);
      var distance = this._getDistance(pos[0], pos[1]);
      var size = (distance - this.oldDistance) / 100;
      var oldScaleSize = this.data.scaleSize;
      var posX = this.data.photoPosX;
      var posY = this.data.photoPosY;
      this.isBeingZoomed = true;
      this.data.scaleSize += this._round(size, 6);
      if (this.data.scaleSize < 0.2) {
        this.data.scaleSize = 0.2;
      }
      // todo
      if (this.data.scaleSize < oldScaleSize) {
        this.data.photoPosX = (1 + this.data.scaleSize - oldScaleSize) * posX+50;
        this.data.photoPosY = (1 + this.data.scaleSize - oldScaleSize) * posY+50;
      }

      if (this.data.scaleSize < 1 || this.data.scaleSize > this._getScaleBoarder()) {
        this.data.hideUi = true;
      } else {
        this.data.hideUi = false;
      }
      this.oldDistance = distance;
      this.e.preventDefault();
      this._photoUpdate();
    }
  }, {
    key: 'afterGesture',
    value: function afterGesture() {
      if (this.data.scaleSize > this._getScaleBoarder()) {
        return;
      }
      this.data.photoPosX = 0;
      this.data.photoPosY = 0;
      this.data.scale = false;
      this.data.scaleSize = 1;
      this.data.hideUi = false;
      this._fireEvent('gestureend');
      // this._photoUpdate();
    }
  }, {
    key: '_getForceAndTheta',
    value: function _getForceAndTheta(vx, vy) {
      return {
        force: Math.sqrt(vx * vx + vy * vy),
        theta: Math.atan2(vy, vx)
      };
    }
  }, {
    key: '_getScaleBoarder',
    value: function _getScaleBoarder() {
      var item = this._getSelectedItem();
      var windowWidth = this._getWindowWidth();
      var windowHeight = this._getWindowHeight();
      if (!util.isSmartPhone()) {
        return 1 / item.scale;
      }
      if (item.width > item.height) {
        return windowHeight / (item.height * item.scale);
      }
      return windowWidth / (item.width * item.scale);
    }
  }, {
    key: '_makeBound',
    value: function _makeBound(item) {
      var width = item.width * item.scale * this.data.scaleSize;
      var height = item.height * item.scale * this.data.scaleSize;
      var minX = void 0;
      var minY = void 0;
      var maxX = void 0;
      var maxY = void 0;
      var windowWidth = this._getWindowWidth();
      var windowHeight = this._getWindowHeight();
      if (windowWidth > width) {
        maxX = (windowWidth - width) / 2;
        minX = -1 * maxX;
      } else {
        maxX = (width - windowWidth) / 2;
        minX = -1 * maxX;
      }
      if (windowHeight > height) {
        maxY = (windowHeight - height) / 2;
        minY = -1 * maxY;
      } else {
        maxY = (height - windowHeight) / 2;
        minY = -1 * maxY;
      }
      return {
        minX: this._round(minX, 6) * this.data.scaleSize,
        minY: this._round(minY, 6) * this.data.scaleSize,
        maxX: this._round(maxX, 6) * this.data.scaleSize,
        maxY: this._round(maxY, 6) * this.data.scaleSize
      };
    }
  }, {
    key: '_registerElasticForce',
    value: function _registerElasticForce(x, y) {
      var _this12 = this;

      var item = this._getSelectedItem();
      var bound = this._makeBound(item);
      this.data.elastic = true;
      if (x === 1) {
        this.data.photoPosX = bound.minX+100;
      } else if (x === -1) {
        this.data.photoPosX = bound.maxX+100;
      }
      if (y === 1) {
        this.data.photoPosY = bound.minY+100;
      } else if (y === -1) {
        this.data.photoPosY = bound.maxY+100;
      }
      this._photoUpdate();
      setTimeout(function () {
        _this12.data.elastic = false;
        _this12._photoUpdate();
      }, 300);
    }
  }, {
    key: '_getSelectedItem',
    value: function _getSelectedItem() {
      var data = this.data;
      var index = data.currentIndex;
      return data.group[data.currentGroup][index];
    }
  }, {
    key: '_getUniqId',
    value: function _getUniqId() {
      return (Date.now().toString(36) + Math.random().toString(36).substr(2, 5)).toUpperCase();
    }
  }, {
    key: '_getDistance',
    value: function _getDistance(point1, point2) {
      var x = point1.x - point2.x;
      var y = point1.y - point2.y;
      return Math.sqrt(x * x + y * y);
    }
  }, {
    key: '_round',
    value: function _round(val, precision) {
      var digit = Math.pow(10, precision);
      val *= digit;
      val = Math.round(val);
      val /= digit;
      return val;
    }
  }, {
    key: '_isTouched',
    value: function _isTouched(e) {
      if (e && e.touches) {
        return true;
      }
      return false;
    }
  }, {
    key: '_isGestured',
    value: function _isGestured(e) {
      if (e && e.touches && e.touches.length > 1) {
        return true;
      }
      return false;
    }
  }, {
    key: '_isSmartPhone',
    value: function _isSmartPhone() {
      var agent = navigator.userAgent;
      if (agent.indexOf('iPhone') > 0 || agent.indexOf('iPad') > 0 || agent.indexOf('ipod') > 0 || agent.indexOf('Android') > 0) {
        return true;
      }
      return false;
    }
  }, {
    key: '_calcGravity',
    value: function _calcGravity(gamma, beta) {
      if (gamma > 5 || gamma < -5) {
        this.vx += gamma * 0.05;
      }
      if (this.data.verticalGravity === false) {
        return;
      }
      if (beta > 5 || beta < -5) {
        this.vy += beta * 0.05;
      }
    }
  }, {
    key: '_photoUpdate',
    value: function _photoUpdate() {
      var classNames = this.data.classNames;
      var current = this._getElementByQuery('.current');
      var img = current.querySelector('.' + classNames.smartPhotoImg);
      var nav = this._getElementByQuery('.' + classNames.smartPhotoNav);
      var arrows = this._getElementByQuery('.' + classNames.smartPhotoArrows);
      var photoPosX = this.virtualPos(this.data.photoPosX);
      var photoPosY = this.virtualPos(this.data.photoPosY);
      var scaleSize = this.data.scaleSize;
      var transform = 'translate(' + photoPosX + '5px,' + photoPosY + '6px) scale(' + scaleSize + ')';

      img.style.transform = transform;
      if (this.data.scale) {
        util.addClass(img, classNames.smartPhotoImgOnMove);
      } else {
        util.removeClass(img, classNames.smartPhotoImgOnMove);
      }
      if (this.data.elastic) {
        util.addClass(img, classNames.smartPhotoImgElasticMove);
      } else {
        util.removeClass(img, classNames.smartPhotoImgElasticMove);
      }
      if (this.data.hideUi) {
        if (nav) {
          nav.setAttribute('aria-hidden', 'true');
        }
        if (arrows) {
          arrows.setAttribute('aria-hidden', 'true');
        }
      } else {
        if (nav) {
          nav.setAttribute('aria-hidden', 'false');
        }
        if (arrows) {
          arrows.setAttribute('aria-hidden', 'false');
        }
      }
    }
  }, {
    key: '_getWindowWidth',
    value: function _getWindowWidth() {
      // return document.documentElement.clientWidth;
      return 375; //宝盒默认
    }
  }, {
    key: '_getWindowHeight',
    value: function _getWindowHeight() {
      return window.innerHeight;
    }
  }, {
    key: '_listUpdate',
    value: function _listUpdate() {
      var classNames = this.data.classNames;
      var list = this._getElementByQuery('.' + classNames.smartPhotoList);
      var transform = 'translate(' + this.data.translateX + 'px,' + this.data.translateY + 'px)';
      list.style.transform = transform;
      // $list
      if (this.data.onMoveClass) {
        util.addClass(list, classNames.smartPhotoListOnMove);
      } else {
        util.removeClass(list, classNames.smartPhotoListOnMove);
      }
    }
  }, {
    key: '_fireEvent',
    value: function _fireEvent(eventName) {
      var photo = this._getElementByClass(this.data.classNames.smartPhoto);
      util.triggerEvent(photo, eventName);
    }
  }, {
    key: '_doAnim',
    value: function _doAnim() {
      if (this.isBeingZoomed || this.isSwipable || this.photoSwipable || this.data.elastic || !this.data.scale) {
        return;
      }
      this.data.photoPosX += this.vx;
      this.data.photoPosY += this.vy;
      var item = this._getSelectedItem();
      var bound = this._makeBound(item);
      if (this.data.photoPosX < bound.minX) {
        this.data.photoPosX = bound.minX+200;
        this.vx *= -0.2;
      } else if (this.data.photoPosX > bound.maxX) {
        this.data.photoPosX = bound.maxX+200;
        this.vx *= -0.2;
      }
      if (this.data.photoPosY < bound.minY) {
        this.data.photoPosY = bound.minY+200;
        this.vy *= -0.2;
      } else if (this.data.photoPosY > bound.maxY) {
        this.data.photoPosY = bound.maxY+200;
        this.vy *= -0.2;
      }
      var power = this._getForceAndTheta(this.vx, this.vy);
      var force = power.force;
      var theta = power.theta;
      force -= this.data.registance;
      if (Math.abs(force) < 0.5) {
        return;
      }
      this.vx = Math.cos(theta) * force;
      this.vy = Math.sin(theta) * force;
      this._photoUpdate();
    }
  }]);

  return smartPhoto;
}(_aTemplate3.default);

module.exports = smartPhoto;

},{"../lib/util":8,"a-template":1}],7:[function(require,module,exports){
'use strict';

module.exports = require('./core/');

},{"./core/":6}],8:[function(require,module,exports){
'use strict';

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

module.exports.isSmartPhone = function () {
  var agent = navigator.userAgent;
  if (agent.indexOf('iPhone') > 0 || agent.indexOf('iPad') > 0 || agent.indexOf('ipod') > 0 || agent.indexOf('Android') > 0) {
    return true;
  } else {
    return false;
  }
};

function deepExtend(out) {
  out = out || {};

  for (var i = 1; i < arguments.length; i++) {
    var obj = arguments[i];
    if (!obj) {
      continue;
    }

    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (_typeof(obj[key]) === 'object') out[key] = deepExtend(out[key], obj[key]);else out[key] = obj[key];
      }
    }
  }

  return out;
};

module.exports.extend = deepExtend;

module.exports.triggerEvent = function (el, eventName, options) {
  var event = void 0;
  if (window.CustomEvent) {
    event = new CustomEvent(eventName, { cancelable: true });
  } else {
    event = document.createEvent('CustomEvent');
    event.initCustomEvent(eventName, false, false, options);
  }
  el.dispatchEvent(event);
};

module.exports.parseQuery = function (query) {
  var s = query.split('&'),
      data = {},
      i = 0,
      iz = s.length,
      param,
      key,
      value;
  for (; i < iz; i++) {
    param = s[i].split('=');
    if (param[0] !== void 0) {
      key = param[0];
      value = param[1] !== void 0 ? param.slice(1).join('=') : key;
      data[key] = decodeURIComponent(value);
    }
  }
  return data;
};

module.exports.getViewPos = function (element) {
  return {
    left: element.getBoundingClientRect().left,
    top: element.getBoundingClientRect().top
  };
};

module.exports.removeElement = function (element) {
  if (element && element.parentNode) {
    element.parentNode.removeChild(element);
  }
};

module.exports.append = function (element, string) {
  var parser = new DOMParser();
  var doc = parser.parseFromString(string, 'text/html');
  element.appendChild(doc.querySelector('body').childNodes[0]);
};

module.exports.addClass = function (element, className) {
  if (element.classList) {
    element.classList.add(className);
  } else {
    element.className += ' ' + className;
  }
};

module.exports.removeClass = function (element, className) {
  if (element.classList) {
    element.classList.remove(className);
  } else {
    element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
  }
};

},{}]},{},[5]);
