/*!

* mdui v0.1.2 (http://mdui.org)
* Copyright 2016-2017 zdhxiong
* Licensed under MIT
*/

/* jshint ignore:start */ ;(function (window, document, undefined) {

'use strict';

/* jshint ignore:end */
var mdui = {};

/**
 * =============================================================================
 * ************   Dom 操作库   ************
 * =============================================================================
 *
 * Inspired by https://github.com/nolimits4web/Framework7
 * https://github.com/nolimits4web/Framework7/blob/master/LICENSE
 */
var $ = {};
(function () {

  /**
   * 是否是数组
   * @param arr
   * @returns {boolean}
   */
  $.isArray = function (arr) {
    return Object.prototype.toString.apply(arr) === '[object Array]';
  };

  /**
   * nodeList 转换为数组
   * @param nodeList
   * @returns {Array}
   */
  $.toArray = function (nodeList) {
    var i;
    var arr = [];
    for (i = 0; i < nodeList.length; i++) {
      if (nodeList[i]) {
        arr.push(nodeList[i]);
      }
    }

    return arr;
  };

  /**
   * 循环数组或对象
   * @param obj
   * @param callback
   */
  $.each = function (obj, callback) {
    var i;
    var prop;
    if (!obj) {
      return;
    }

    if ($.isArray(obj)) {
      // Array
      for (i = 0; i < obj.length; i++) {
        if (callback(i, obj[i]) === false) {
          break;
        }
      }
    } else {
      // Object
      for (prop in obj) {
        if (obj.hasOwnProperty(prop)) {
          if (callback(prop, obj[prop]) === false) {
            break;
          }
        }
      }
    }
  };

  /**
   * 去除数组中的重复值
   * @param arr
   * @returns {Array}
   */
  $.unique = function (arr) {
    var unique = [];
    for (var i = 0; i < arr.length; i++) {
      if (unique.indexOf(arr[i]) === -1) {
        unique.push(arr[i]);
      }
    }

    return unique;
  };

  var _queueData = [];
  /**
   * 写入队列
   * @param name 队列名
   * @param func 函数名,没有函数名时,返回所有队列
   */
  $.queue = function (name, func) {
    if (typeof _queueData[name] === 'undefined') {
      _queueData[name] = [];
    }

    if (typeof func === 'undefined') {
      return _queueData[name];
    }

    _queueData[name].push(func);
  };

  /**
   * 从队列中移除一个函数,并执行该函数
   * @param name 队列名
   */
  $.dequeue = function (name) {
    if (typeof _queueData[name] !== 'undefined' && _queueData[name].length) {
      (_queueData[name].shift())();
    }
  };

  /**
   * 合并参数
   * @param defaults
   * @param params
   * @returns {*}
   */
  $.extend = function (defaults, params) {
    $.each(defaults, function (key, value) {
      if (typeof params[key] === 'undefined') {
        params[key] = value;
      }
    });

    return params;
  };

  /**
   * 在 dom 元素上存储、读取数据
   * @param dom
   * @param key
   * @param value
   *
   * $.data(dom, key);          读取指定键名的数据
   * $.data(dom, key, value);   写入指定键名的数据
   * $.data(dom, key, null);    删除指定键名的数据
   * $.data(dom, object);       批量写入数据
   */
  $.data = function (dom, key, value) {
    if (!dom.mduiDomDataStorage) {
      dom.mduiDomDataStorage = {};
    }

    var dataStorage = dom.mduiDomDataStorage;

    if (typeof value === 'undefined') {

      // 读取单个数据
      if (typeof key === 'string') {
        if (key in dataStorage) {
          return dataStorage[key];
        } else {
          return null;
        }
      }

      // 批量写入数据
      else if (typeof key === 'object') {
        $.each(key, function (k, v) {
          dataStorage[k] = v;
        });
      }
    }

    // 删除数据
    else if (value === null) {
      if (dataStorage[key]) {
        dataStorage[key] = null;
        delete dataStorage[key];
      }
    }

    // 写入数据
    else {
      dataStorage[key] = value;
    }
  };

  /**
   * 获取元素的最终样式
   * @param dom
   * @param prop 可选
   * @returns {*}
   */
  $.getStyle = function (dom, prop) {
    var style = window.getComputedStyle(dom, null);
    if (arguments.length === 1) {
      return style;
    }

    return style.getPropertyValue(prop);
  };

  /**
   * 获取元素相对于 document 的偏移
   * @param dom
   * @returns {{top: number, left: number}}
   */
  $.offset = function (dom) {
    var box = dom.getBoundingClientRect();
    var body = document.body;
    var clientTop  = dom.clientTop  || body.clientTop  || 0;
    var clientLeft = dom.clientLeft || body.clientLeft || 0;
    var scrollTop  = window.pageYOffset || dom.scrollTop;
    var scrollLeft = window.pageXOffset || dom.scrollLeft;
    return {
      top: box.top  + scrollTop  - clientTop,
      left: box.left + scrollLeft - clientLeft,
    };
  };

  /**
   * 设置 transform 属性
   * @param dom
   * @param transform
   */
  $.transform = function (dom, transform) {
    dom.style.webkitTransform =
      dom.style.transform = transform;
  };

  /**
   * 设置 transform-origin 属性
   * @param dom
   * @param transformOrigin
   */
  $.transformOrigin = function (dom, transformOrigin) {
    dom.style.webkitTransformOrigin =
      dom.style.transformOrigin = transformOrigin;
  };

  /**
   * 设置 transition 过渡时间
   * @param dom
   * @param duration
   */
  $.transition = function (dom, duration) {
    if (typeof duration !== 'string') {
      duration = duration + 'ms';
    }

    dom.style.webkitTransitionDuration =
      dom.style.transitionDuration = duration;
  };

  /**
   * 执行 document.querySelectorAll,并把结果转换为数组
   * @param selector
   * @param parent
   * @returns {Array}
   */
  $.queryAll = function (selector, parent) {
    if (arguments.length === 1) {
      parent = document;
    }

    return $.toArray(parent.querySelectorAll(selector));
  };

  /**
   * 执行 document.querySelector
   * @param selector
   * @param parent
   * @returns {Element}
   */
  $.query = function (selector, parent) {
    if (arguments.length === 1) {
      parent = document;
    }

    return parent.querySelector(selector);
  };

  /**
   * 执行 document.getElementById
   * @param id
   * @param parent
   * @returns {Element}
   */
  $.queryId = function (id, parent) {
    if (arguments.length === 1) {
      parent = document;
    }

    return parent.getElementById(id);
  };

  /**
   * @param dom
   * @param selector
   * @returns {*}
   */
  $.is = function (dom, selector) {
    var compareWith;

    if (typeof selector === 'string') {
      if (dom === document) {
        return selector === document;
      }

      if (dom === window) {
        return selector === window;
      }

      if (dom.matches) {
        return dom.matches(selector);
      } else if (dom.webkitMatchesSelector) {
        return dom.webkitMatchesSelector(selector);
      } else if (dom.mozMatchesSelector) {
        return dom.mozMatchesSelector(selector);
      } else if (dom.msMatchesSelector) {
        return dom.msMatchesSelector(selector);
      } else {
        compareWith = $.queryAll(selector);
        return (compareWith.indexOf(dom) !== -1);
      }
    } else if (selector === document) {
      return dom === document;
    } else if (selector === window) {
      return dom === window;
    } else if (selector.nodeType) {
      return dom === selector;
    } else if (selector[0].nodeType) {
      compareWith = $.toArray(selector);
      return (compareWith.indexOf(dom) !== -1);
    }

    return false;
  };

  /**
   * 查找含有指定 css 选择器的父节点
   * @param dom
   * @param selector
   * @returns {*}
   */
  $.parent = function (dom, selector) {
    var parent = dom.parentNode;
    if (parent !== null) {
      if (selector) {
        if ($.is(parent, selector)) {
          return parent;
        }
      } else {
        return parent;
      }
    }

    return undefined;
  };

  /**
   * 查找含有指定选择器的所有父元素
   * @param dom
   * @param selector
   * @returns {Array}
   */
  $.parents = function (dom, selector) {
    var parents = [];
    var parent = dom.parentNode;
    while (parent) {
      if (selector) {
        if ($.is(parent, selector)) {
          parents.push(parent);
        }
      } else {
        parents.push(parent);
      }

      parent = parent.parentNode;
    }

    return $.unique(parents);
  };

  /**
   * dom 元素是否包含在 parent 元素内
   * @param parent
   * @param dom
   * @returns {boolean}
   */
  $.contains = function (parent, dom) {
    var tmp = dom.parentNode;
    while (tmp) {
      if ($.is(tmp, parent)) {
        return true;
      }

      tmp = tmp.parentNode;
    }

    return false;
  };

  /**
   * 设置 transition 动画时间
   * @param dom
   * @param duration
   */
  $.transition = function (dom, duration) {
    if (typeof duration !== 'string') {
      duration = duration + 'ms';
    }

    dom.style.webkitTransitionDuration = dom.style.transitionDuration = duration;
  };

  /**
   * 事件绑定
   * @param dom
   * @param eventName 多个事件用空格分割
   * @param targetSelector
   * @param listener
   * @param capture
   */
  $.on = function (dom, eventName, targetSelector, listener, capture) {
    // 处理委托事件
    function handleLiveEvent(e) {
      var target = e.target;
      if ($.is(target, targetSelector)) {
        listener.call(target, e);
      } else {
        var parents = $.parents(target);
        for (var k = 0; k < parents.length; k++) {
          if ($.is(parents[k], targetSelector)) {
            listener.call(parents[k], e);
          }
        }
      }
    }

    var events = eventName.split(' ');
    var i;
    if (typeof targetSelector === 'function' || targetSelector === false) {
      if (typeof targetSelector === 'function') {
        listener = arguments[2];
        capture = arguments[3] || false;
      }

      for (i = 0; i < events.length; i++) {
        dom.addEventListener(events[i], listener, capture);
      }
    } else {
      // Live events
      for (i = 0; i < events.length; i++) {
        if (!dom.domLiveListeners) {
          dom.domLiveListeners = [];
        }

        dom.domLiveListeners.push({ listener: listener, liveListener: handleLiveEvent });
        dom.addEventListener(events[i], handleLiveEvent, capture);
      }
    }
  };

  /**
   * 解除事件绑定
   * @param dom
   * @param eventName
   * @param targetSelector
   * @param listener
   * @param capture
   */
  $.off = function (dom, eventName, targetSelector, listener, capture) {
    var events = eventName.split(' ');
    for (var i = 0; i < events.length; i++) {
      if (typeof targetSelector === 'function') {
        listener = arguments[2];
        capture = arguments[3] || false;
        dom.removeEventListener(events[i], listener, capture);
      } else {
        // Live event
        if (dom.domLiveListeners) {
          for (var j = 0; j < dom.domLiveListeners.length; j++) {
            if (dom.domLiveListeners[j].listener === listener) {
              dom.removeEventListener(events[i], dom.domLiveListeners[j].liveListener, capture);
            }
          }
        }
      }
    }
  };

  /**
   * 事件绑定,只触发一次
   * @param dom
   * @param eventName
   * @param targetSelector
   * @param listener
   * @param capture
   * @returns {*}
   */
  $.one = function (dom, eventName, targetSelector, listener, capture) {
    if (typeof targetSelector === 'function') {
      listener = arguments[2];
      capture = arguments[3];
      targetSelector = false;
    }

    function proxy(e) {
      listener.call(e.target, e);
      $.off(dom, eventName, targetSelector, proxy, capture);
    }

    $.on(dom, eventName, targetSelector, proxy, capture);
  };

  /**
   * 触发事件
   * @param dom
   * @param eventName
   * @param eventData
   */
  $.trigger = function (dom, eventName, eventData) {
    var events = eventName.split(' ');
    for (var i = 0; i < events.length; i++) {
      var evt;
      try {
        evt = new CustomEvent(events[i], { detail: eventData, bubbles: true, cancelable: true });
      } catch (e) {
        evt = document.createEvent('Event');
        evt.initEvent(events[i], true, true);
        evt.detail = eventData;
      }

      dom.dispatchEvent(evt);
    }
  };

  /**
   * transition 动画结束回调
   * @param dom
   * @param callback
   */
  $.transitionEnd = function (dom, callback) {
    var events = [
      'webkitTransitionEnd',
      'transitionend',
    ];
    var i;
    function fireCallback(e) {
      if (e.target !== dom) {
        return;
      }

      callback.call(dom, e);
      for (i = 0; i < events.length; i++) {
        $.off(dom, events[i], fireCallback);
      }
    }

    if (callback) {
      for (i = 0; i < events.length; i++) {
        $.on(dom, events[i], fireCallback);
      }
    }
  };

  /**
   * 重绘
   * @param dom
   * @returns {number}
   */
  $.relayout = function (dom) {
    return dom.clientLeft;
  };

  $.requestAnimationFrame = function (callback) {
    var raf = window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame;
    if (raf) {
      return raf(callback);
    } else {
      return window.setTimeout(callback, 1000 / 60);
    }
  };

  $.cancelAnimationFrame = function (id) {
    var caf = window.cancelAnimationFrame ||
      window.webkitCancelAnimationFrame ||
      window.mozCancelAnimationFrame;
    if (caf) {
      return caf(id);
    } else {
      return window.clearTimeout(id);
    }
  };

  /**
   * 创建 Node 数组
   * @param selector 选择器或 html 字符串
   * @returns {Array}
   */
  $.dom = function (selector) {
    var tempParent;

    if (!selector) {
      return [];
    }

    // String
    if (typeof selector === 'string') {
      selector = selector.trim();
      if (selector.indexOf('<') >= 0 && selector.indexOf('>') >= 0) {
        // HTML
        var toCreate = 'div';
        if (selector.indexOf('<li') === 0) {
          toCreate = 'ul';
        }

        if (selector.indexOf('<tr') === 0) {
          toCreate = 'tbody';
        }

        if (selector.indexOf('<td') === 0 || selector.indexOf('<th') === 0) {
          toCreate = 'tr';
        }

        if (selector.indexOf('<tbody') === 0) {
          toCreate = 'table';
        }

        if (selector.indexOf('<option') === 0) {
          toCreate = 'select';
        }

        tempParent = document.createElement(toCreate);
        tempParent.innerHTML = selector;
        return $.toArray(tempParent.childNodes);
      } else {
        if (selector[0] === '#' &&  !selector.match(/[ .<>:~]/)) {
          // ID 选择器
          return [$.queryId(selector.split('#')[1])];
        } else {
          // 其他选择器
          return $.queryAll(selector);
        }
      }
    }

    // Node
    else if (selector.nodeType || selector === window || selector === document) {
      return [selector];
    }

    // Array of elements
    else if (selector.length > 0 && selector[0].nodeType) {
      return $.toArray(selector);
    }

    return [];
  };

  /**
   * 获取含指定 css 的直接子元素数组
   * @param dom
   * @param selector
   * @returns {Array}
   */
  $.children = function (dom, selector) {
    var children = [];
    var childNodes = dom.childNodes;

    if (!selector) {
      return $.toArray(childNodes);
    }

    for (var i = 0; i < childNodes.length; i++) {
      if (childNodes[i].nodeType === 1 && $.is(childNodes[i], selector)) {
        children.push(childNodes[i]);
      }
    }

    return children.length ? children : null;
  };

  /**
   * 获取含指定 css 的第一个直接子元素
   * @param dom
   * @param selector
   * @returns {*}
   */
  $.child = function (dom, selector) {
    var childNodes = dom.childNodes;

    if (!selector) {
      return childNodes[0];
    }

    for (var i = 0; i < childNodes.length; i++) {
      if (childNodes[i].nodeType === 1 && $.is(childNodes[i], selector)) {
        return childNodes[i];
      }
    }

    return null;
  };

  /**
   * 移除 dom 元素
   * @param dom
   */
  $.remove = function (dom) {
    if (dom) {
      dom.parentNode.removeChild(dom);
    }
  };

  /**
   * 移除 dom 元素中所有的子元素
   * @param dom
   */
  $.empty = function (dom) {
    if (!dom) {
      return;
    }

    if (dom.nodeType !== 1) {
      return;
    }

    for (var i = 0; i < dom.childNodes.length; i++) {
      $.remove(dom.childNodes[i]);
    }

    dom.textContent = '';
  };

  /**
   * 把 newChild 添加到 dom 元素内的最前面
   * @param dom
   * @param newChild
   */
  $.prepend = function (dom, newChild) {
    dom.insertBefore(newChild, dom.childNodes[0]);
  };

  /**
   * Dom 加载完毕后
   * @param fn
   */
  $.ready = function (fn) {
    document.addEventListener('DOMContentLoaded', function () {
      fn();
    });
  };

  /**
   * 解析 DATA API 参数
   * @param str
   * @returns {{}}
   */
  $.parseOptions = function (str) {
    var options = {};

    if (str === null || !str) {
      return options;
    }

    if (typeof str === 'object') {
      return str;
    }

    /* jshint ignore:start */
    var start = str.indexOf('{');
    try {
      options = (new Function('',
        'var json = ' + str.substr(start) +
        '; return JSON.parse(JSON.stringify(json));'))();
    } catch (e) {
    }
    /* jshint ignore:end */

    return options;
  };

  /**
   * 触发插件的事件
   * @param eventName 事件名
   * @param pluginName 插件名
   * @param inst 插件实例
   * @param trigger 在该元素上触发
   * @param obj 事件参数
   */
  $.pluginEvent = function (eventName, pluginName, inst, trigger, obj) {
    if (typeof obj === 'undefined') {
      obj = {};
    }

    obj.inst = inst;

    var fullEventName = eventName + '.mdui.' + pluginName;

    // jQuery 事件
    if (typeof jQuery !== 'undefined') {
      jQuery(trigger).trigger(fullEventName, obj);
    }

    // 原生js事件
    $.trigger(trigger, fullEventName, obj);
  };

})();

/**
 * =============================================================================
 * ************   检测支持的特性   ************
 * =============================================================================
 */

(function () {
  mdui.support = {
    touch: !!('ontouchstart' in window),
  };
})();

/**
 * 触摸或鼠标事件
 */
mdui.touchEvents = {
  start: mdui.support.touch ? 'touchstart' : 'mousedown',
  move: mdui.support.touch ? 'touchmove' : 'mousemove',
  end: mdui.support.touch ? 'touchend' : 'mouseup',
};

/**
 * 判断窗口大小
 */
mdui.screen = {
  xs: function () {
    return window.innerWidth < 600;
  },

  sm: function () {
    return window.innerWidth >= 600 && window.innerWidth < 1024;
  },

  md: function () {
    return window.innerWidth >= 1024 && window.innerWidth < 1440;
  },

  lg: function () {
    return window.innerWidth >= 1440 && window.innerWidth < 1920;
  },

  xl: function () {
    return window.innerWidth >= 1920;
  },

  xsDown: function () {
    return window.innerWidth < 600;
  },

  smDown: function () {
    return window.innerWidth < 1024;
  },

  mdDown: function () {
    return window.innerWidth < 1440;
  },

  lgDown: function () {
    return window.innerWidth < 1920;
  },

  xlDown: function () {
    return true;
  },

  xsUp: function () {
    return true;
  },

  smUp: function () {
    return window.innerWidth >= 600;
  },

  mdUp: function () {
    return window.innerWidth >= 1024;
  },

  lgUp: function () {
    return window.innerWidth >= 1440;
  },

  xlUp: function () {
    return window.innerWidth >= 1920;
  },

};

/**
 * 创建遮罩层并显示
 * @param zIndex 遮罩层的 z_index
 * @returns {Element}
 */
mdui.showOverlay = function (zIndex) {
  var overlay = $.dom('<div class="mdui-overlay">')[0];
  document.body.appendChild(overlay);

  $.relayout(overlay);

  if (typeof zIndex === 'undefined') {
    zIndex = 2000;
  }

  overlay.style['z-index'] = zIndex;
  overlay.classList.add('mdui-overlay-show');

  return overlay;
};

/**
 * 隐藏遮罩层
 * @param overlay 指定遮罩层元素,若没有该参数,则移除所有遮罩层
 */
mdui.hideOverlay = function (overlay) {
  var overlays;
  if (typeof overlay === 'undefined') {
    overlays = $.queryAll('.mdui-overlay');
  } else {
    overlays = [overlay];
  }

  $.each(overlays, function (i, overlay) {
    overlay.classList.remove('mdui-overlay-show');
    $.transitionEnd(overlay, function () {
      $.remove(overlay);
    });
  });
};

/**
 * 锁定屏幕
 */
mdui.lockScreen = function () {
  var body = document.body;
  var oldWindowWidth = body.clientWidth;

  // 不直接把 body 设为 box-sizing: border-box,避免污染全局样式
  var oldBodyPaddingLeft = parseFloat($.getStyle(body, 'padding-left'));
  var oldBodyPaddingRight = parseFloat($.getStyle(body, 'padding-right'));

  document.body.classList.add('mdui-locked');
  document.body.style.width = oldWindowWidth - oldBodyPaddingLeft - oldBodyPaddingRight + 'px';
};

/**
 * 解除屏幕锁定
 */
mdui.unlockScreen = function () {
  document.body.classList.remove('mdui-locked');
  document.body.style.width = '';
};

/**
 * 函数节流
 * @param fn
 * @param delay
 * @returns {Function}
 */
mdui.throttle = function (fn, delay) {
  var timer = null;

  return function () {
    var _this = this;
    var args = arguments;

    if (timer === null) {
      timer = setTimeout(function () {
        fn.apply(_this, args);
        timer = null;
      }, delay);
    }
  };
};

/**
 * 生成唯一 id
 * @param pluginName 插件名,若传入该参数,guid 将以该参数作为前缀
 * @returns {string}
 */
mdui.guid = function (pluginName) {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }

  var guid = s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
  if (pluginName) {
    guid = 'mdui-' + pluginName + '-' + guid;
  }

  return guid;
};

$.ready(function () {
  // 避免页面加载完后直接执行css动画
  // https://css-tricks.com/transitions-only-after-page-load/

  setTimeout(function () {
    document.body.classList.add('mdui-loaded');
  }, 0);

  // 支持触摸时在 body 添加 mdui-support-touch
  if (mdui.support.touch) {
    document.body.classList.add('mdui-support-touch');
  }

});

/**
 * =============================================================================
 * ************   Headroom.js   ************
 * =============================================================================
 */

mdui.Headroom = (function () {

  /**
   * 默认参数
   * @type {{}}
   */
  var DEFAULT = {
    tolerance: 5,                                // 滚动条滚动多少距离开始隐藏或显示元素,{down: num, up: num},或数字
    offset: 0,                                   // 在页面顶部多少距离内滚动不会隐藏元素
    initialClass: 'mdui-headroom',               // 初始化时添加的类
    pinnedClass: 'mdui-headroom-pinned-top',     // 元素固定时添加的类
    unpinnedClass: 'mdui-headroom-unpinned-top', // 元素隐藏时添加的类
  };

  /**
   * Headroom
   * @param selector
   * @param opts
   * @constructor
   */
  function Headroom(selector, opts) {
    var _this = this;

    _this.headroom = $.dom(selector)[0];
    if (typeof _this.headroom === 'undefined') {
      return;
    }

    // 已通过自定义属性实例化过,不再重复实例化
    var oldInst = $.data(_this.headroom, 'mdui.headroom');
    if (oldInst) {
      return oldInst;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));

    // 数值转为 {down: bum, up: num}
    var tolerance = _this.options.tolerance;
    if (tolerance !== Object(tolerance)) {
      _this.options.tolerance = {
        down: tolerance,
        up: tolerance,
      };
    }

    _this._init();
  }

  /**
   * 初始化
   * @private
   */
  Headroom.prototype._init = function () {
    var _this = this;

    _this.state = 'pinned';
    _this.headroom.classList.add(_this.options.initialClass);
    _this.headroom.classList.remove(
      _this.options.pinnedClass,
      _this.options.unpinnedClass
    );

    _this.inited = false;
    _this.lastScrollY = 0;

    _this._attachEvent();
  };

  /**
   * 监听滚动事件
   * @private
   */
  Headroom.prototype._attachEvent = function () {
    var _this = this;

    if (!_this.inited) {
      _this.lastScrollY = window.pageYOffset;
      _this.inited = true;
      $.on(window, 'scroll', function () {
        _this._scroll();
      });
    }
  };

  /**
   * 滚动时的处理
   * @private
   */
  Headroom.prototype._scroll = function () {
    var _this = this;
    _this.animationFrameId = $.requestAnimationFrame(function () {
      var currentScrollY = window.pageYOffset;
      var direction = currentScrollY > _this.lastScrollY ? 'down' : 'up';
      var toleranceExceeded =
        Math.abs(currentScrollY - _this.lastScrollY) >=
        _this.options.tolerance[direction];

      if (
        currentScrollY > _this.lastScrollY &&
        currentScrollY >= _this.options.offset &&
        toleranceExceeded) {
        _this.unpin();
      } else if (
        (currentScrollY < _this.lastScrollY && toleranceExceeded) ||
        currentScrollY <= _this.options.offset
      ) {
        _this.pin();
      }

      _this.lastScrollY = currentScrollY;
    });
  };

  /**
   * 固定住
   */
  Headroom.prototype.pin = function () {
    var _this = this;

    if (
      _this.state === 'pinning' ||
      _this.state === 'pinned' ||
      !_this.headroom.classList.contains(_this.options.initialClass)
    ) {
      return;
    }

    _this.state = 'pinning';
    _this.headroom.classList.remove(_this.options.unpinnedClass);
    _this.headroom.classList.add(_this.options.pinnedClass);
    $.pluginEvent('pin', 'headroom', _this, _this.headroom);

    $.transitionEnd(_this.headroom, function () {
      if (_this.state === 'pinning') {
        _this.state = 'pinned';
        $.pluginEvent('pinned', 'headroom', _this, _this.headroom);
      }
    });
  };

  /**
   * 不固定住
   */
  Headroom.prototype.unpin = function () {
    var _this = this;

    if (
      _this.state === 'unpinning' ||
      _this.state === 'unpinned' ||
      !_this.headroom.classList.contains(_this.options.initialClass)
    ) {
      return;
    }

    _this.state = 'unpinning';
    _this.headroom.classList.remove(_this.options.pinnedClass);
    _this.headroom.classList.add(_this.options.unpinnedClass);
    $.pluginEvent('unpin', 'headroom', _this, _this.headroom);

    $.transitionEnd(_this.headroom, function () {
      if (_this.state === 'unpinning') {
        _this.state = 'unpinned';
        $.pluginEvent('unpinned', 'headroom', _this, _this.headroom);
      }
    });
  };

  /**
   * 启用
   */
  Headroom.prototype.enable = function () {
    var _this = this;

    if (!_this.inited) {
      _this._init();
    }
  };

  /**
   * 禁用
   */
  Headroom.prototype.disable = function () {
    var _this = this;

    if (_this.inited) {
      _this.inited = false;
      _this.headroom.classList.remove(
        _this.options.initialClass,
        _this.options.pinnedClass,
        _this.options.unpinnedClass
      );
      $.off(window, 'scroll', function () {
        _this._scroll();
      });

      $.cancelAnimationFrame(_this.animationFrameId);
    }
  };

  /**
   * 获取当前状态 pinning | pinned | unpinning | unpinned
   */
  Headroom.prototype.getState = function () {
    return this.state;
  };

  return Headroom;

})();

/**
 * =============================================================================
 * ************   Headroom 自定义属性 API   ************
 * =============================================================================
 */

$.ready(function () {

  $.each($.queryAll('[mdui-headroom]'), function (i, target) {
    var options = $.parseOptions(target.getAttribute('mdui-headroom'));

    var inst = $.data(target, 'mdui.headroom');
    if (!inst) {
      inst = new mdui.Headroom(target, options);
      $.data(target, 'mdui.headroom', inst);
    }
  });
});

/**
 * =============================================================================
 * ************   供 Collapse、 Panel 调用的折叠内容块插件   ************
 * =============================================================================
 */
$.Collapse = (function () {

  /**
   * 默认参数
   */
  var DEFAULT = {
    accordion: false,                             // 是否使用手风琴效果
  };

  // 类名
  var CLASS = {
    item: 'mdui-collapse-item',           // item 类名
    itemOpen: 'mdui-collapse-item-open',  // 打开状态的 item
    header: 'mdui-collapse-item-header',  // item 中的 header 类名
    body: 'mdui-collapse-item-body',      // item 中的 body 类名
  };

  // 命名空间
  var NAMESPACE = 'collapse';

  /**
   * 折叠内容块
   * @param selector
   * @param opts
   * @param classes
   * @param namespace
   * @constructor
   */
  function Collapse(selector, opts, classes, namespace) {
    var _this = this;

    _this.classes = $.extend(CLASS, classes || {});
    _this.namespace = (typeof namespace === 'undefined' || !namespace) ? NAMESPACE : namespace;

    // 折叠面板元素
    _this.collapse = $.dom(selector)[0];
    if (typeof _this.collapse === 'undefined') {
      return;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));

    // 已通过自定义属性实例化过,不再重复实例化
    var oldInst = $.data(_this.collapse, 'mdui.' + _this.namespace);
    if (oldInst) {
      return oldInst;
    }

    $.on(_this.collapse, 'click', '.' + _this.classes.header, function (e) {
      var item = $.parent(this, '.' + _this.classes.item);
      if ($.child(_this.collapse, item)) {
        _this.toggle(item);
      }
    });
  }

  /**
   * 指定 item 是否处于打开状态
   * @param item
   * @returns {boolean}
   * @private
   */
  Collapse.prototype._isOpen = function (item) {
    return item.classList.contains(this.classes.itemOpen);
  };

  /**
   * 获取指定 item
   * @param item
   * @returns {*}
   * @private
   */
  Collapse.prototype._getItem = function (item) {
    var _this = this;

    if (parseInt(item) === item) {
      var items = $.children(_this.collapse, '.' + _this.classes.item);
      return items[item];
    }

    return $.dom(item)[0];
  };

  /**
   * 打开指定面板项
   * @param item 面板项的索引号或 DOM 元素或 CSS 选择器
   */
  Collapse.prototype.open = function (item) {
    var _this = this;
    item = _this._getItem(item);

    if (_this._isOpen(item)) {
      return;
    }

    // 关闭其他项
    if (_this.options.accordion) {
      $.each($.children(_this.collapse, '.' + _this.classes.itemOpen), function (i, temp) {
        if (temp !== item) {
          _this.close(temp);
        }
      });
    }

    var content = $.child(item, '.' + _this.classes.body);
    content.style.height = content.scrollHeight + 'px';

    $.transitionEnd(content, function () {
      if (_this._isOpen(item)) {
        $.transition(content, 0);
        content.style.height = 'auto';
        $.relayout(content);
        $.transition(content, '');
        $.pluginEvent('opened', _this.namespace, _this, item);
      } else {
        content.style.height = '';
      }
    });

    $.pluginEvent('open', _this.namespace, _this, item);
    item.classList.add(_this.classes.itemOpen);
  };

  /**
   * 关闭指定项
   * @param item 面板项的索引号或 DOM 元素或 CSS 选择器
   */
  Collapse.prototype.close = function (item) {
    var _this = this;
    item = _this._getItem(item);

    if (!_this._isOpen(item)) {
      return;
    }

    var content = $.child(item, '.' + _this.classes.body);
    item.classList.remove(_this.classes.itemOpen);
    $.transition(content, 0);
    content.style.height = content.scrollHeight + 'px';
    $.relayout(content);

    $.transition(content, '');
    content.style.height = '';
    $.pluginEvent('close', _this.namespace, _this, item);

    $.transitionEnd(content, function () {
      if (_this._isOpen(item)) {
        $.transition(content, 0);
        content.style.height = 'auto';
        $.relayout(content);
        $.transition(content, '');
      } else {
        content.style.height = '';
        $.pluginEvent('closed', _this.namespace, _this, item);
      }
    });
  };

  /**
   * 切换指定项的状态
   * @param item 面板项的索引号或 DOM 元素或 CSS 选择器
   */
  Collapse.prototype.toggle = function (item) {
    var _this = this;
    item = _this._getItem(item);

    if (_this._isOpen(item)) {
      _this.close(item);
    } else {
      _this.open(item);
    }
  };

  /**
   * 打开所有项
   */
  Collapse.prototype.openAll = function () {
    var _this = this;

    $.each($.children(_this.collapse, '.' + _this.classes.item), function (i, item) {
      if (!_this._isOpen(item)) {
        _this.open(item);
      }
    });
  };

  /**
   * 关闭所有项
   */
  Collapse.prototype.closeAll = function () {
    var _this = this;

    $.each($.children(_this.collapse, '.' + _this.classes.item), function (i, item) {
      if (_this._isOpen(item)) {
        _this.close(item);
      }
    });
  };

  return Collapse;
})();

/**
 * =============================================================================
 * ************   Collapse 折叠内容块插件   ************
 * =============================================================================
 */
mdui.Collapse = (function () {

  function Collapse(selector, opts) {
    return new $.Collapse(selector, opts);
  }

  return Collapse;
})();

/**
 * =============================================================================
 * ************   Collapse 自定义属性   ************
 * =============================================================================
 */

$.ready(function () {

  // 实例化插件
  $.each($.queryAll('[mdui-collapse]'), function (i, target) {
    var options = $.parseOptions(target.getAttribute('mdui-collapse'));

    var inst = $.data(target, 'mdui.collapse');
    if (!inst) {
      inst = new mdui.Collapse(target, options);
      $.data(target, 'mdui.collapse', inst);
    }
  });
});

/**
 * =============================================================================
 * ************   Table 表格   ************
 * =============================================================================
 */

(function () {

  /**
   * 生成 checkbox 的 HTML 结构
   * @param tag
   * @returns {string}
   */
  var checkboxHTML = function (tag) {
    return '<' + tag + ' class="mdui-table-cell-checkbox">' +
             '<label class="mdui-checkbox">' +
               '<input type="checkbox"/>' +
               '<i class="mdui-checkbox-icon"></i>' +
             '</label>' +
           '</' + tag + '>';
  };

  /**
   * Table 表格
   * @param selector
   * @constructor
   */
  function Table(selector) {
    var _this = this;
    _this.table = $.dom(selector)[0];
    _this.init();
  }

  /**
   * 初始化
   */
  Table.prototype.init = function () {
    var _this = this;

    _this.thRow = $.query('thead tr', _this.table);
    _this.tdRows = $.queryAll('tbody tr', _this.table);
    _this.tdCheckboxs = [];
    _this.selectable = _this.table.classList.contains('mdui-table-selectable');

    _this.updateTdCheckbox();
    _this.updateThCheckbox();
    _this.updateNumericCol();
  };

  /**
   * 更新表格行的 checkbox
   */
  Table.prototype.updateTdCheckbox = function () {
    var _this = this;
    var td;
    var tdCheckbox;
    _this.tdCheckboxs = [];

    $.each(_this.tdRows, function (i, tdRow) {
      // 移除旧的 checkbox
      tdCheckbox = $.query('.mdui-table-cell-checkbox', tdRow);
      if (tdCheckbox) {
        $.remove(tdCheckbox);
      }

      // 创建新的 checkbox
      if (_this.selectable) {
        // 创建 DOM
        td = $.dom(checkboxHTML('td'))[0];
        $.prepend(tdRow, td);

        var checkbox = $.query('input[type="checkbox"]', td);

        // 默认选中的行
        if (tdRow.classList.contains('mdui-table-row-selected')) {
          checkbox.checked = true;
        }

        // 绑定事件
        $.on(checkbox, 'change', function () {
          tdRow.classList[checkbox.checked ? 'add' : 'remove']('mdui-table-row-selected');
        });

        _this.tdCheckboxs.push(checkbox);
      }
    });
  };

  /**
   * 更新表头的 checkbox
   */
  Table.prototype.updateThCheckbox = function () {
    var _this = this;
    var thCheckbox;

    // 移除旧的 checkbox
    thCheckbox = $.query('.mdui-table-cell-checkbox', _this.thRow);
    if (thCheckbox) {
      $.remove(thCheckbox);
    }

    if (!_this.selectable) {
      return;
    }

    // 创建 DOM
    var th = $.dom(checkboxHTML('th'))[0];
    $.prepend(_this.thRow, th);

    // 绑定事件
    thCheckbox = $.query('input[type="checkbox"]', th);
    $.on(thCheckbox, 'change', function () {

      $.each(_this.tdCheckboxs, function (i, checkbox) {
        checkbox.checked = thCheckbox.checked;
      });

      $.each(_this.tdRows, function (i, row) {
        row.classList[thCheckbox.checked ? 'add' : 'remove']('mdui-table-row-selected');
      });

    });
  };

  /**
   * 更新数值列
   */
  Table.prototype.updateNumericCol = function () {
    var _this = this;

    var ths = $.queryAll('th', _this.thRow);
    $.each(ths, function (i, th) {
      $.each(_this.tdRows, function (j, tdRow) {
        var method = th.classList.contains('mdui-table-col-numeric') ? 'add' : 'remove';
        var td = $.queryAll('td', tdRow)[i];
        if (td) {
          td.classList[method]('mdui-table-col-numeric');
        }
      });
    });
  };

  $.ready(function () {
    // 实例化表格
    var tables = $.queryAll('.mdui-table');
    $.each(tables, function (i, table) {
      var inst = new Table(table);
      $.data(table, 'mdui.table', inst);
    });
  });

  /**
   * 更新表格
   */
  mdui.updateTables = function () {
    var tables;

    if (arguments.length === 1) {
      tables = $.dom(arguments[0]);
    } else {
      tables = $.queryAll('.mdui-table');
    }

    $.each(tables, function (i, table) {
      var inst = $.data(table, 'mdui.table');
      inst.init();
    });
  };

})();

/**
 * =============================================================================
 * ************   涟漪   ************
 * =============================================================================
 *
 * Inspired by https://github.com/nolimits4web/Framework7/blob/master/src/js/fast-clicks.js
 * https://github.com/nolimits4web/Framework7/blob/master/LICENSE
 *
 * Inspired by https://github.com/fians/Waves
 */

(function () {

  var Ripple = {

    /**
     * 显示涟漪动画
     * @param e
     * @param element
     */
    show: function (e, element) {

      // 鼠标右键不产生涟漪
      if (e.button === 2) {
        return;
      }

      // 点击位置坐标
      var tmp;
      if ('touches' in e && e.touches.length) {
        tmp = e.touches[0];
      } else {
        tmp = e;
      }

      var touchStartX = tmp.pageX;
      var touchStartY = tmp.pageY;

      // 涟漪位置
      var box = element.getBoundingClientRect();
      var offset = $.offset(element);
      var center = {
        x: touchStartX - offset.left,
        y: touchStartY - offset.top,
      };

      var height = box.height;
      var width = box.width;
      var diameter = Math.max(
        Math.pow((Math.pow(height, 2) + Math.pow(width, 2)), 0.5), 48
      );

      // 涟漪扩散动画
      var translate =
        'translate3d(' + (-center.x + width / 2) + 'px, ' + (-center.y + height / 2) + 'px, 0) ' +
        'scale(1)';

      // 涟漪的 DOM 结构
      var ripple = $.dom('<div class="mdui-ripple-wave" style="' +
        'width: ' + diameter + 'px; ' +
        'height: ' + diameter + 'px; ' +
        'margin-top:-' + diameter / 2 + 'px; ' +
        'margin-left:-' + diameter / 2 + 'px; ' +
        'left:' + center.x + 'px; ' +
        'top:' + center.y + 'px;">' +
        '</div>')[0];

      // 缓存动画效果
      $.data(ripple, {
        translate: translate,
      });

      $.prepend(element, ripple);
      $.relayout(ripple);
      $.transform(ripple, translate);
    },

    /**
     * 隐藏涟漪动画
     * @param e
     * @param element
     */
    hide: function (e, element) {
      element = element || this;

      var ripples = $.children(element, '.mdui-ripple-wave');

      $.each(ripples, function (i, ripple) {
        removeRipple(ripple);
      });

      if (mdui.support.touch) {
        $.off(element, 'touchmove touchend touchcancel', Ripple.hide);
      }

      $.off(element, 'mousemove mouseup mouseleave', Ripple.hide);
    },
  };

  /**
   * 隐藏并移除涟漪
   * @param ripple
   */
  function removeRipple(ripple) {
    if (!ripple || $.data(ripple, 'isRemoved')) {
      return;
    }

    $.data(ripple, 'isRemoved', true);

    var removeTimeout = setTimeout(function () {
      $.remove(ripple);
    }, 400);

    ripple.classList.add('mdui-ripple-wave-fill');
    var translate = $.data(ripple, 'translate');
    $.transform(ripple, translate.replace('scale(1)', 'scale(1.01)'));
    $.transitionEnd(ripple, function (e) {
      clearTimeout(removeTimeout);

      var ripple = e.target;
      ripple.classList.add('mdui-ripple-wave-out');
      $.transform(ripple, translate.replace('scale(1)', 'scale(1.01)'));

      removeTimeout = setTimeout(function () {
        $.remove(ripple);
      }, 700);

      setTimeout(function () {
        $.transitionEnd(ripple, function (e) {
          clearTimeout(removeTimeout);
          $.remove(e.target);
        });
      }, 0);
    });
  }

  /**
   * touch 事件后的 500ms 内禁用 mousedown 事件
   */
  var TouchHandler = {
    touches: 0,

    allowEvent: function (e) {
      var allow = true;

      if (e.type === 'mousedown' && TouchHandler.touches) {
        allow = false;
      }

      return allow;
    },

    registerEvent: function (e) {
      var eType = e.type;

      if (eType === 'touchstart') {
        TouchHandler.touches += 1;
      } else if (['touchmove', 'touchend', 'touchcancel'].indexOf(eType) > -1) {
        setTimeout(function () {
          if (TouchHandler.touches) {
            TouchHandler.touches -= 1;
          }
        }, 500);
      }
    },
  };

  /**
   * 找到含 .mdui-ripple 类的元素
   * @param e
   * @returns {*}
   */
  function getRippleElement(e) {
    if (TouchHandler.allowEvent(e) === false) {
      return null;
    }

    var element = null;
    var target = e.target;
    var rippleParents;

    if (target.classList.contains('mdui-ripple')) {
      element = target;
    } else {
      rippleParents = $.parents(target, '.mdui-ripple');
      if (rippleParents.length) {
        element = rippleParents[0];
      }
    }

    return element;
  }

  /**
   * 显示涟漪,并绑定 touchend 等事件
   * @param e
   */
  function showRipple(e) {
    var element = getRippleElement(e);

    if (element !== null) {

      // 禁用状态的元素上不产生涟漪效果
      if (element.disabled || element.getAttribute('disabled')) {
        return;
      }

      TouchHandler.registerEvent(e);

      Ripple.show(e, element);

      if (mdui.support.touch) {
        $.on(element, 'touchmove touchend touchcancel', Ripple.hide);
      }

      $.on(element, 'mousemove mouseup mouseleave', Ripple.hide);
    }
  }

  // 初始化绑定的事件
  if (mdui.support.touch) {
    $.on(document, 'touchstart', showRipple);
    $.on(document, 'touchmove touchend touchcancel', TouchHandler.registerEvent);
  }

  $.on(document, 'mousedown', showRipple);
})();

/**
 * =============================================================================
 * ************   Text Field 文本框   ************
 * =============================================================================
 */

(function () {

  var notInputs = ['checkbox', 'button', 'submit', 'range', 'radio', 'image'];

  var classNames = {
    field: 'mdui-textfield',
    input: 'mdui-textfield-input',
    focus: 'mdui-textfield-focus',
    notEmpty: 'mdui-textfield-not-empty',
    disabled: 'mdui-textfield-disabled',
    invalid: 'mdui-textfield-invalid',
    expanded: 'mdui-textfield-expanded',
  };

  /**
   * 输入框事件
   * @param e
   */
  var inputEvent = function (e) {
    var input = e.target;
    var event = e.type;
    var value = input.value;

    // reInit 为 true 时,需要重新初始化文本框
    var reInit;
    if (
      typeof e.detail === 'object' &&
      typeof e.detail.reInit !== 'undefined' &&
      e.detail.reInit
    ) {
      reInit = e.detail.reInit;
    } else {
      reInit = false;
    }

    // domLoadedEvent 为 true 时,为 DOM 加载完毕后自动触发的事件
    var domLoadedEvent;
    if (
      typeof e.detail === 'object' &&
      typeof e.detail.domLoadedEvent !== 'undefined' &&
      e.detail.domLoadedEvent
    ) {
      domLoadedEvent = e.detail.domLoadedEvent;
    } else {
      domLoadedEvent = false;
    }

    // 文本框类型
    var type = input.getAttribute('type') || '';
    if (notInputs.indexOf(type) >= 0) {
      return;
    }

    var textField = $.parents(input, '.' + classNames.field)[0];

    // 输入框是否聚焦
    if (event === 'focus') {
      textField.classList.add(classNames.focus);
    }

    if (event === 'blur') {
      textField.classList.remove(classNames.focus);
    }

    // 输入框是否为空
    if (event === 'blur' || event === 'input') {
      if (value && value !== '') {
        textField.classList.add(classNames.notEmpty);
      } else {
        textField.classList.remove(classNames.notEmpty);
      }
    }

    // 输入框是否禁用
    if (input.disabled) {
      textField.classList.add(classNames.disabled);
    } else {
      textField.classList.remove(classNames.disabled);
    }

    // 表单验证
    if ((event === 'input' || event === 'blur') && !domLoadedEvent) {
      if (input.validity) {
        if (input.validity.valid) {
          textField.classList.remove(classNames.invalid);
        } else {
          textField.classList.add(classNames.invalid);
        }
      }
    }

    // textarea 高度自动调整
    if (e.target.nodeName.toLowerCase() === 'textarea') {
      input.style.height = '';
      var height = input.offsetHeight;
      var diff = height - input.clientHeight;
      var scrollHeight = input.scrollHeight;

      if (scrollHeight + diff > height) {
        var newAreaHeight = scrollHeight + diff;
        input.style.height = newAreaHeight + 'px';
      }
    }

    // 实时字数统计
    var counter;
    if (reInit) {
      textField.classList.remove('mdui-textfield-has-counter');
      counter = $.query('.mdui-textfield-counter', textField);
      if (counter) {
        $.remove(counter);
      }
    }

    var maxlength = input.getAttribute('maxlength');
    if (maxlength) {
      if (reInit || domLoadedEvent) {
        counter = $.dom(
          '<div class="mdui-textfield-counter">' +
            '<span class="mdui-textfield-counter-inputed"></span> / ' + maxlength +
          '</div>'
        )[0];
        textField.appendChild(counter);

        // 如果没有 .mdui-textfield-error 作为占位,需要增加 .mdui-textfield 的下边距,
        // 使 .mdui-textfield-counter 不会覆盖在文本框上
        if (!$.query('.mdui-textfield-error', textField)) {
          textField.classList.add('mdui-textfield-has-counter');
        }
      }

      // 字符长度,确保统计方式和 maxlength 一致
      var inputed = input.value.length + input.value.split('\n').length - 1;
      $.query('.mdui-textfield-counter-inputed', textField).innerText = inputed.toString();
    }

  };

  // 绑定事件
  var inputSelector = '.' + classNames.field + ' input, .' + classNames.field + ' textarea';
  $.on(document, 'input focus blur', inputSelector, inputEvent, true);

  // 可展开文本框展开
  $.on(document, 'click', '.mdui-textfield-expandable .mdui-textfield-icon', function () {
    var _this = this;
    var textField = $.parents(_this, '.' + classNames.field)[0];
    var input = $.query('.' + classNames.input, textField);

    textField.classList.add(classNames.expanded);
    input.focus();
  });

  // 可展开文本框关闭
  $.on(document, 'click', '.mdui-textfield-expandable .mdui-textfield-close', function () {
    var _this = this;
    var textField = $.parents(_this, '.' + classNames.field)[0];
    var input = $.query('.' + classNames.input, textField);

    textField.classList.remove(classNames.expanded);
    input.value = '';
  });

  /**
   * 通过 JS 更新了表单内容,需要重新进行表单处理
   * @param dom 如果传入了 .mdui-textfield 所在的 DOM 元素,则更新该文本框;否则,更新所有文本框
   */
  mdui.updateTextFields = function () {
    var textfields;
    var input;

    if (arguments.length === 1) {
      textfields = $.dom(arguments[0]);
    } else {
      textfields = $.queryAll('.mdui-textfield');
    }

    $.each(textfields, function (i, textfield) {
      input = $.query('.mdui-textfield-input', textfield);
      if (input) {
        $.trigger(input, 'input', {
          reInit: true,
        });
      }
    });
  };

  $.ready(function () {

    // DOM 加载完后自动执行
    $.each($.queryAll('.mdui-textfield-input'), function (i, input) {
      $.trigger(input, 'input', {
        domLoadedEvent: true,
      });
    });

  });

})();

/**
 * =============================================================================
 * ************   Slider 滑块   ************
 * =============================================================================
 */

(function () {

  /**
   * 滑块的值变更后修改滑块样式
   * @param slider
   */
  var updateValueStyle = function (slider) {
    var track = $.data(slider, 'track');
    var fill = $.data(slider, 'fill');
    var thumb = $.data(slider, 'thumb');
    var input = $.data(slider, 'input');
    var min = $.data(slider, 'min');
    var max = $.data(slider, 'max');
    var isDisabled = $.data(slider, 'disabled');
    var isDiscrete = $.data(slider, 'discrete');
    var thumbText = $.data(slider, 'thumbText');
    var percent = (input.value - min) / (max - min) * 100;

    fill.style.width = percent + '%';
    track.style.width = 100 - percent + '%';

    if (isDisabled) {
      fill.style['padding-right'] = '6px';
      track.style['padding-left'] = '6px';
    }

    thumb.style.left = percent + '%';

    if (isDiscrete) {
      thumbText.textContent = input.value;
    }

    slider.classList[parseFloat(percent) === 0 ? 'add' : 'remove']('mdui-slider-zero');
  };

  /**
   * 重新初始化
   * @param slider
   */
  var reInit = function (slider) {
    var track = $.dom('<div class="mdui-slider-track"></div>')[0];
    var fill = $.dom('<div class="mdui-slider-fill"></div>')[0];
    var thumb = $.dom('<div class="mdui-slider-thumb"></div>')[0];
    var input = $.query('input[type="range"]', slider);

    // 禁用状态
    var isDisabled = input.disabled;
    slider.classList[isDisabled ? 'add' : 'remove']('mdui-slider-disabled');

    // 重新填充 HTML
    $.remove($.query('.mdui-slider-track', slider));
    slider.appendChild(track);

    $.remove($.query('.mdui-slider-fill', slider));
    slider.appendChild(fill);

    $.remove($.query('.mdui-slider-thumb', slider));
    slider.appendChild(thumb);

    // 间续型滑块
    var isDiscrete = slider.classList.contains('mdui-slider-discrete');

    var thumbText;
    if (isDiscrete) {
      thumbText = $.dom('<span></span>')[0];

      $.empty(thumb);
      thumb.appendChild(thumbText);
    }

    $.data(slider, {
      track: track,
      fill: fill,
      thumb: thumb,
      input: input,
      min: input.getAttribute('min'),   // 滑块最小值
      max: input.getAttribute('max'),   // 滑块最大值
      disabled: isDisabled,             // 是否禁用状态
      discrete: isDiscrete,             // 是否是间续型滑块
      thumbText: thumbText,             // 间续型滑块的数值
    });

    // 设置默认值
    updateValueStyle(slider);
  };

  /**
   * 滑动滑块事件
   */
  $.on(document, 'input change', '.mdui-slider input[type="range"]', function () {
    var slider = $.parent(this, '.mdui-slider');
    updateValueStyle(slider);
  });

  /**
   * 开始触摸滑块事件
   */
  $.on(document, mdui.touchEvents.start, '.mdui-slider input[type="range"]', function () {
    var slider = $.parent(this, '.mdui-slider');
    if (!this.disabled) {
      slider.classList.add('mdui-slider-focus');
    }
  });

  /**
   * 结束触摸滑块事件
   */
  $.on(document, mdui.touchEvents.end, '.mdui-slider input[type="range"]', function () {
    var slider = $.parent(this, '.mdui-slider');
    if (!this.disabled) {
      slider.classList.remove('mdui-slider-focus');
    }
  });

  /**
   * 页面加载完后自动初始化
   */
  $.ready(function () {
    var sliders = $.queryAll('.mdui-slider');
    $.each(sliders, function (i, slider) {
      reInit(slider);
    });
  });

  /**
   * 重新初始化滑块
   */
  mdui.updateSliders = function () {
    var sliders;

    if (arguments.length === 1) {
      sliders = $.dom(arguments[0]);
    } else {
      sliders = $.queryAll('.mdui-slider');
    }

    $.each(sliders, function (i, slider) {
      reInit(slider);
    });
  };
})();

/**
 * =============================================================================
 * ************   Fab 浮动操作按钮   ************
 * =============================================================================
 */

mdui.Fab = (function () {

  /**
   * 默认参数
   * @type {{}}
   */
  var DEFAULT = {
    trigger: 'hover',      // 触发方式 ['hover', 'click']
  };

  /**
   * 浮动操作按钮实例
   * @param selector 选择器或 HTML 字符串或 DOM 元素
   * @param opts
   * @constructor
   */
  function Fab(selector, opts) {
    var _this = this;

    _this.fab = $.dom(selector)[0];
    if (typeof _this.fab === 'undefined') {
      return;
    }

    // 已通过 data 属性实例化过,不再重复实例化
    var oldInst = $.data(_this.fab, 'mdui.fab');
    if (oldInst) {
      return oldInst;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));
    _this.state = 'closed';

    _this.btn = $.child(_this.fab, '.mdui-fab');
    _this.dial = $.child(_this.fab, '.mdui-fab-dial');
    _this.dialBtns = $.queryAll('.mdui-fab', _this.dial);

    // 支持 touch 时,始终在 touchstart 时切换,不受 trigger 参数影响
    if (mdui.support.touch) {
      $.on(_this.btn, 'touchstart', function () {
        _this.open();
      });

      $.on(document, 'touchend', function (e) {
        if (!$.parents(e.target, '.mdui-fab-wrapper').length) {
          _this.close();
        }
      });
    }

    // 不支持touch
    else {

      // 点击切换
      if (_this.options.trigger === 'click') {
        $.on(_this.btn, 'click', function () {
          _this.toggle();
        });
      }

      // 鼠标悬浮切换
      if (_this.options.trigger === 'hover') {
        $.on(_this.fab, 'mouseenter', function () {
          _this.open();
        });

        $.on(_this.fab, 'mouseleave', function () {
          _this.close();
        });
      }
    }
  }

  /**
   * 打开菜单
   */
  Fab.prototype.open = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    // 为菜单中的按钮添加不同的 transition-delay
    $.each(_this.dialBtns, function (index, btn) {
      btn.style['transition-delay'] = 15 * (_this.dialBtns.length - index) + 'ms';
    });

    _this.dial.classList.add('mdui-fab-dial-show');

    // 如果按钮中存在 .mdui-fab-opened 的图标,则进行图标切换
    if ($.query('.mdui-fab-opened', _this.btn)) {
      _this.btn.classList.add('mdui-fab-opened');
    }

    _this.state = 'opening';
    $.pluginEvent('open', 'fab', _this, _this.fab);

    // 打开顺序为从下到上逐个打开,最上面的打开后才表示动画完成
    $.transitionEnd(_this.dialBtns[0], function () {
      if (_this.btn.classList.contains('mdui-fab-opened')) {
        _this.state = 'opened';
        $.pluginEvent('opened', 'fab', _this, _this.fab);
      }
    });
  };

  /**
   * 关闭菜单
   */
  Fab.prototype.close = function () {
    var _this = this;

    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    // 为菜单中的按钮添加不同的 transition-delay
    $.each(_this.dialBtns, function (index, btn) {
      btn.style['transition-delay'] = 15 * index + 'ms';
    });

    _this.dial.classList.remove('mdui-fab-dial-show');
    _this.btn.classList.remove('mdui-fab-opened');
    _this.state = 'closing';
    $.pluginEvent('close', 'fab', _this, _this.fab);

    // 从上往下依次关闭,最后一个关闭后才表示动画完成
    $.transitionEnd(_this.dialBtns[_this.dialBtns.length - 1], function () {
      if (!_this.btn.classList.contains('mdui-fab-opened')) {
        _this.state = 'closed';
        $.pluginEvent('closed', 'fab', _this, _this.fab);
      }
    });
  };

  /**
   * 切换菜单的打开状态
   */
  Fab.prototype.toggle = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      _this.close();
    } else if (_this.state === 'closing' || _this.state === 'closed') {
      _this.open();
    }
  };

  /**
   * 获取当前菜单状态
   * @returns {'opening'|'opened'|'closing'|'closed'}
   */
  Fab.prototype.getState = function () {
    return this.state;
  };

  /**
   * 以动画的形式显示浮动操作按钮
   */
  Fab.prototype.show = function () {
    this.fab.classList.remove('mdui-fab-hide');
  };

  /**
   * 以动画的形式隐藏浮动操作按钮
   */
  Fab.prototype.hide = function () {
    this.fab.classList.add('mdui-fab-hide');
  };

  return Fab;
})();

/**
 * =============================================================================
 * ************   Fab DATA API   ************
 * =============================================================================
 */

$.ready(function () {

  // mouseenter 不冒泡,无法进行事件委托,这里用 mouseover 代替。
  // 不管是 click 、 mouseover 还是 touchstart ,都先初始化。
  var event = mdui.support.touch ? 'touchstart' : 'click mouseover';

  $.on(document, event, '[mdui-fab]', function (e) {
    var _this = this;
    var eventType = e.type;

    var inst = $.data(_this, 'mdui.fab');
    if (!inst) {
      var options = $.parseOptions(_this.getAttribute('mdui-fab'));
      inst = new mdui.Fab(_this, options);
      $.data(_this, 'mdui.fab', inst);

      // 判断当前事件
      if (eventType === 'touchstart') {
        inst.open();
      }else if (
        (inst.options.trigger === 'click' && eventType === 'click') ||
        (inst.options.trigger === 'hover' && eventType === 'mouseover')
      ) {
        inst.open();
      }
    }
  });
});

/**
 * =============================================================================
 * ************   Appbar   ************
 * =============================================================================
 * 滚动时自动隐藏应用栏
 * mdui-appbar-scroll-hide
 * mdui-appbar-scroll-toolbar-hide
 */

$.ready(function () {

  // 滚动时隐藏应用栏
  $.each($.queryAll('.mdui-appbar-scroll-hide'), function (i, appbar) {
    $.data(appbar, 'mdui.headroom', new mdui.Headroom(appbar));
  });

  // 滚动时只隐藏应用栏中的工具栏
  $.each($.queryAll('.mdui-appbar-scroll-toolbar-hide'), function (i, appbar) {
    var inst = new mdui.Headroom('.mdui-appbar-scroll-toolbar-hide', {
      pinnedClass: 'mdui-headroom-pinned-toolbar',
      unpinnedClass: 'mdui-headroom-unpinned-toolbar',
    });
    $.data(appbar, 'mdui.headroom', inst);
  });
});

/**
 * =============================================================================
 * ************   Tab   ************
 * =============================================================================
 */

mdui.Tab = (function () {

  var DEFAULT = {
    trigger: 'click',       // 触发方式 click: 鼠标点击切换 hover: 鼠标悬浮切换
    //animation: false,       // 切换时是否显示动画
    loop: false,            // 为true时,在最后一个选项卡时调用 next() 方法会回到第一个选项卡
  };

  /**
   * 选项卡
   * @param selector
   * @param opts
   * @returns {*}
   * @constructor
   */
  function Tab(selector, opts) {
    var _this = this;
    var trigger;

    _this.tab = $.dom(selector)[0];
    if (typeof _this.tab === 'undefined') {
      return;
    }

    // 已通过自定义属性实例化过,不再重复实例化
    var oldInst = $.data(_this.tab, 'mdui.tab');
    if (oldInst) {
      return oldInst;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));
    _this.tabs = $.children(_this.tab, 'a');

    _this.indicator = $.dom('<div class="mdui-tab-indicator"></div>')[0];

    // 选项卡下面添加的指示符
    _this.tab.appendChild(_this.indicator);

    // 触发方式
    if (mdui.support.touch) {
      trigger = 'touchend';
    } else if (_this.options.trigger === 'hover') {
      trigger = 'mouseenter';
    } else {
      trigger = 'click';
    }

    // 根据 url hash 获取默认激活的选项卡
    var hash = location.hash;
    if (hash) {
      $.each(_this.tabs, function (i, tab) {
        if (tab.getAttribute('href') === hash) {
          _this.activeIndex = i;
          return false;
        }
      });
    }

    // 含 mdui-tab-active 的元素默认激活
    if (typeof _this.activeIndex === 'undefined') {
      $.each(_this.tabs, function (i, tab) {
        if (tab.classList.contains('mdui-tab-active')) {
          _this.activeIndex = i;
          return false;
        }
      });
    }

    // 默认激活第一个选项卡
    if (typeof _this.activeIndex === 'undefined') {
      _this.activeIndex = 0;
    }

    // 设置激活状态选项卡
    _this._setActive();

    // 监听窗口大小变化事件,调整指示器位置
    $.on(window, 'resize', mdui.throttle(function () {
      _this._setIndicatorPosition();
    }, 100));

    // 监听点击选项卡事件
    $.each(_this.tabs, function (i, tab) {
      $.on(tab, trigger, function (e) {
        if (tab.getAttribute('disabled') !== null) {
          e.preventDefault();
          return;
        }

        _this.activeIndex = i;
        _this._setActive();
      });

      $.on(tab, 'click', function (e) {
        // 阻止链接的默认点击动作
        if (tab.getAttribute('href').indexOf('#') === 0) {
          e.preventDefault();
        }
      });
    });
  }

  /**
   * 设置激活状态的选项卡
   */
  Tab.prototype._setActive = function () {
    var _this = this;

    $.each(_this.tabs, function (i, tab) {
      var targetId = tab.getAttribute('href');
      var targetContent;

      if (tab.getAttribute('disabled') !== null) {
        if (targetId.indexOf('#') === 0) {
          targetContent = $.query(targetId);
          if (targetContent) {
            targetContent.style.display = 'none';
          }
        }

        return;
      }

      // 选项卡激活状态
      if (i === _this.activeIndex) {
        $.pluginEvent('change', 'tab', _this, _this.tab, {
          index: _this.activeIndex,
          target: tab,
        });
        $.pluginEvent('show', 'tab', _this, tab);

        if (!tab.classList.contains('mdui-tab-active')) {
          tab.classList.add('mdui-tab-active');
        }
      } else {
        if (tab.classList.contains('mdui-tab-active')) {
          tab.classList.remove('mdui-tab-active');
        }
      }

      // 选项卡内容显示切换
      if (targetId.indexOf('#') === 0) {
        targetContent = $.query(targetId);
        if (targetContent) {
          if (i === _this.activeIndex) {
            targetContent.style.display = 'block';
          } else {
            targetContent.style.display = 'none';
          }
        }
      }

    });

    _this._setIndicatorPosition();
  };

  /**
   * 设置选项卡指示器的位置
   */
  Tab.prototype._setIndicatorPosition = function () {
    var _this = this;

    var activeTab = _this.tabs[_this.activeIndex];
    if (activeTab.getAttribute('disabled') !== null) {
      return;
    }

    var activeTabOffset = $.offset(activeTab);
    _this.indicator.style.left =
      activeTabOffset.left + _this.tab.scrollLeft - _this.tab.getBoundingClientRect().left + 'px';
    _this.indicator.style.width = $.getStyle(activeTab, 'width');
  };

  /**
   * 切换到下一个选项卡
   */
  Tab.prototype.next = function () {
    var _this = this;

    if (_this.tabs.length > _this.activeIndex + 1) {
      _this.activeIndex++;
    } else if (_this.options.loop) {
      _this.activeIndex = 0;
    }

    _this._setActive();
  };

  /**
   * 切换到上一个选项卡
   */
  Tab.prototype.prev = function () {
    var _this = this;

    if (_this.activeIndex > 0) {
      _this.activeIndex--;
    } else if (_this.options.loop) {
      _this.activeIndex = _this.tabs.length - 1;
    }

    _this._setActive();
  };

  /**
   * 显示指定序号或指定id的选项卡
   * @param index 从0开始的序号,或以#开头的id
   */
  Tab.prototype.show = function (index) {
    var _this = this;

    if (parseInt(index) === index) {
      _this.activeIndex = index;
    } else {
      $.each(_this.tabs, function (i, tab) {
        if (tab.id === index) {
          _this.activeIndex = i;
          return false;
        }
      });
    }

    _this._setActive();
  };

  /**
   * 在父元素的宽度变化时,需要调用该方法重新调整指示器位置
   */
  Tab.prototype.handleUpdate = function () {
    this._setIndicatorPosition();
  };

  return Tab;
})();

/**
 * =============================================================================
 * ************   Tab 自定义属性 API   ************
 * =============================================================================
 */

$.ready(function () {

  // 实例化插件
  $.each($.queryAll('[mdui-tab]'), function (i, target) {
    var options = $.parseOptions(target.getAttribute('mdui-tab'));

    var inst = $.data(target, 'mdui.tab');
    if (!inst) {
      inst = new mdui.Tab(target, options);
      $.data(target, 'mdui.tab', inst);
    }
  });
});

/**
 * =============================================================================
 * ************   Drawer 抽屉栏   ************
 * =============================================================================
 *
 * 在桌面设备上默认显示抽屉栏,不显示遮罩层
 * 在手机和平板设备上默认不显示抽屉栏,始终显示遮罩层,且覆盖导航栏
 */

mdui.Drawer = (function () {

  /**
   * 默认参数
   * @type {{}}
   */
  var DEFAULT = {
    // 在桌面设备上是否显示遮罩层。手机和平板不受这个参数影响,始终会显示遮罩层
    overlay: false,
  };

  /**
   * 抽屉栏实例
   * @param selector 选择器或 HTML 字符串或 DOM 元素
   * @param opts
   * @constructor
   */
  function Drawer(selector, opts) {
    var _this = this;

    _this.drawer = $.dom(selector)[0];
    if (typeof _this.drawer === 'undefined') {
      return;
    }

    var oldInst = $.data(_this.drawer, 'mdui.drawer');
    if (oldInst) {
      return oldInst;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));

    _this.overlay = false; // 是否显示着遮罩层
    _this.position = _this.drawer.classList.contains('mdui-drawer-right') ? 'right' : 'left';

    if (_this.drawer.classList.contains('mdui-drawer-close')) {
      _this.state = 'closed';
    } else if (_this.drawer.classList.contains('mdui-drawer-open')) {
      _this.state = 'opened';
    } else if (mdui.screen.mdUp()) {
      _this.state = 'opened';
    } else {
      _this.state = 'closed';
    }

    // 浏览器窗口大小调整时
    $.on(window, 'resize', mdui.throttle(function () {
      // 由手机平板切换到桌面时
      if (mdui.screen.mdUp()) {
        // 如果显示着遮罩,则隐藏遮罩
        if (_this.overlay && !_this.options.overlay) {
          mdui.hideOverlay();
          _this.overlay = false;

          mdui.unlockScreen();
        }

        // 没有强制关闭,则状态为打开状态
        if (!_this.drawer.classList.contains('mdui-drawer-close')) {
          _this.state = 'opened';
        }
      }

      // 由桌面切换到手机平板时。如果抽屉栏是打开着的且没有遮罩层,则关闭抽屉栏
      else {
        if (!_this.overlay && _this.state === 'opened') {
          // 抽屉栏处于强制打开状态,添加遮罩
          if (_this.drawer.classList.contains('mdui-drawer-open')) {
            mdui.showOverlay();
            _this.overlay = true;

            mdui.lockScreen();

            $.one($.query('.mdui-overlay'), 'click', function () {
              _this.close();
            });
          } else {
            _this.state = 'closed';
          }
        }
      }

    }, 100));

    // 不支持 touch 的设备默认隐藏滚动条,鼠标移入时显示滚动条;支持 touch 的设备会自动隐藏滚动条
    if (!mdui.support.touch) {
      _this.drawer.style['overflow-y'] = 'hidden';
      _this.drawer.classList.add('mdui-drawer-scrollbar');
    }

    // 绑定关闭按钮事件
    var closes = $.queryAll('[mdui-drawer-close]', _this.drawer);
    $.each(closes, function (i, close) {
      $.on(close, 'click', function () {
        _this.close();
      });
    });
  }

  /**
   * 打开抽屉栏
   */
  Drawer.prototype.open = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    _this.drawer.classList.remove('mdui-drawer-close');
    _this.drawer.classList.add('mdui-drawer-open');

    _this.state = 'opening';
    $.pluginEvent('open', 'drawer', _this, _this.drawer);

    if (!_this.options.overlay) {
      document.body.classList.add('mdui-drawer-body-' + _this.position);
    }

    $.transitionEnd(_this.drawer, function () {
      if (_this.drawer.classList.contains('mdui-drawer-open')) {
        _this.state = 'opened';
        $.pluginEvent('opened', 'drawer', _this, _this.drawer);
      }
    });

    if (!mdui.screen.mdUp() || _this.options.overlay) {
      mdui.showOverlay();
      _this.overlay = true;

      mdui.lockScreen();

      $.one($.query('.mdui-overlay'), 'click', function () {
        _this.close();
      });
    }
  };

  /**
   * 关闭抽屉栏
   */
  Drawer.prototype.close = function () {
    var _this = this;

    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    _this.drawer.classList.add('mdui-drawer-close');
    _this.drawer.classList.remove('mdui-drawer-open');
    _this.state = 'closing';
    $.pluginEvent('close', 'drawer', _this, _this.drawer);

    if (!_this.options.overlay) {
      document.body.classList.remove('mdui-drawer-body-' + _this.position);
    }

    $.transitionEnd(_this.drawer, function () {
      if (!_this.drawer.classList.contains('mdui-drawer-open')) {
        _this.state = 'closed';
        $.pluginEvent('closed', 'drawer', _this, _this.drawer);
      }
    });

    if (_this.overlay) {
      mdui.hideOverlay();
      _this.overlay = false;

      mdui.unlockScreen();
    }
  };

  /**
   * 切换抽屉栏打开/关闭状态
   */
  Drawer.prototype.toggle = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      _this.close();
    } else if (_this.state === 'closing' || _this.state === 'closed') {
      _this.open();
    }
  };

  /**
   * 获取抽屉栏状态
   * @returns {'opening'|'opened'|'closing'|'closed'}
   */
  Drawer.prototype.getState = function () {
    return this.state;
  };

  return Drawer;

})();

/**
 * =============================================================================
 * ************   Drawer 自定义属性 API   ************
 * =============================================================================
 */

$.ready(function () {

  // 实例化插件
  $.each($.queryAll('[mdui-drawer]'), function (i, target) {
    var options = $.parseOptions(target.getAttribute('mdui-drawer'));
    var selector = options.target;
    delete options.target;

    var drawer = $.dom(selector)[0];

    var inst = $.data(drawer, 'mdui.drawer');
    if (!inst) {
      inst = new mdui.Drawer(drawer, options);
      $.data(drawer, 'mdui.drawer', inst);
    }

    $.on(target, 'click', function () {
      inst.toggle();
    });
  });

});

/**
 * =============================================================================
 * ************   Dialog 提示框   ************
 * =============================================================================
 */

mdui.Dialog = (function () {

  /**
   * 默认参数
   */
  var DEFAULT = {
    history: true,                // 监听 hashchange 事件
    overlay: true,                // 打开提示框时显示遮罩
    modal: false,                 // 是否模态化提示框,为 false 时点击提示框外面区域关闭提示框,为 true 时不关闭
    closeOnEsc: true,             // 按下 esc 关闭提示框
    closeOnCancel: true,          // 按下取消按钮时关闭提示框
    closeOnConfirm: true,         // 按下确认按钮时关闭提示框
    destroyOnClosed: false,        // 关闭后销毁
  };

  /**
   * 遮罩层元素
   */
  var overlay;

  /**
   * 当前提示框
   */
  var current;

  /**
   * 队列名
   * @type {string}
   */
  var queueName = '__md_dialog';

  /**
   * 窗口宽度变化,或提示框内容变化时,调整提示框位置和提示框内的滚动条
   */
  var readjust = function () {
    if (!current) {
      return;
    }

    var dialog = current.dialog;

    var dialogTitle = $.child(dialog, '.mdui-dialog-title');
    var dialogContent = $.child(dialog, '.mdui-dialog-content');
    var dialogActions = $.child(dialog, '.mdui-dialog-actions');

    // 调整 dialog 的 top 和 height 值
    dialog.style.height = '';
    if (dialogContent) {
      dialogContent.style.height = '';
    }

    var dialogHeight = dialog.clientHeight;
    dialog.style.top = ((window.innerHeight - dialogHeight) / 2) + 'px';
    dialog.style.height = dialogHeight + 'px';

    // 调整 mdui-dialog-content 的高度
    var dialogTitleHeight = dialogTitle ? dialogTitle.scrollHeight : 0;
    var dialogActionsHeight = dialogActions ? dialogActions.scrollHeight : 0;
    if (dialogContent) {
      dialogContent.style.height = dialogHeight - dialogTitleHeight - dialogActionsHeight + 'px';
    }
  };

  /**
   * hashchange 事件触发时关闭提示框
   */
  var hashchangeEvent = function () {
    if (location.hash.substring(1).indexOf('&mdui-dialog') < 0) {
      current.close(true);
    }
  };

  /**
   * 点击遮罩层关闭提示框
   * @param e
   */
  var overlayClick = function (e) {
    if (e.target.classList.contains('mdui-overlay')) {
      current.close();
    }
  };

  /**
   * 提示框实例
   * @param selector 选择器或 HTML 字符串或 DOM 元素
   * @param opts
   * @constructor
   */
  function Dialog(selector, opts) {
    var _this = this;

    // 提示框元素
    _this.dialog = $.dom(selector)[0];
    if (typeof _this.dialog === 'undefined') {
      return;
    }

    // 已通过 data 属性实例化过,不再重复实例化
    var oldInst = $.data(_this.dialog, 'mdui.dialog');
    if (oldInst) {
      return oldInst;
    }

    // 如果提示框元素没有在当前文档中,则需要添加
    if (!document.body.contains(_this.dialog)) {
      _this.append = true;
      document.body.appendChild(_this.dialog);
    }

    _this.options = $.extend(DEFAULT, (opts || {}));
    _this.state = 'closed';

    // 在不支持触摸的设备上美化滚动条
    if (!mdui.support.touch) {
      var content = $.query('.mdui-dialog-content', _this.dialog);
      if (content) {
        content.classList.add('mdui-dialog-scrollbar');
      }
    }

    // 绑定取消按钮事件
    var cancels = $.queryAll('[mdui-dialog-cancel]', _this.dialog);
    $.each(cancels, function (i, cancel) {
      $.on(cancel, 'click', function () {
        $.pluginEvent('cancel', 'dialog', _this, _this.dialog);
        if (_this.options.closeOnCancel) {
          _this.close();
        }
      });
    });

    // 绑定确认按钮事件
    var confirms = $.queryAll('[mdui-dialog-confirm]', _this.dialog);
    $.each(confirms, function (i, confirm) {
      $.on(confirm, 'click', function () {
        $.pluginEvent('confirm', 'dialog', _this, _this.dialog);
        if (_this.options.closeOnConfirm) {
          _this.close();
        }
      });
    });

    // 绑定关闭按钮事件
    var closes = $.queryAll('[mdui-dialog-close]', _this.dialog);
    $.each(closes, function (i, close) {
      $.on(close, 'click', function () {
        _this.close();
      });
    });
  }

  /**
   * 打开提示框
   */
  Dialog.prototype.open = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    // 如果当前有正在打开或已经打开的对话框,或队列不为空,则先加入队列,等旧对话框开始关闭时再打开
    if (
      (current && (current.state === 'opening' || current.state === 'opened')) ||
      $.queue(queueName).length
    ) {
      $.queue(queueName, function () {
        _this.open();
      });

      return;
    }

    current = _this;

    mdui.lockScreen();
    _this.dialog.style.display = 'block';

    readjust();
    $.on(window, 'resize', mdui.throttle(function () {
      readjust();
    }, 100));

    // 打开消息框
    _this.dialog.classList.add('mdui-dialog-open');
    _this.state = 'opening';
    $.pluginEvent('open', 'dialog', _this, _this.dialog);

    // 打开提示框动画完成后
    $.transitionEnd(_this.dialog, function () {
      if (_this.dialog.classList.contains('mdui-dialog-open')) {
        _this.state = 'opened';
        $.pluginEvent('opened', 'dialog', _this, _this.dialog);
      }
    });

    // 不存在遮罩层元素时,添加遮罩层
    if (!overlay) {
      overlay = mdui.showOverlay();
    }

    // 点击遮罩层时是否关闭提示框
    $[_this.options.modal ? 'off' : 'on'](overlay, 'click', overlayClick);

    // 是否显示遮罩层,不显示时,把遮罩层背景透明
    overlay.style.opacity = _this.options.overlay ? '' : 0;

    if (_this.options.history) {
      // 如果 hash 中原来就有 &mdui-dialog,先删除,避免后退历史纪录后仍然有 &mdui-dialog 导致无法关闭
      var hash = location.hash.substring(1);
      if (hash.indexOf('&mdui-dialog') > -1) {
        hash = hash.replace(/&mdui-dialog/g, '');
      }

      // 后退按钮关闭对话框
      location.hash = hash + '&mdui-dialog';
      $.on(window, 'hashchange', hashchangeEvent);
    }
  };

  /**
   * 关闭提示框
   */
  Dialog.prototype.close = function () {
    var _this = this;

    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    current = null;
    _this.dialog.classList.remove('mdui-dialog-open');
    _this.state = 'closing';
    $.pluginEvent('close', 'dialog', _this, _this.dialog);

    // 所有提示框都关闭,且当前没有打开的提示框时,隐藏遮罩
    if ($.queue(queueName).length === 0) {
      mdui.hideOverlay(overlay);
      overlay = null;
    }

    $.transitionEnd(_this.dialog, function () {
      if (!_this.dialog.classList.contains('mdui-dialog-open')) {

        _this.state = 'closed';
        $.pluginEvent('closed', 'dialog', _this, _this.dialog);

        _this.dialog.style.display = 'none';

        // 所有提示框都关闭,且当前没有打开的提示框时,解锁屏幕
        if ($.queue(queueName).length === 0 && !current) {
          mdui.unlockScreen();
        }

        $.off(window, 'resize', readjust);

        if (_this.options.destroyOnClosed) {
          _this.destroy();
        }
      }
    });

    if (_this.options.history && $.queue(queueName).length === 0) {
      // 是否需要后退历史纪录,默认为 false。
      // 为 false 时是通过 js 关闭,需要后退一个历史记录
      // 为 true 时是通过后退按钮关闭,不需要后退历史记录
      if (!arguments[0]) {
        window.history.back();
      }

      $.off(window, 'hashchange', hashchangeEvent);
    }

    // 关闭旧对话框,打开新对话框。
    // 加一点延迟,仅仅为了视觉效果更好。不加延时也不影响功能
    setTimeout(function () {
      $.dequeue(queueName);
    }, 100);
  };

  /**
   * 切换提示框打开/关闭状态
   */
  Dialog.prototype.toggle = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      _this.close();
    } else if (_this.state === 'closing' || _this.state === 'closed') {
      _this.open();
    }
  };

  /**
   * 获取提示框状态
   * @returns {'opening'|'opened'|'closing'|'closed'}
   */
  Dialog.prototype.getState = function () {
    return this.state;
  };

  /**
   * 销毁提示框
   */
  Dialog.prototype.destroy = function () {
    var _this = this;

    if (_this.append) {
      $.remove(_this.dialog);
    }

    $.data(_this.dialog, 'mdui.dialog', null);

    if (current === _this) {
      mdui.unlockScreen();
      mdui.hideOverlay();
    }
  };

  /**
   * 提示框内容变化时,需要调用该方法来调整提示框位置和滚动条高度
   */
  Dialog.prototype.handleUpdate = function () {
    readjust();
  };

  // esc 按下时关闭对话框
  $.on(document, 'keydown', function (e) {
    if (current && current.options.closeOnEsc && current.state === 'opened' && e.keyCode === 27) {
      current.close();
    }
  });

  return Dialog;

})();

/**
 * =============================================================================
 * ************   Dialog DATA API   ************
 * =============================================================================
 */

$.ready(function () {

  $.on(document, 'click', '[mdui-dialog]', function () {
    var _this = this;
    var options = $.parseOptions(_this.getAttribute('mdui-dialog'));
    var selector = options.target;
    delete options.target;

    var dialog = $.dom(selector)[0];

    var inst = $.data(dialog, 'mdui.dialog');
    if (!inst) {
      inst = new mdui.Dialog(dialog, options);
      $.data(dialog, 'mdui.dialog', inst);
    }

    inst.open();
  });

});

/**
 * =============================================================================
 * ************   mdui.dialog(options)   ************
 * =============================================================================
 */

mdui.dialog = function (options) {

  /**
   * 默认参数
   */
  var DEFAULT = {
    title: '',                // 标题
    content: '',              // 文本
    buttons: [],              // 按钮
    stackedButtons: false,    // 垂直排列按钮
    cssClass: '',             // 在 Dialog 上添加的 CSS 类
    history: true,            // 监听 hashchange 事件
    overlay: true,            // 是否显示遮罩
    modal: false,             // 是否模态化提示框
    closeOnEsc: true,         // 按下 esc 时关闭提示框
    destroyOnClosed: true,    // 关闭后销毁
    onOpen: function () {     // 打开动画开始时的回调
    },

    onOpened: function () {   // 打开动画结束后的回调
    },

    onClose: function () {    // 关闭动画开始时的回调
    },

    onClosed: function () {   // 关闭动画结束时的回调
    },
  };

  /**
   * 按钮的默认参数
   */
  var DEFAULT_BUTTON = {
    text: '',                   // 按钮文本
    bold: false,                // 按钮文本是否加粗
    close: true,                // 点击按钮后关闭提示框
    onClick: function (inst) {  // 点击按钮的回调
    },
  };

  // 合并参数
  options = $.extend(DEFAULT, (options || {}));
  $.each(options.buttons, function (i, button) {
    options.buttons[i] = $.extend(DEFAULT_BUTTON, button);
  });

  // 按钮的 HTML
  var buttonsHTML = '';
  if (options.buttons.length) {
    buttonsHTML =
      '<div class="mdui-dialog-actions ' +
        (options.stackedButtons ? 'mdui-dialog-actions-stacked' : '') +
      '">';
    $.each(options.buttons, function (i, button) {
      buttonsHTML +=
        '<a href="javascript:void(0)" ' +
          'class="mdui-btn mdui-ripple mdui-text-color-primary ' +
          (button.bold ? 'mdui-btn-bold' : '') + '">' +
          button.text +
        '</a>';
    });

    buttonsHTML += '</div>';
  }

  // Dialog 的 HTML
  var HTML =
    '<div class="mdui-dialog ' + options.cssClass + '">' +
      (options.title ? '<div class="mdui-dialog-title">' + options.title + '</div>' : '') +
      (options.content ? '<div class="mdui-dialog-content">' + options.content + '</div>' : '') +
      buttonsHTML +
    '</div>';

  // 实例化 Dialog
  var inst = new mdui.Dialog(HTML, {
    history: options.history,
    overlay: options.overlay,
    modal: options.modal,
    closeOnEsc: options.closeOnEsc,
    destroyOnClosed: options.destroyOnClosed,
  });

  // 绑定按钮事件
  if (options.buttons.length) {
    var buttons = $.queryAll('.mdui-dialog-actions .mdui-btn', inst.dialog);
    $.each(buttons, function (i, button) {
      $.on(button, 'click', function () {
        if (typeof options.buttons[i].onClick === 'function') {
          options.buttons[i].onClick(inst);
        }

        if (options.buttons[i].close) {
          inst.close();
        }
      });
    });
  }

  // 绑定打开关闭事件
  if (typeof options.onOpen === 'function') {
    $.on(inst.dialog, 'open.mdui.dialog', function () {
      options.onOpen(inst);
    });

    $.on(inst.dialog, 'opened.mdui.dialog', function () {
      options.onOpened(inst);
    });

    $.on(inst.dialog, 'close.mdui.dialog', function () {
      options.onClose(inst);
    });

    $.on(inst.dialog, 'closed.mdui.dialog', function () {
      options.onClosed(inst);
    });
  }

  inst.open();

  return inst;
};

/**
 * =============================================================================
 * ************   mdui.alert(text, title, onConfirm, options)   ************
 * ************   mdui.alert(text, onConfirm, options)   ************
 * =============================================================================
 */

mdui.alert = function (text, title, onConfirm, options) {

  // title 参数可选
  if (typeof title === 'function') {
    title = '';
    onConfirm = arguments[1];
    options = arguments[2];
  }

  if (typeof onConfirm === 'undefined') {
    onConfirm = function () {};
  }

  if (typeof options === 'undefined') {
    options = {};
  }

  /**
   * 默认参数
   */
  var DEFAULT = {
    confirmText: 'ok',             // 按钮上的文本
    history: true,                 // 监听 hashchange 事件
    modal: false,                  // 是否模态化提示框,为 false 时点击提示框外面区域关闭提示框,为 true 时不关闭
    closeOnEsc: true,              // 按下 esc 关闭提示框
  };

  options = $.extend(DEFAULT, options);

  return mdui.dialog({
    title: title,
    content: text,
    buttons: [
      {
        text: options.confirmText,
        bold: false,
        close: true,
        onClick: onConfirm,
      },
    ],
    cssClass: 'mdui-dialog-alert',
    history: options.history,
    modal: options.modal,
    closeOnEsc: options.closeOnEsc,
  });
};

/**
 * =============================================================================
 * ************   mdui.confirm(text, title, onConfirm, onCancel, options)   ************
 * ************   mdui.confirm(text, onConfirm, onCancel, options)          ************
 * =============================================================================
 */

mdui.confirm = function (text, title, onConfirm, onCancel, options) {

  // title 参数可选
  if (typeof title === 'function') {
    title = '';
    onConfirm = arguments[1];
    onCancel = arguments[2];
    options = arguments[3];
  }

  if (typeof onConfirm === 'undefined') {
    onConfirm = function () {};
  }

  if (typeof onCancel === 'undefined') {
    onCancel = function () {};
  }

  if (typeof options === 'undefined') {
    options = {};
  }

  /**
   * 默认参数
   */
  var DEFAULT = {
    confirmText: 'ok',            // 确认按钮的文本
    cancelText: 'cancel',         // 取消按钮的文本
    history: true,                // 监听 hashchange 事件
    modal: false,                 // 是否模态化提示框,为 false 时点击提示框外面区域关闭提示框,为 true 时不关闭
    closeOnEsc: true,             // 按下 esc 关闭提示框
  };

  options = $.extend(DEFAULT, options);

  return mdui.dialog({
    title: title,
    content: text,
    buttons: [
      {
        text: options.cancelText,
        bold: false,
        close: true,
        onClick: onCancel,
      },
      {
        text: options.confirmText,
        bold: false,
        close: true,
        onClick: onConfirm,
      },
    ],
    cssClass: 'mdui-dialog-confirm',
    history: options.history,
    modal: options.modal,
    closeOnEsc: options.closeOnEsc,
  });
};

/**
 * =============================================================================
 * ************   mdui.prompt(label, title, onConfirm, onCancel, options)   ************
 * ************   mdui.prompt(label, onConfirm, onCancel, options)          ************
 * =============================================================================
 */

mdui.prompt = function (label, title, onConfirm, onCancel, options) {

  // title 参数可选
  if (typeof title === 'function') {
    title = '';
    onConfirm = arguments[1];
    onCancel = arguments[2];
    options = arguments[3];
  }

  if (typeof onConfirm === 'undefined') {
    onConfirm = function () {};
  }

  if (typeof onCancel === 'undefined') {
    onCancel = function () {};
  }

  if (typeof options === 'undefined') {
    options = {};
  }

  /**
   * 默认参数
   */
  var DEFAULT = {
    confirmText: 'ok',        // 确认按钮的文本
    cancelText: 'cancel',     // 取消按钮的文本
    history: true,            // 监听 hashchange 事件
    modal: false,             // 是否模态化提示框,为 false 时点击提示框外面区域关闭提示框,为 true 时不关闭
    closeOnEsc: true,         // 按下 esc 关闭提示框
    type: 'text',             // 输入框类型,text: 单行文本框 textarea: 多行文本框
    maxlength: '',            // 最大输入字符数
    defaultValue: '',         // 输入框中的默认文本
  };

  options = $.extend(DEFAULT, options);

  var content =
    '<div class="mdui-textfield">' +
      (label ? '<label class="mdui-textfield-label">' + label + '</label>' : '') +
      (options.type === 'text' ?
        '<input class="mdui-textfield-input" type="text" ' +
          'value="' + options.defaultValue + '" ' +
          (options.maxlength ? ('maxlength="' + options.maxlength + '"') : '') + '/>' :
        '') +
      (options.type === 'textarea' ?
        '<textarea class="mdui-textfield-input" ' +
          (options.maxlength ? ('maxlength="' + options.maxlength + '"') : '') + '>' +
            options.defaultValue +
        '</textarea>' :
        '') +
    '</div>';

  return mdui.dialog({
    title: title,
    content: content,
    buttons: [
      {
        text: options.cancelText,
        bold: false,
        close: true,
        onClick: function (inst) {
          var value = $.query('.mdui-textfield-input', inst.dialog).value;
          onCancel(value, inst);
        },
      },
      {
        text: options.confirmText,
        bold: false,
        close: true,
        onClick: function (inst) {
          var value = $.query('.mdui-textfield-input', inst.dialog).value;
          onConfirm(value, inst);
        },
      },
    ],
    cssClass: 'mdui-dialog-prompt',
    history: options.history,
    modal: options.modal,
    closeOnEsc: options.closeOnEsc,
    onOpen: function (inst) {

      // 初始化输入框
      var input = $.query('.mdui-textfield-input', inst.dialog);
      mdui.updateTextFields(input);

      // 聚焦到输入框
      input.focus();

      // 如果是多行输入框,监听输入框的 input 事件,更新提示框高度
      if (options.type === 'textarea') {
        $.on(input, 'input', function () {
          inst.handleUpdate();
        });
      }

      // 有字符数限制时,加载完文本框后 DOM 会变化,需要更新提示框高度
      if (options.maxlength) {
        inst.handleUpdate();
      }
    },
  });

};

/**
 * =============================================================================
 * ************   ToolTip 工具提示   ************
 * =============================================================================
 */

mdui.Tooltip = (function () {

  /**
   * 默认参数
   */
  var DEFAULT = {
    position: 'auto',     // 提示所在位置
    delay: 0,             // 延迟,单位毫秒
    content: '',          // 提示文本,允许包含 HTML
  };

  /**
   * 设置 Tooltip 的位置
   * @param inst
   */
  function setPosition(inst) {
    var marginLeft;
    var marginTop;
    var position;

    // 触发的元素
    var targetProps = inst.target.getBoundingClientRect();

    // 触发的元素和 Tooltip 之间的距离
    var targetMargin = (mdui.support.touch ? 24 : 14);

    // Tooltip 的宽度和高度
    var tooltipWidth = inst.tooltip.offsetWidth;
    var tooltipHeight = inst.tooltip.offsetHeight;

    // Tooltip 的方向
    position = inst.options.position;

    // 自动判断位置,加 2px,使 Tooltip 距离窗口边框至少有 2px 的间距
    if (['bottom', 'top', 'left', 'right'].indexOf(position) === -1) {
      if (
        targetProps.top + targetProps.height + targetMargin + tooltipHeight + 2 <
        document.documentElement.clientHeight
      ) {
        position = 'bottom';
      } else if (targetMargin + tooltipHeight + 2 < targetProps.top) {
        position = 'top';
      } else if (targetMargin + tooltipWidth + 2 < targetProps.left) {
        position = 'left';
      } else if (
        targetProps.width + targetMargin + tooltipWidth + 2 <
        document.documentElement.clientWidth - targetProps.left
      ) {
        position = 'right';
      } else {
        position = 'bottom';
      }
    }

    // 设置位置
    switch (position) {
      case 'bottom':
        marginLeft = -1 * (tooltipWidth / 2);
        marginTop = (targetProps.height / 2) + targetMargin;
        $.transformOrigin(inst.tooltip, 'top center');
        break;
      case 'top':
        marginLeft = -1 * (tooltipWidth / 2);
        marginTop = -1 * (tooltipHeight + (targetProps.height / 2) + targetMargin);
        $.transformOrigin(inst.tooltip, 'bottom center');
        break;
      case 'left':
        marginLeft = -1 * (tooltipWidth + (targetProps.width / 2) + targetMargin);
        marginTop = -1 * (tooltipHeight / 2);
        $.transformOrigin(inst.tooltip, 'center right');
        break;
      case 'right':
        marginLeft = (targetProps.width / 2) + targetMargin;
        marginTop = -1 * (tooltipHeight / 2);
        $.transformOrigin(inst.tooltip, 'center left');
        break;
    }

    var targetOffset = $.offset(inst.target);
    inst.tooltip.style.top = targetOffset.top + (targetProps.height / 2) + 'px';
    inst.tooltip.style.left = targetOffset.left + (targetProps.width / 2) + 'px';
    inst.tooltip.style['margin-left'] = marginLeft + 'px';
    inst.tooltip.style['margin-top'] = marginTop + 'px';
  }

  /**
   * Tooltip 实例
   * @param selector
   * @param opts
   * @constructor
   */
  function Tooltip(selector, opts) {
    var _this = this;

    _this.target = $.dom(selector)[0];
    if (typeof _this.target === 'undefined') {
      return;
    }

    // 已通过 data 属性实例化过,不再重复实例化
    var oldInst = $.data(_this.target, 'mdui.tooltip');
    if (oldInst) {
      return oldInst;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));
    _this.state = 'closed';

    // 创建 Tooltip HTML
    var guid = mdui.guid();
    _this.tooltip = $.dom(
      '<div class="mdui-tooltip ' +
        (mdui.support.touch ? 'mdui-tooltip-mobile' : 'mdui-tooltip-desktop') +
        '" id="mdui-tooltip-' + guid + '">' +
        _this.options.content + '</div>'
    )[0];
    document.body.appendChild(_this.tooltip);

    // 绑定事件
    var openEvent = mdui.support.touch ? 'touchstart' : 'mouseenter';
    var closeEvent = mdui.support.touch ? 'touchend' : 'mouseleave';
    $.on(_this.target, openEvent, function () {
      _this.open();
    });

    $.on(_this.target, closeEvent, function () {
      _this.close();
    });
  }

  /**
   * 打开 Tooltip
   * @param opts 允许每次打开时设置不同的参数
   */
  Tooltip.prototype.open = function (opts) {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    var oldOpts = _this.options;

    // 合并 data 属性参数
    var dataOpts = $.parseOptions(_this.target.getAttribute('mdui-tooltip'));
    _this.options = $.extend(_this.options, dataOpts);

    if (opts) {
      _this.options = $.extend(_this.options, opts);
    }

    if (oldOpts.content !== _this.options.content) {
      _this.tooltip.innerHTML = _this.options.content;
    }

    setPosition(_this);

    _this.timeoutId = setTimeout(function () {
      _this.tooltip.classList.add('mdui-tooltip-open');
      _this.state = 'opening';
      $.pluginEvent('open', 'tooltip', _this, _this.target);

      $.transitionEnd(_this.tooltip, function () {
        if (_this.tooltip.classList.contains('mdui-tooltip-open')) {
          _this.state = 'opened';
          $.pluginEvent('opened', 'tooltip', _this, _this.target);
        }
      });
    }, _this.options.delay);
  };

  /**
   * 关闭 Tooltip
   */
  Tooltip.prototype.close = function () {
    var _this = this;

    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    clearTimeout(_this.timeoutId);
    _this.tooltip.classList.remove('mdui-tooltip-open');
    _this.state = 'closing';
    $.pluginEvent('close', 'tooltip', _this, _this.target);

    $.transitionEnd(_this.tooltip, function () {
      if (!_this.tooltip.classList.contains('mdui-tooltip-open')) {
        _this.state = 'closed';
        $.pluginEvent('closed', 'tooltip', _this, _this.target);
      }
    });
  };

  /**
   * 切换 Tooltip 状态
   */
  Tooltip.prototype.toggle = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      _this.close();
    } else if (_this.state === 'closing' || _this.state === 'closed') {
      _this.open();
    }
  };

  /**
   * 获取 Tooltip 状态
   * @returns {'opening'|'opened'|'closing'|'closed'}
   */
  Tooltip.prototype.getState = function () {
    return this.state;
  };

  /**
   * 销毁 Tooltip
   */
  /*Tooltip.prototype.destroy = function () {
    var _this = this;
    clearTimeout(_this.timeoutId);
    $.data(_this.target, 'mdui.tooltip', null);
    $.remove(_this.tooltip);
  };*/

  return Tooltip;

})();

/**
 * =============================================================================
 * ************   Tooltip DATA API   ************
 * =============================================================================
 */

(function () {
  // mouseenter 不能冒泡,所以这里用 mouseover 代替
  var event = mdui.support.touch ? 'touchstart' : 'mouseover';

  $.on(document, event, '[mdui-tooltip]', function () {
    var _this = this;

    var inst = $.data(_this, 'mdui.tooltip');
    if (!inst) {
      var options = $.parseOptions(_this.getAttribute('mdui-tooltip'));
      inst = new mdui.Tooltip(_this, options);
      $.data(_this, 'mdui.tooltip', inst);

      inst.open();
    }
  });
})();

/**
 * =============================================================================
 * ************   Snackbar   ************
 * =============================================================================
 */

(function () {

  /**
   * 当前打开着的 Snackbar
   */
  var current;

  /**
   * 对列名
   * @type {string}
   */
  var queueName = '__md_snackbar';

  var DEFAULT = {
    message: '',                    // 文本内容
    timeout: 4000,                  // 在用户没有操作时多长时间自动隐藏
    buttonText: '',                 // 按钮的文本
    buttonColor: '',                // 按钮的颜色,支持 blue #90caf9 rgba(...)
    closeOnButtonClick: true,       // 点击按钮时关闭
    closeOnOutsideClick: true,      // 触摸或点击屏幕其他地方时关闭
    onClick: function () {          // 在 Snackbar 上点击的回调
    },

    onButtonClick: function () {    // 点击按钮的回调
    },

    onClose: function () {          // 关闭动画开始时的回调
    },
  };

  /**
   * 点击 Snackbar 外面的区域关闭
   * @param e
   */
  var closeOnOutsideClick = function (e) {
    if (
      !e.target.classList.contains('mdui-snackbar') &&
      !$.parents(e.target, '.mdui-snackbar').length
    ) {
      current.close();
    }
  };

  /**
   * Snackbar 实例
   * @param opts
   * @constructor
   */
  function Snackbar(opts) {
    var _this = this;

    _this.options = $.extend(DEFAULT, (opts || {}));

    // message 参数必须
    if (!_this.options.message) {
      return;
    }

    _this.state = 'closed';

    // 按钮颜色
    var buttonColorStyle = '';
    var buttonColorClass = '';

    if (
      _this.options.buttonColor.indexOf('#') === 0 ||
      _this.options.buttonColor.indexOf('rgb') === 0
    ) {
      buttonColorStyle = 'style="color:' + _this.options.buttonColor + '"';
    }else if (_this.options.buttonColor !== '') {
      buttonColorClass = 'mdui-text-color-' + _this.options.buttonColor;
    }

    // 添加 HTML
    var tpl =
      '<div class="mdui-snackbar ' +
          (mdui.screen.mdUp() ? 'mdui-snackbar-desktop' : 'mdui-snackbar-mobile') +
      '">' +
        '<div class="mdui-snackbar-text">' +
          _this.options.message +
        '</div>' +
        (_this.options.buttonText ?
          ('<a href="javascript:void(0)" ' +
          'class="mdui-snackbar-action mdui-btn mdui-ripple mdui-ripple-white ' +
            buttonColorClass + '" ' +
            buttonColorStyle + '>' +
            _this.options.buttonText +
          '</a>') :
          ''
        ) +
      '</div>';
    _this.snackbar = $.dom(tpl)[0];
    document.body.appendChild(_this.snackbar);

    // 设置位置
    $.transform(_this.snackbar, 'translateY(' + _this.snackbar.clientHeight + 'px)');
    _this.snackbar.style.left = (document.body.clientWidth - _this.snackbar.clientWidth) / 2 + 'px';
    _this.snackbar.classList.add('mdui-snackbar-transition');
  }

  /**
   * 打开 Snackbar
   */
  Snackbar.prototype.open = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    // 如果当前有正在显示的 Snackbar,则先加入队列,等旧 Snackbar 关闭后再打开
    if (current) {
      $.queue(queueName, function () {
        _this.open();
      });

      return;
    }

    current = _this;

    // 开始打开
    _this.state = 'opening';
    $.transform(_this.snackbar, 'translateY(0)');

    $.transitionEnd(_this.snackbar, function () {
      if (_this.state !== 'opening') {
        return;
      }

      _this.state = 'opened';

      // 有按钮时绑定事件
      if (_this.options.buttonText) {
        var action = $.query('.mdui-snackbar-action', _this.snackbar);
        $.on(action, 'click', function () {
          _this.options.onButtonClick();
          if (_this.options.closeOnButtonClick) {
            _this.close();
          }
        });
      }

      // 点击 Snackbar 的事件
      $.on(_this.snackbar, 'click', function (e) {
        if (!e.target.classList.contains('mdui-snackbar-action')) {
          _this.options.onClick();
        }
      });

      // 点击 Snackbar 外面的区域关闭
      if (_this.options.closeOnOutsideClick) {
        $.on(document, mdui.support.touch ? 'touchstart' : 'click', closeOnOutsideClick);
      }

      // 超时后自动关闭
      _this.timeoutId = setTimeout(function () {
        _this.close();
      }, _this.options.timeout);

    });
  };

  /**
   * 关闭 Snackbar
   */
  Snackbar.prototype.close = function () {
    var _this = this;

    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    if (typeof _this.timeoutId !== 'undefined') {
      clearTimeout(_this.timeoutId);
    }

    if (_this.options.closeOnOutsideClick) {
      $.off(document, mdui.support.touch ? 'touchstart' : 'click', closeOnOutsideClick);
    }

    _this.state = 'closing';
    $.transform(_this.snackbar, 'translateY(' + _this.snackbar.clientHeight + 'px)');
    _this.options.onClose();

    $.transitionEnd(_this.snackbar, function () {
      if (_this.state !== 'closing') {
        return;
      }

      current = null;
      _this.state = 'closed';
      $.remove(_this.snackbar);
      $.dequeue(queueName);
    });
  };

  /**
   * 打开 Snackbar
   * @param params
   */
  mdui.snackbar = function (params) {
    var inst = new Snackbar(params);

    inst.open();
    return inst;
  };

})();

/**
 * =============================================================================
 * ************   Bottom navigation 底部导航栏   ************
 * =============================================================================
 */

(function () {

  // 切换导航项
  $.on(document, 'click', '.mdui-bottom-nav>a', function () {
    var _this = this;
    var bottomNav = $.parent(_this, '.mdui-bottom-nav');
    var items = $.children(bottomNav, 'a');

    $.each(items, function (i, curItem) {
      if (_this === curItem) {
        $.pluginEvent('change', 'bottomNav', null, bottomNav, {
          index: i,
        });

        curItem.classList.add('mdui-bottom-nav-active');
      } else {
        curItem.classList.remove('mdui-bottom-nav-active');
      }
    });
  });

  // 滚动时隐藏 mdui-bottom-nav-scroll-hide
  $.each($.queryAll('.mdui-bottom-nav-scroll-hide'), function (i, bottomNav) {
    var inst = new mdui.Headroom(bottomNav, {
      pinnedClass: 'mdui-headroom-pinned-down',
      unpinnedClass: 'mdui-headroom-unpinned-down',
    });
    $.data(bottomNav, 'mdui.headroom', inst);
  });

})();

/**
 * =============================================================================
 * ************   Spinner 圆形进度条   ************
 * =============================================================================
 */

(function () {
  /**
   * layer 的 HTML 结构
   */
  var layerHTML = function () {
    var i = arguments.length === 1 ? arguments[0] : false;

    return '<div class="mdui-spinner-layer ' + (i ? 'mdui-spinner-layer-' + i : '') + '">' +
               '<div class="mdui-spinner-circle-clipper mdui-spinner-left">' +
             '<div class="mdui-spinner-circle"></div>' +
             '</div>' +
             '<div class="mdui-spinner-gap-patch">' +
               '<div class="mdui-spinner-circle"></div>' +
             '</div>' +
             '<div class="mdui-spinner-circle-clipper mdui-spinner-right">' +
               '<div class="mdui-spinner-circle"></div>' +
             '</div>' +
           '</div>';
  };

  /**
   * 填充 HTML
   * @param spinner
   */
  var fillHTML = function (spinner) {
    var layer;
    if (spinner.classList.contains('mdui-spinner-colorful')) {
      layer = layerHTML('1') + layerHTML('2') + layerHTML('3') + layerHTML('4');
    } else {
      layer = layerHTML();
    }

    spinner.innerHTML = layer;
  };

  /**
   * 页面加载完后自动填充 HTML 结构
   */
  $.ready(function () {
    var spinners = $.queryAll('.mdui-spinner');
    $.each(spinners, function (i, spinner) {
      fillHTML(spinner);
    });
  });

  /**
   * 更新圆形进度条
   */
  mdui.updateSpinners = function () {
    var spinners;

    if (arguments.length === 1) {
      spinners = $.dom(arguments[0]);
    } else {
      spinners = $.queryAll('.mdui-spinner');
    }

    $.each(spinners, function (i, spinner) {
      fillHTML(spinner);
    });
  };

})();

/**
 * =============================================================================
 * ************   Expansion panel 可扩展面板   ************
 * =============================================================================
 */

mdui.Panel = (function () {

  function Panel(selector, opts) {
    return new $.Collapse(selector, opts, {
      item: 'mdui-panel-item',
      itemOpen: 'mdui-panel-item-open',
      header: 'mdui-panel-item-header',
      body: 'mdui-panel-item-body',
    }, 'panel');
  }

  return Panel;

})();

/**
 * =============================================================================
 * ************   Expansion panel 自定义属性   ************
 * =============================================================================
 */

$.ready(function () {

  // 实例化插件
  $.each($.queryAll('[mdui-panel]'), function (i, target) {
    var options = $.parseOptions(target.getAttribute('mdui-panel'));

    var inst = $.data(target, 'mdui.panel');
    if (!inst) {
      inst = new mdui.Panel(target, options);
      $.data(target, 'mdui.panel', inst);
    }
  });
});

/**
 * =============================================================================
 * ************   Menu 菜单   ************
 * =============================================================================
 */

mdui.Menu = (function () {

  /**
   * 默认参数
   */
  var DEFAULT = {
    position: 'auto',         // 菜单位置 top、bottom、center、auto
    align: 'auto',            // 菜单和触发它的元素的对齐方式 left、right、center、auto
    gutter: 16,               // 菜单距离窗口边缘的最小距离,单位 px
    fixed: false,             // 是否使菜单固定在窗口,不随滚动条滚动
    covered: 'auto',          // 菜单是否覆盖在触发它的元素上,true、false。auto 时简单菜单覆盖,级联菜单不覆盖
    subMenuTrigger: 'hover',  // 子菜单的触发方式 hover、click
    subMenuDelay: 200,        // 子菜单的触发延时,仅在 submenuTrigger 为 hover 有效
  };

  /**
   * 类名
   */
  var CLASS = {
    menu: 'mdui-menu',                    // 菜单基础类
    cascade: 'mdui-menu-cascade',         // 级联菜单
    open: 'mdui-menu-open',               // 打开状态的菜单
    item: 'mdui-menu-item',               // 菜单条目
    active: 'mdui-menu-item-active',      // 激活状态的菜单
    divider: 'mdui-divider',              // 分隔线
  };

  /**
   * 调整主菜单位置
   * @param _this 实例
   */
  var readjust = function (_this) {
    var menuLeft;
    var menuTop;

    // 菜单位置和方向
    var position;
    var align;

    // window 窗口的宽度和高度
    var windowHeight = document.documentElement.clientHeight;
    var windowWidth = document.documentElement.clientWidth;

    // 配置参数
    var gutter = _this.options.gutter;
    var isCovered = _this.isCovered;
    var isFixed = _this.options.fixed;

    // 动画方向参数
    var transformOriginX;
    var transformOriginY;

    // 菜单的原始宽度和高度
    var menuWidth = parseFloat($.getStyle(_this.menu, 'width'));
    var menuHeight = parseFloat($.getStyle(_this.menu, 'height'));

    var anchor = _this.anchor;

    // 触发菜单的元素在窗口中的位置
    var anchorTmp = anchor.getBoundingClientRect();
    var anchorTop = anchorTmp.top;
    var anchorLeft = anchorTmp.left;
    var anchorHeight = anchorTmp.height;
    var anchorWidth = anchorTmp.width;
    var anchorBottom = windowHeight - anchorTop - anchorHeight;
    var anchorRight = windowWidth - anchorLeft - anchorWidth;

    // 触发元素相对其拥有定位属性的父元素的位置
    var anchorOffsetTop = anchor.offsetTop;
    var anchorOffsetLeft = anchor.offsetLeft;

    // ===============================
    // ================= 自动判断菜单位置
    // ===============================
    if (_this.options.position === 'auto') {

      // 判断下方是否放得下菜单
      if (anchorBottom + (isCovered ? anchorHeight : 0) > menuHeight + gutter) {
        position = 'bottom';
      }

      // 判断上方是否放得下菜单
      else if (anchorTop + (isCovered ? anchorHeight : 0) > menuHeight + gutter) {
        position = 'top';
      }

      // 上下都放不下,居中显示
      else {
        position = 'center';
      }
    } else {
      position = _this.options.position;
    }

    // ===============================
    // ============== 自动判断菜单对齐方式
    // ===============================
    if (_this.options.align === 'auto') {

      // 判断右侧是否放得下菜单
      if (anchorRight + anchorWidth > menuWidth + gutter) {
        align = 'left';
      }

      // 判断左侧是否放得下菜单
      else if (anchorLeft + anchorWidth > menuWidth + gutter) {
        align = 'right';
      }

      // 左右都放不下,居中显示
      else {
        align = 'center';
      }
    } else {
      align = _this.options.align;
    }

    // ===============================
    // ==================== 设置菜单位置
    // ===============================
    if (position === 'bottom') {
      transformOriginY = '0';

      menuTop =
        (isCovered ? 0 : anchorHeight) +
        (isFixed ? anchorTop : anchorOffsetTop);

    } else if (position === 'top') {
      transformOriginY = '100%';

      menuTop =
        (isCovered ? anchorHeight : 0) +
        (isFixed ? (anchorTop - menuHeight) : (anchorOffsetTop - menuHeight));

    } else {
      transformOriginY = '50%';

      // =====================在窗口中居中
      // 显示的菜单的高度,简单菜单高度不超过窗口高度,若超过了则在菜单内部显示滚动条
      // 级联菜单内部不允许出现滚动条
      var menuHeightTemp = menuHeight;

      // 简单菜单比窗口高时,限制菜单高度
      if (!_this.menu.classList.contains('mdui-menu-cascade')) {
        if (menuHeight + gutter * 2 > windowHeight) {
          menuHeightTemp = windowHeight - gutter * 2;
          _this.menu.style.height = menuHeightTemp + 'px';
        }
      }

      menuTop =
        (windowHeight - menuHeightTemp) / 2 +
        (isFixed ? 0 : (anchorOffsetTop - anchorTop));
    }

    _this.menu.style.top = menuTop + 'px';

    // ===============================
    // ================= 设置菜单对齐方式
    // ===============================
    if (align === 'left') {
      transformOriginX = '0';

      menuLeft = isFixed ? anchorLeft : anchorOffsetLeft;

    } else if (align === 'right') {
      transformOriginX = '100%';

      menuLeft = isFixed ?
        (anchorLeft + anchorWidth - menuWidth) :
        (anchorOffsetLeft + anchorWidth - menuWidth);
    } else {
      transformOriginX = '50%';

      //=======================在窗口中居中
      // 显示的菜单的宽度,菜单宽度不能超过窗口宽度
      var menuWidthTemp = menuWidth;

      // 菜单比窗口宽,限制菜单宽度
      if (menuWidth + gutter * 2 > windowWidth) {
        menuWidthTemp = windowWidth - gutter * 2;
        _this.menu.style.width = menuWidthTemp + 'px';
      }

      menuLeft =
        (windowWidth - menuWidthTemp) / 2 +
        (isFixed ? 0 : anchorOffsetLeft - anchorLeft);
    }

    _this.menu.style.left = menuLeft + 'px';

    // 设置菜单动画方向
    $.transformOrigin(_this.menu, transformOriginX + ' ' + transformOriginY);
  };

  /**
   * 调整子菜单的位置
   * @param submenu
   */
  var readjustSubmenu = function (submenu) {
    var item = $.parent(submenu, '.' + CLASS.item);

    var submenuTop;
    var submenuLeft;

    // 子菜单位置和方向
    var position; // top、bottom
    var align; // left、right

    // window 窗口的宽度和高度
    var windowHeight = document.documentElement.clientHeight;
    var windowWidth = document.documentElement.clientWidth;

    // 动画方向参数
    var transformOriginX;
    var transformOriginY;

    // 子菜单的原始宽度和高度
    var submenuWidth = parseFloat($.getStyle(submenu, 'width'));
    var submenuHeight = parseFloat($.getStyle(submenu, 'height'));

    // 触发子菜单的菜单项的宽度高度
    var itemTmp = item.getBoundingClientRect();
    var itemWidth = itemTmp.width;
    var itemHeight = itemTmp.height;
    var itemLeft = itemTmp.left;
    var itemTop = itemTmp.top;

    // ===================================
    // ===================== 判断菜单上下位置
    // ===================================

    // 判断下方是否放得下菜单
    if (windowHeight - itemTop > submenuHeight) {
      position = 'bottom';
    }

    // 判断上方是否放得下菜单
    else if (itemTop + itemHeight > submenuHeight) {
      position = 'top';
    }

    // 默认放在下方
    else {
      position = 'bottom';
    }

    // ====================================
    // ====================== 判断菜单左右位置
    // ====================================

    // 判断右侧是否放得下菜单
    if (windowWidth - itemLeft - itemWidth > submenuWidth) {
      align = 'left';
    }

    // 判断左侧是否放得下菜单
    else if (itemLeft > submenuWidth) {
      align = 'right';
    }

    // 默认放在右侧
    else {
      align = 'left';
    }

    // ===================================
    // ======================== 设置菜单位置
    // ===================================
    if (position === 'bottom') {
      transformOriginY = '0';
      submenuTop = '0';
    } else if (position === 'top') {
      transformOriginY = '100%';
      submenuTop = -submenuHeight + itemHeight;
    }

    submenu.style.top = submenuTop + 'px';

    // ===================================
    // ===================== 设置菜单对齐方式
    // ===================================
    if (align === 'left') {
      transformOriginX = '0';
      submenuLeft = itemWidth;
    } else if (align === 'right') {
      transformOriginX = '100%';
      submenuLeft = -submenuWidth;
    }

    submenu.style.left = submenuLeft + 'px';

    // 设置菜单动画方向
    $.transformOrigin(submenu, transformOriginX + ' ' + transformOriginY);
  };

  /**
   * 打开子菜单
   * @param submenu
   */
  var openSubMenu = function (submenu) {
    readjustSubmenu(submenu);
    submenu.classList.add(CLASS.open);

    // 菜单项上添加激活状态的样式
    var item = $.parent(submenu, '.' + CLASS.item);
    item.classList.add(CLASS.active);
  };

  /**
   * 关闭子菜单,及其嵌套的子菜单
   * @param submenu
   */
  var closeSubMenu = function (submenu) {
    var item;

    // 关闭子菜单
    submenu.classList.remove(CLASS.open);

    // 移除激活状态的样式
    item = $.parent(submenu, '.' + CLASS.item);
    item.classList.remove(CLASS.active);

    // 循环关闭嵌套的子菜单
    var submenus = $.queryAll('.' + CLASS.menu, submenu);
    $.each(submenus, function (i, tmp) {
      tmp.classList.remove(CLASS.open);

      // 移除激活状态的样式
      item = $.parent(tmp, '.' + CLASS.item);
      item.classList.remove(CLASS.active);
    });
  };

  /**
   * 切换子菜单状态
   * @param submenu
   */
  var toggleSubMenu = function (submenu) {
    if (submenu.classList.contains(CLASS.open)) {
      closeSubMenu(submenu);
    } else {
      openSubMenu(submenu);
    }
  };

  /**
   * 绑定子菜单事件
   * @param inst 实例
   */
  var bindSubMenuEvent = function (inst) {
    var trigger;
    var delay;

    if (inst.options.subMenuTrigger === 'hover' && !mdui.support.touch) {
      trigger = 'mouseover mouseout';
      delay = inst.options.subMenuDelay;
    } else {
      trigger = 'click';
      delay = 0;
    }

    // subMneuTrigger: 'click'
    if (trigger === 'click') {
      $.on(inst.menu, trigger, '.' + CLASS.item, function (e) {
        var _this = this;

        // 禁用状态菜单不操作
        if (_this.getAttribute('disabled') !== null) {
          return;
        }

        // 没有点击在子菜单的菜单项上时,不操作(点在了子菜单的空白区域、或分隔线上)
        if ($.is(e.target, '.' + CLASS.menu) || $.is(e.target, '.' + CLASS.divider)) {
          return;
        }

        // 阻止冒泡,点击菜单项时只在最后一级的 mdui-menu-item 上生效,不向上冒泡
        if ($.parents(e.target, '.' + CLASS.item)[0] !== _this) {
          return;
        }

        var submenu = $.child(_this, '.' + CLASS.menu);

        // 先关闭除当前子菜单外的所有同级子菜单
        var menu = $.parent(_this, '.' + CLASS.menu);
        var items = $.children(menu, '.' + CLASS.item);
        $.each(items, function (i, item) {
          var tmpSubmenu = $.child(item, '.' + CLASS.menu);
          if (
            tmpSubmenu &&
            (!submenu || !$.is(tmpSubmenu, submenu))
          ) {
            closeSubMenu(tmpSubmenu);
          }
        });

        // 切换当前子菜单
        if (submenu) {
          toggleSubMenu(submenu);
        }
      });
    }

    // subMenuTrigger: 'hover'
    else {

      // 临时存储 setTimeout 对象
      var timeout;

      var timeoutOpen;
      var timeoutClose;

      $.on(inst.menu, trigger, '.' + CLASS.item, function (e) {
        var _this = this;
        var eventType = e.type;
        var relatedTarget = e.relatedTarget;

        // 禁用状态的菜单不操作
        if (_this.getAttribute('disabled') !== null) {
          return;
        }

        // 用 mouseover 模拟 mouseenter
        if (eventType === 'mouseover') {
          if (_this !== relatedTarget && $.contains(_this, relatedTarget)) {
            return;
          }
        }

        // 用 mouseout 模拟 mouseleave
        else if (eventType === 'mouseout') {
          if (_this === relatedTarget || $.contains(_this, relatedTarget)) {
            return;
          }
        }

        // 当前菜单项下的子菜单,未必存在
        var submenu = $.child(_this, '.' + CLASS.menu);

        // 鼠标移入菜单项时,显示菜单项下的子菜单
        if (eventType === 'mouseover') {
          if (submenu) {

            // 当前子菜单准备打开时,如果当前子菜单正准备着关闭,不用再关闭了
            var tmpClose = $.data(submenu, 'timeoutClose.mdui.menu');
            if (tmpClose) {
              clearTimeout(tmpClose);
            }

            // 如果当前子菜单已经打开,不操作
            if (submenu.classList.contains(CLASS.open)) {
              return;
            }

            // 当前子菜单准备打开时,其他准备打开的子菜单不用再打开了
            clearTimeout(timeoutOpen);

            // 准备打开当前子菜单
            timeout = timeoutOpen = setTimeout(function () {
              openSubMenu(submenu);
            }, delay);

            $.data(submenu, 'timeoutOpen.mdui.menu', timeout);
          }
        }

        // 鼠标移出菜单项时,关闭菜单项下的子菜单
        else if (eventType === 'mouseout') {
          if (submenu) {

            // 鼠标移出菜单项时,如果当前菜单项下的子菜单正准备打开,不用再打开了
            var tmpOpen = $.data(submenu, 'timeoutOpen.mdui.menu');
            if (tmpOpen) {
              clearTimeout(tmpOpen);
            }

            // 准备关闭当前子菜单
            timeout = timeoutClose = setTimeout(function () {
              closeSubMenu(submenu);
            }, delay);

            $.data(submenu, 'timeoutClose.mdui.menu', timeout);
          }
        }
      });
    }
  };

  /**
   * 菜单
   * @param anchorSelector 点击该元素触发菜单
   * @param menuSelector 菜单
   * @param opts 配置项
   * @constructor
   */
  function Menu(anchorSelector, menuSelector, opts) {
    var _this = this;

    // 触发菜单的元素
    _this.anchor = $.dom(anchorSelector)[0];
    if (typeof _this.anchor === 'undefined') {
      return;
    }

    // 已通过自定义属性实例化过,不再重复实例化
    var oldInst = $.data(_this.anchor, 'mdui.menu');
    if (oldInst) {
      return oldInst;
    }

    _this.menu = $.dom(menuSelector)[0];

    // 触发菜单的元素 和 菜单必须时同级的元素,否则菜单可能不能定位
    if (!$.child(_this.anchor.parentNode, _this.menu)) {
      return;
    }

    _this.options = $.extend(DEFAULT, (opts || {}));
    _this.state = 'closed';

    // 是否是级联菜单
    _this.isCascade = _this.menu.classList.contains(CLASS.cascade);

    // covered 参数处理
    if (_this.options.covered === 'auto') {
      _this.isCovered = !_this.isCascade;
    } else {
      _this.isCovered = _this.options.covered;
    }

    // 点击触发菜单切换
    $.on(_this.anchor, 'click', function () {
      _this.toggle();
    });

    // 点击菜单外面区域关闭菜单
    $.on(document, 'click touchstart', function (e) {
      if (
        (_this.state === 'opening' || _this.state === 'opened') &&
        !$.is(e.target, _this.menu) &&
        !$.contains(_this.menu, e.target) &&
        !$.is(e.target, _this.anchor) &&
        !$.contains(_this.anchor, e.target)
      ) {
        _this.close();
      }
    });

    // 点击不含子菜单的菜单条目关闭菜单
    $.on(document, 'click', '.' + CLASS.item, function () {
      if (!$.query('.' + CLASS.menu, this) && this.getAttribute('disabled') === null) {
        _this.close();
      }
    });

    // 绑定点击或鼠标移入含子菜单的条目的事件
    bindSubMenuEvent(_this);

    // 窗口大小变化时,重新调整菜单位置
    $.on(window, 'resize', mdui.throttle(function () {
      readjust(_this);
    }, 100));
  }

  /**
   * 切换菜单状态
   */
  Menu.prototype.toggle = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      _this.close();
    } else if (_this.state === 'closing' || _this.state === 'closed') {
      _this.open();
    }
  };

  /**
   * 打开菜单
   */
  Menu.prototype.open = function () {
    var _this = this;

    if (_this.state === 'opening' || _this.state === 'opened') {
      return;
    }

    _this.state = 'opening';

    // 调整菜单位置
    readjust(_this);

    // 菜单隐藏状态使用使用 fixed 定位。
    _this.menu.style.position = _this.options.fixed ? 'fixed' : 'absolute';

    // 打开菜单
    _this.menu.classList.add(CLASS.open);
    $.pluginEvent('open', 'menu', _this, _this.menu);

    // 打开动画完成后
    $.transitionEnd(_this.menu, function () {

      // 如果打开动画结束前,菜单状态已经改变了,则不触发 opened 事件
      if (_this.state !== 'opening') {
        return;
      }

      _this.state = 'opened';
      $.pluginEvent('opened', 'menu', _this, _this.menu);
    });
  };

  /**
   * 关闭菜单
   */
  Menu.prototype.close = function () {
    var _this = this;
    if (_this.state === 'closing' || _this.state === 'closed') {
      return;
    }

    _this.menu.classList.remove(CLASS.open);
    _this.state = 'closing';
    $.pluginEvent('close', 'menu', _this, _this.menu);

    // 菜单开始关闭时,关闭所有子菜单
    $.each($.queryAll('.mdui-menu', _this.menu), function (i, submenu) {
      closeSubMenu(submenu);
    });

    // 关闭动画完成后
    $.transitionEnd(_this.menu, function () {

      // 如果关闭动画完成前,菜单状态又改变了,则不触发 closed 事件
      if (_this.state !== 'closing') {
        return;
      }

      _this.state = 'closed';
      $.pluginEvent('closed', 'menu', _this, _this.menu);

      // 关闭后,恢复菜单样式到默认状态
      _this.menu.style.top = '';
      _this.menu.style.left = '';
      _this.menu.style.width = '';

      // 关闭后,恢复 fixed 定位
      _this.menu.style.position = 'fixed';
    });
  };

  return Menu;
})();

/**
 * =============================================================================
 * ************   Menu 自定义属性 API   ************
 * =============================================================================
 */

$.ready(function () {

  $.on(document, 'click', '[mdui-menu]', function () {
    var _this = this;

    var inst = $.data(_this, 'mdui.menu');
    if (!inst) {
      var options = $.parseOptions(_this.getAttribute('mdui-menu'));
      var menuSelector = options.target;
      delete options.target;

      inst = new mdui.Menu(_this, menuSelector, options);
      $.data(_this, 'mdui.menu', inst);

      inst.toggle();
    }
  });
});

/* jshint ignore:start */
window.mdui = mdui;

})(window, document); /* jshint ignore:end */