/*!
 * mdui 1.0.1 (https://mdui.org)
 * Copyright 2016-2020 zdhxiong
 * Licensed under MIT
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mdui = factory());
}(this, (function () { 'use strict';

  !function(){try{return new MouseEvent("test")}catch(e$1){}var e=function(e,t){t=t||{bubbles:!1,cancelable:!1};var n=document.createEvent("MouseEvent");return n.initMouseEvent(e,t.bubbles,t.cancelable,window,0,t.screenX||0,t.screenY||0,t.clientX||0,t.clientY||0,t.ctrlKey||!1,t.altKey||!1,t.shiftKey||!1,t.metaKey||!1,t.button||0,t.relatedTarget||null),n};e.prototype=Event.prototype,window.MouseEvent=e;}();

  !function(){function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n}"function"!=typeof window.CustomEvent&&(t.prototype=window.Event.prototype,window.CustomEvent=t);}();

  /**
   * @this {Promise}
   */
  function finallyConstructor(callback) {
    var constructor = this.constructor;
    return this.then(
      function(value) {
        // @ts-ignore
        return constructor.resolve(callback()).then(function() {
          return value;
        });
      },
      function(reason) {
        // @ts-ignore
        return constructor.resolve(callback()).then(function() {
          // @ts-ignore
          return constructor.reject(reason);
        });
      }
    );
  }

  function allSettled(arr) {
    var P = this;
    return new P(function(resolve, reject) {
      if (!(arr && typeof arr.length !== 'undefined')) {
        return reject(
          new TypeError(
            typeof arr +
              ' ' +
              arr +
              ' is not iterable(cannot read property Symbol(Symbol.iterator))'
          )
        );
      }
      var args = Array.prototype.slice.call(arr);
      if (args.length === 0) { return resolve([]); }
      var remaining = args.length;

      function res(i, val) {
        if (val && (typeof val === 'object' || typeof val === 'function')) {
          var then = val.then;
          if (typeof then === 'function') {
            then.call(
              val,
              function(val) {
                res(i, val);
              },
              function(e) {
                args[i] = { status: 'rejected', reason: e };
                if (--remaining === 0) {
                  resolve(args);
                }
              }
            );
            return;
          }
        }
        args[i] = { status: 'fulfilled', value: val };
        if (--remaining === 0) {
          resolve(args);
        }
      }

      for (var i = 0; i < args.length; i++) {
        res(i, args[i]);
      }
    });
  }

  // Store setTimeout reference so promise-polyfill will be unaffected by
  // other code modifying setTimeout (like sinon.useFakeTimers())
  var setTimeoutFunc = setTimeout;

  function isArray(x) {
    return Boolean(x && typeof x.length !== 'undefined');
  }

  function noop() {}

  // Polyfill for Function.prototype.bind
  function bind(fn, thisArg) {
    return function() {
      fn.apply(thisArg, arguments);
    };
  }

  /**
   * @constructor
   * @param {Function} fn
   */
  function Promise$1(fn) {
    if (!(this instanceof Promise$1))
      { throw new TypeError('Promises must be constructed via new'); }
    if (typeof fn !== 'function') { throw new TypeError('not a function'); }
    /** @type {!number} */
    this._state = 0;
    /** @type {!boolean} */
    this._handled = false;
    /** @type {Promise|undefined} */
    this._value = undefined;
    /** @type {!Array<!Function>} */
    this._deferreds = [];

    doResolve(fn, this);
  }

  function handle(self, deferred) {
    while (self._state === 3) {
      self = self._value;
    }
    if (self._state === 0) {
      self._deferreds.push(deferred);
      return;
    }
    self._handled = true;
    Promise$1._immediateFn(function() {
      var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
      if (cb === null) {
        (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
        return;
      }
      var ret;
      try {
        ret = cb(self._value);
      } catch (e) {
        reject(deferred.promise, e);
        return;
      }
      resolve(deferred.promise, ret);
    });
  }

  function resolve(self, newValue) {
    try {
      // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
      if (newValue === self)
        { throw new TypeError('A promise cannot be resolved with itself.'); }
      if (
        newValue &&
        (typeof newValue === 'object' || typeof newValue === 'function')
      ) {
        var then = newValue.then;
        if (newValue instanceof Promise$1) {
          self._state = 3;
          self._value = newValue;
          finale(self);
          return;
        } else if (typeof then === 'function') {
          doResolve(bind(then, newValue), self);
          return;
        }
      }
      self._state = 1;
      self._value = newValue;
      finale(self);
    } catch (e) {
      reject(self, e);
    }
  }

  function reject(self, newValue) {
    self._state = 2;
    self._value = newValue;
    finale(self);
  }

  function finale(self) {
    if (self._state === 2 && self._deferreds.length === 0) {
      Promise$1._immediateFn(function() {
        if (!self._handled) {
          Promise$1._unhandledRejectionFn(self._value);
        }
      });
    }

    for (var i = 0, len = self._deferreds.length; i < len; i++) {
      handle(self, self._deferreds[i]);
    }
    self._deferreds = null;
  }

  /**
   * @constructor
   */
  function Handler(onFulfilled, onRejected, promise) {
    this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
    this.onRejected = typeof onRejected === 'function' ? onRejected : null;
    this.promise = promise;
  }

  /**
   * Take a potentially misbehaving resolver function and make sure
   * onFulfilled and onRejected are only called once.
   *
   * Makes no guarantees about asynchrony.
   */
  function doResolve(fn, self) {
    var done = false;
    try {
      fn(
        function(value) {
          if (done) { return; }
          done = true;
          resolve(self, value);
        },
        function(reason) {
          if (done) { return; }
          done = true;
          reject(self, reason);
        }
      );
    } catch (ex) {
      if (done) { return; }
      done = true;
      reject(self, ex);
    }
  }

  Promise$1.prototype['catch'] = function(onRejected) {
    return this.then(null, onRejected);
  };

  Promise$1.prototype.then = function(onFulfilled, onRejected) {
    // @ts-ignore
    var prom = new this.constructor(noop);

    handle(this, new Handler(onFulfilled, onRejected, prom));
    return prom;
  };

  Promise$1.prototype['finally'] = finallyConstructor;

  Promise$1.all = function(arr) {
    return new Promise$1(function(resolve, reject) {
      if (!isArray(arr)) {
        return reject(new TypeError('Promise.all accepts an array'));
      }

      var args = Array.prototype.slice.call(arr);
      if (args.length === 0) { return resolve([]); }
      var remaining = args.length;

      function res(i, val) {
        try {
          if (val && (typeof val === 'object' || typeof val === 'function')) {
            var then = val.then;
            if (typeof then === 'function') {
              then.call(
                val,
                function(val) {
                  res(i, val);
                },
                reject
              );
              return;
            }
          }
          args[i] = val;
          if (--remaining === 0) {
            resolve(args);
          }
        } catch (ex) {
          reject(ex);
        }
      }

      for (var i = 0; i < args.length; i++) {
        res(i, args[i]);
      }
    });
  };

  Promise$1.allSettled = allSettled;

  Promise$1.resolve = function(value) {
    if (value && typeof value === 'object' && value.constructor === Promise$1) {
      return value;
    }

    return new Promise$1(function(resolve) {
      resolve(value);
    });
  };

  Promise$1.reject = function(value) {
    return new Promise$1(function(resolve, reject) {
      reject(value);
    });
  };

  Promise$1.race = function(arr) {
    return new Promise$1(function(resolve, reject) {
      if (!isArray(arr)) {
        return reject(new TypeError('Promise.race accepts an array'));
      }

      for (var i = 0, len = arr.length; i < len; i++) {
        Promise$1.resolve(arr[i]).then(resolve, reject);
      }
    });
  };

  // Use polyfill for setImmediate for performance gains
  Promise$1._immediateFn =
    // @ts-ignore
    (typeof setImmediate === 'function' &&
      function(fn) {
        // @ts-ignore
        setImmediate(fn);
      }) ||
    function(fn) {
      setTimeoutFunc(fn, 0);
    };

  Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
    if (typeof console !== 'undefined' && console) {
      console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
    }
  };

  /** @suppress {undefinedVars} */
  var globalNS = (function() {
    // the only reliable means to get the global object is
    // `Function('return this')()`
    // However, this causes CSP violations in Chrome apps.
    if (typeof self !== 'undefined') {
      return self;
    }
    if (typeof window !== 'undefined') {
      return window;
    }
    if (typeof global !== 'undefined') {
      return global;
    }
    throw new Error('unable to locate global object');
  })();

  // Expose the polyfill if Promise is undefined or set to a
  // non-function value. The latter can be due to a named HTMLElement
  // being exposed by browsers for legacy reasons.
  // https://github.com/taylorhakes/promise-polyfill/issues/114
  if (typeof globalNS['Promise'] !== 'function') {
    globalNS['Promise'] = Promise$1;
  } else if (!globalNS.Promise.prototype['finally']) {
    globalNS.Promise.prototype['finally'] = finallyConstructor;
  } else if (!globalNS.Promise.allSettled) {
    globalNS.Promise.allSettled = allSettled;
  }

  function isFunction(target) {
      return typeof target === 'function';
  }
  function isString(target) {
      return typeof target === 'string';
  }
  function isNumber(target) {
      return typeof target === 'number';
  }
  function isBoolean(target) {
      return typeof target === 'boolean';
  }
  function isUndefined(target) {
      return typeof target === 'undefined';
  }
  function isNull(target) {
      return target === null;
  }
  function isWindow(target) {
      return target instanceof Window;
  }
  function isDocument(target) {
      return target instanceof Document;
  }
  function isElement(target) {
      return target instanceof Element;
  }
  function isNode(target) {
      return target instanceof Node;
  }
  /**
   * 是否是 IE 浏览器
   */
  function isIE() {
      // @ts-ignore
      return !!window.document.documentMode;
  }
  function isArrayLike(target) {
      if (isFunction(target) || isWindow(target)) {
          return false;
      }
      return isNumber(target.length);
  }
  function isObjectLike(target) {
      return typeof target === 'object' && target !== null;
  }
  function toElement(target) {
      return isDocument(target) ? target.documentElement : target;
  }
  /**
   * 把用 - 分隔的字符串转为驼峰（如 box-sizing 转换为 boxSizing）
   * @param string
   */
  function toCamelCase(string) {
      return string
          .replace(/^-ms-/, 'ms-')
          .replace(/-([a-z])/g, function (_, letter) { return letter.toUpperCase(); });
  }
  /**
   * 把驼峰法转为用 - 分隔的字符串（如 boxSizing 转换为 box-sizing）
   * @param string
   */
  function toKebabCase(string) {
      return string.replace(/[A-Z]/g, function (replacer) { return '-' + replacer.toLowerCase(); });
  }
  /**
   * 获取元素的样式值
   * @param element
   * @param name
   */
  function getComputedStyleValue(element, name) {
      return window.getComputedStyle(element).getPropertyValue(toKebabCase(name));
  }
  /**
   * 检查元素的 box-sizing 是否是 border-box
   * @param element
   */
  function isBorderBox(element) {
      return getComputedStyleValue(element, 'box-sizing') === 'border-box';
  }
  /**
   * 获取元素的 padding, border, margin 宽度（两侧宽度的和，单位为px）
   * @param element
   * @param direction
   * @param extra
   */
  function getExtraWidth(element, direction, extra) {
      var position = direction === 'width' ? ['Left', 'Right'] : ['Top', 'Bottom'];
      return [0, 1].reduce(function (prev, _, index) {
          var prop = extra + position[index];
          if (extra === 'border') {
              prop += 'Width';
          }
          return prev + parseFloat(getComputedStyleValue(element, prop) || '0');
      }, 0);
  }
  /**
   * 获取元素的样式值，对 width 和 height 进行过处理
   * @param element
   * @param name
   */
  function getStyle(element, name) {
      // width、height 属性使用 getComputedStyle 得到的值不准确，需要使用 getBoundingClientRect 获取
      if (name === 'width' || name === 'height') {
          var valueNumber = element.getBoundingClientRect()[name];
          if (isBorderBox(element)) {
              return (valueNumber + "px");
          }
          return ((valueNumber -
              getExtraWidth(element, name, 'border') -
              getExtraWidth(element, name, 'padding')) + "px");
      }
      return getComputedStyleValue(element, name);
  }
  /**
   * 获取子节点组成的数组
   * @param target
   * @param parent
   */
  function getChildNodesArray(target, parent) {
      var tempParent = document.createElement(parent);
      tempParent.innerHTML = target;
      return [].slice.call(tempParent.childNodes);
  }
  /**
   * 始终返回 false 的函数
   */
  function returnFalse() {
      return false;
  }
  /**
   * 数值单位的 CSS 属性
   */
  var cssNumber = [
      'animationIterationCount',
      'columnCount',
      'fillOpacity',
      'flexGrow',
      'flexShrink',
      'fontWeight',
      'gridArea',
      'gridColumn',
      'gridColumnEnd',
      'gridColumnStart',
      'gridRow',
      'gridRowEnd',
      'gridRowStart',
      'lineHeight',
      'opacity',
      'order',
      'orphans',
      'widows',
      'zIndex',
      'zoom' ];

  function each(target, callback) {
      if (isArrayLike(target)) {
          for (var i = 0; i < target.length; i += 1) {
              if (callback.call(target[i], i, target[i]) === false) {
                  return target;
              }
          }
      }
      else {
          var keys = Object.keys(target);
          for (var i$1 = 0; i$1 < keys.length; i$1 += 1) {
              if (callback.call(target[keys[i$1]], keys[i$1], target[keys[i$1]]) === false) {
                  return target;
              }
          }
      }
      return target;
  }

  /**
   * 为了使用模块扩充，这里不能使用默认导出
   */
  var JQ = function JQ(arr) {
      var this$1 = this;

      this.length = 0;
      if (!arr) {
          return this;
      }
      each(arr, function (i, item) {
          // @ts-ignore
          this$1[i] = item;
      });
      this.length = arr.length;
      return this;
  };

  function get$() {
      var $ = function (selector) {
          if (!selector) {
              return new JQ();
          }
          // JQ
          if (selector instanceof JQ) {
              return selector;
          }
          // function
          if (isFunction(selector)) {
              if (/complete|loaded|interactive/.test(document.readyState) &&
                  document.body) {
                  selector.call(document, $);
              }
              else {
                  document.addEventListener('DOMContentLoaded', function () { return selector.call(document, $); }, false);
              }
              return new JQ([document]);
          }
          // String
          if (isString(selector)) {
              var html = selector.trim();
              // 根据 HTML 字符串创建 JQ 对象
              if (html[0] === '<' && html[html.length - 1] === '>') {
                  var toCreate = 'div';
                  var tags = {
                      li: 'ul',
                      tr: 'tbody',
                      td: 'tr',
                      th: 'tr',
                      tbody: 'table',
                      option: 'select',
                  };
                  each(tags, function (childTag, parentTag) {
                      if (html.indexOf(("<" + childTag)) === 0) {
                          toCreate = parentTag;
                          return false;
                      }
                      return;
                  });
                  return new JQ(getChildNodesArray(html, toCreate));
              }
              // 根据 CSS 选择器创建 JQ 对象
              var isIdSelector = selector[0] === '#' && !selector.match(/[ .<>:~]/);
              if (!isIdSelector) {
                  return new JQ(document.querySelectorAll(selector));
              }
              var element = document.getElementById(selector.slice(1));
              if (element) {
                  return new JQ([element]);
              }
              return new JQ();
          }
          if (isArrayLike(selector) && !isNode(selector)) {
              return new JQ(selector);
          }
          return new JQ([selector]);
      };
      $.fn = JQ.prototype;
      return $;
  }
  var $ = get$();

  // 避免页面加载完后直接执行css动画
  // https://css-tricks.com/transitions-only-after-page-load/
  setTimeout(function () { return $('body').addClass('mdui-loaded'); });
  var mdui = {
      $: $,
  };

  $.fn.each = function (callback) {
      return each(this, callback);
  };

  /**
   * 检查 container 元素内是否包含 contains 元素
   * @param container 父元素
   * @param contains 子元素
   * @example
  ```js
  contains( document, document.body ); // true
  contains( document.getElementById('test'), document ); // false
  contains( $('.container').get(0), $('.contains').get(0) ); // false
  ```
   */
  function contains(container, contains) {
      return container !== contains && toElement(container).contains(contains);
  }

  /**
   * 把第二个数组的元素追加到第一个数组中，并返回合并后的数组
   * @param first 第一个数组
   * @param second 该数组的元素将被追加到第一个数组中
   * @example
  ```js
  merge( [ 0, 1, 2 ], [ 2, 3, 4 ] )
  // [ 0, 1, 2, 2, 3, 4 ]
  ```
   */
  function merge(first, second) {
      each(second, function (_, value) {
          first.push(value);
      });
      return first;
  }

  $.fn.get = function (index) {
      return index === undefined
          ? [].slice.call(this)
          : this[index >= 0 ? index : index + this.length];
  };

  $.fn.find = function (selector) {
      var foundElements = [];
      this.each(function (_, element) {
          merge(foundElements, $(element.querySelectorAll(selector)).get());
      });
      return new JQ(foundElements);
  };

  // 存储事件
  var handlers = {};
  // 元素ID
  var mduiElementId = 1;
  /**
   * 为元素赋予一个唯一的ID
   */
  function getElementId(element) {
      var key = '_mduiEventId';
      // @ts-ignore
      if (!element[key]) {
          // @ts-ignore
          element[key] = ++mduiElementId;
      }
      // @ts-ignore
      return element[key];
  }
  /**
   * 解析事件名中的命名空间
   */
  function parse(type) {
      var parts = type.split('.');
      return {
          type: parts[0],
          ns: parts.slice(1).sort().join(' '),
      };
  }
  /**
   * 命名空间匹配规则
   */
  function matcherFor(ns) {
      return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
  }
  /**
   * 获取匹配的事件
   * @param element
   * @param type
   * @param func
   * @param selector
   */
  function getHandlers(element, type, func, selector) {
      var event = parse(type);
      return (handlers[getElementId(element)] || []).filter(function (handler) { return handler &&
          (!event.type || handler.type === event.type) &&
          (!event.ns || matcherFor(event.ns).test(handler.ns)) &&
          (!func || getElementId(handler.func) === getElementId(func)) &&
          (!selector || handler.selector === selector); });
  }
  /**
   * 添加事件监听
   * @param element
   * @param types
   * @param func
   * @param data
   * @param selector
   */
  function add(element, types, func, data, selector) {
      var elementId = getElementId(element);
      if (!handlers[elementId]) {
          handlers[elementId] = [];
      }
      // 传入 data.useCapture 来设置 useCapture: true
      var useCapture = false;
      if (isObjectLike(data) && data.useCapture) {
          useCapture = true;
      }
      types.split(' ').forEach(function (type) {
          if (!type) {
              return;
          }
          var event = parse(type);
          function callFn(e, elem) {
              // 因为鼠标事件模拟事件的 detail 属性是只读的，因此在 e._detail 中存储参数
              var result = func.apply(elem, 
              // @ts-ignore
              e._detail === undefined ? [e] : [e].concat(e._detail));
              if (result === false) {
                  e.preventDefault();
                  e.stopPropagation();
              }
          }
          function proxyFn(e) {
              // @ts-ignore
              if (e._ns && !matcherFor(e._ns).test(event.ns)) {
                  return;
              }
              // @ts-ignore
              e._data = data;
              if (selector) {
                  // 事件代理
                  $(element)
                      .find(selector)
                      .get()
                      .reverse()
                      .forEach(function (elem) {
                      if (elem === e.target ||
                          contains(elem, e.target)) {
                          callFn(e, elem);
                      }
                  });
              }
              else {
                  // 不使用事件代理
                  callFn(e, element);
              }
          }
          var handler = {
              type: event.type,
              ns: event.ns,
              func: func,
              selector: selector,
              id: handlers[elementId].length,
              proxy: proxyFn,
          };
          handlers[elementId].push(handler);
          element.addEventListener(handler.type, proxyFn, useCapture);
      });
  }
  /**
   * 移除事件监听
   * @param element
   * @param types
   * @param func
   * @param selector
   */
  function remove(element, types, func, selector) {
      var handlersInElement = handlers[getElementId(element)] || [];
      var removeEvent = function (handler) {
          delete handlersInElement[handler.id];
          element.removeEventListener(handler.type, handler.proxy, false);
      };
      if (!types) {
          handlersInElement.forEach(function (handler) { return removeEvent(handler); });
      }
      else {
          types.split(' ').forEach(function (type) {
              if (type) {
                  getHandlers(element, type, func, selector).forEach(function (handler) { return removeEvent(handler); });
              }
          });
      }
  }

  $.fn.trigger = function (type, extraParameters) {
      var event = parse(type);
      var eventObject;
      var eventParams = {
          bubbles: true,
          cancelable: true,
      };
      var isMouseEvent = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(event.type) > -1;
      if (isMouseEvent) {
          // Note: MouseEvent 无法传入 detail 参数
          eventObject = new MouseEvent(event.type, eventParams);
      }
      else {
          eventParams.detail = extraParameters;
          eventObject = new CustomEvent(event.type, eventParams);
      }
      // @ts-ignore
      eventObject._detail = extraParameters;
      // @ts-ignore
      eventObject._ns = event.ns;
      return this.each(function () {
          this.dispatchEvent(eventObject);
      });
  };

  function extend(target, object1) {
      var objectN = [], len = arguments.length - 2;
      while ( len-- > 0 ) objectN[ len ] = arguments[ len + 2 ];

      objectN.unshift(object1);
      each(objectN, function (_, object) {
          each(object, function (prop, value) {
              if (!isUndefined(value)) {
                  target[prop] = value;
              }
          });
      });
      return target;
  }

  /**
   * 将数组或对象序列化，序列化后的字符串可作为 URL 查询字符串使用
   *
   * 若传入数组，则格式必须和 serializeArray 方法的返回值一样
   * @param obj 对象或数组
   * @example
  ```js
  param({ width: 1680, height: 1050 });
  // width=1680&height=1050
  ```
   * @example
  ```js
  param({ foo: { one: 1, two: 2 }})
  // foo[one]=1&foo[two]=2
  ```
   * @example
  ```js
  param({ids: [1, 2, 3]})
  // ids[]=1&ids[]=2&ids[]=3
  ```
   * @example
  ```js
  param([
    {"name":"name","value":"mdui"},
    {"name":"password","value":"123456"}
  ])
  // name=mdui&password=123456
  ```
   */
  function param(obj) {
      if (!isObjectLike(obj) && !Array.isArray(obj)) {
          return '';
      }
      var args = [];
      function destructure(key, value) {
          var keyTmp;
          if (isObjectLike(value)) {
              each(value, function (i, v) {
                  if (Array.isArray(value) && !isObjectLike(v)) {
                      keyTmp = '';
                  }
                  else {
                      keyTmp = i;
                  }
                  destructure((key + "[" + keyTmp + "]"), v);
              });
          }
          else {
              if (value == null || value === '') {
                  keyTmp = '=';
              }
              else {
                  keyTmp = "=" + (encodeURIComponent(value));
              }
              args.push(encodeURIComponent(key) + keyTmp);
          }
      }
      if (Array.isArray(obj)) {
          each(obj, function () {
              destructure(this.name, this.value);
          });
      }
      else {
          each(obj, destructure);
      }
      return args.join('&');
  }

  // 全局配置参数
  var globalOptions = {};
  // 全局事件名
  var ajaxEvents = {
      ajaxStart: 'start.mdui.ajax',
      ajaxSuccess: 'success.mdui.ajax',
      ajaxError: 'error.mdui.ajax',
      ajaxComplete: 'complete.mdui.ajax',
  };

  /**
   * 判断此请求方法是否通过查询字符串提交参数
   * @param method 请求方法，大写
   */
  function isQueryStringData(method) {
      return ['GET', 'HEAD'].indexOf(method) >= 0;
  }
  /**
   * 添加参数到 URL 上，且 URL 中不存在 ? 时，自动把第一个 & 替换为 ?
   * @param url
   * @param query
   */
  function appendQuery(url, query) {
      return (url + "&" + query).replace(/[&?]{1,2}/, '?');
  }
  /**
   * 合并请求参数，参数优先级：options > globalOptions > defaults
   * @param options
   */
  function mergeOptions(options) {
      // 默认参数
      var defaults = {
          url: '',
          method: 'GET',
          data: '',
          processData: true,
          async: true,
          cache: true,
          username: '',
          password: '',
          headers: {},
          xhrFields: {},
          statusCode: {},
          dataType: 'text',
          contentType: 'application/x-www-form-urlencoded',
          timeout: 0,
          global: true,
      };
      // globalOptions 中的回调函数不合并
      each(globalOptions, function (key, value) {
          var callbacks = [
              'beforeSend',
              'success',
              'error',
              'complete',
              'statusCode' ];
          // @ts-ignore
          if (callbacks.indexOf(key) < 0 && !isUndefined(value)) {
              defaults[key] = value;
          }
      });
      return extend({}, defaults, options);
  }
  /**
   * 发送 ajax 请求
   * @param options
   * @example
  ```js
  ajax({
    method: "POST",
    url: "some.php",
    data: { name: "John", location: "Boston" }
  }).then(function( msg ) {
    alert( "Data Saved: " + msg );
  });
  ```
   */
  function ajax(options) {
      // 是否已取消请求
      var isCanceled = false;
      // 事件参数
      var eventParams = {};
      // 参数合并
      var mergedOptions = mergeOptions(options);
      var url = mergedOptions.url || window.location.toString();
      var method = mergedOptions.method.toUpperCase();
      var data = mergedOptions.data;
      var processData = mergedOptions.processData;
      var async = mergedOptions.async;
      var cache = mergedOptions.cache;
      var username = mergedOptions.username;
      var password = mergedOptions.password;
      var headers = mergedOptions.headers;
      var xhrFields = mergedOptions.xhrFields;
      var statusCode = mergedOptions.statusCode;
      var dataType = mergedOptions.dataType;
      var contentType = mergedOptions.contentType;
      var timeout = mergedOptions.timeout;
      var global = mergedOptions.global;
      // 需要发送的数据
      // GET/HEAD 请求和 processData 为 true 时，转换为查询字符串格式，特殊格式不转换
      if (data &&
          (isQueryStringData(method) || processData) &&
          !isString(data) &&
          !(data instanceof ArrayBuffer) &&
          !(data instanceof Blob) &&
          !(data instanceof Document) &&
          !(data instanceof FormData)) {
          data = param(data);
      }
      // 对于 GET、HEAD 类型的请求，把 data 数据添加到 URL 中
      if (data && isQueryStringData(method)) {
          // 查询字符串拼接到 URL 中
          url = appendQuery(url, data);
          data = null;
      }
      /**
       * 触发事件和回调函数
       * @param event
       * @param params
       * @param callback
       * @param args
       */
      function trigger(event, params, callback) {
          var args = [], len = arguments.length - 3;
          while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];

          // 触发全局事件
          if (global) {
              $(document).trigger(event, params);
          }
          // 触发 ajax 回调和事件
          var result1;
          var result2;
          if (callback) {
              // 全局回调
              if (callback in globalOptions) {
                  // @ts-ignore
                  result1 = globalOptions[callback].apply(globalOptions, args);
              }
              // 自定义回调
              if (mergedOptions[callback]) {
                  // @ts-ignore
                  result2 = mergedOptions[callback].apply(mergedOptions, args);
              }
              // beforeSend 回调返回 false 时取消 ajax 请求
              if (callback === 'beforeSend' &&
                  (result1 === false || result2 === false)) {
                  isCanceled = true;
              }
          }
      }
      // XMLHttpRequest 请求
      function XHR() {
          var textStatus;
          return new Promise(function (resolve, reject) {
              // GET/HEAD 请求的缓存处理
              if (isQueryStringData(method) && !cache) {
                  url = appendQuery(url, ("_=" + (Date.now())));
              }
              // 创建 XHR
              var xhr = new XMLHttpRequest();
              xhr.open(method, url, async, username, password);
              if (contentType ||
                  (data && !isQueryStringData(method) && contentType !== false)) {
                  xhr.setRequestHeader('Content-Type', contentType);
              }
              // 设置 Accept
              if (dataType === 'json') {
                  xhr.setRequestHeader('Accept', 'application/json, text/javascript');
              }
              // 添加 headers
              if (headers) {
                  each(headers, function (key, value) {
                      // undefined 值不发送，string 和 null 需要发送
                      if (!isUndefined(value)) {
                          xhr.setRequestHeader(key, value + ''); // 把 null 转换成字符串
                      }
                  });
              }
              // 检查是否是跨域请求，跨域请求时不添加 X-Requested-With
              var crossDomain = /^([\w-]+:)?\/\/([^/]+)/.test(url) &&
                  RegExp.$2 !== window.location.host;
              if (!crossDomain) {
                  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
              }
              if (xhrFields) {
                  each(xhrFields, function (key, value) {
                      // @ts-ignore
                      xhr[key] = value;
                  });
              }
              eventParams.xhr = xhr;
              eventParams.options = mergedOptions;
              var xhrTimeout;
              xhr.onload = function () {
                  if (xhrTimeout) {
                      clearTimeout(xhrTimeout);
                  }
                  // AJAX 返回的 HTTP 响应码是否表示成功
                  var isHttpStatusSuccess = (xhr.status >= 200 && xhr.status < 300) ||
                      xhr.status === 304 ||
                      xhr.status === 0;
                  var responseData;
                  if (isHttpStatusSuccess) {
                      if (xhr.status === 204 || method === 'HEAD') {
                          textStatus = 'nocontent';
                      }
                      else if (xhr.status === 304) {
                          textStatus = 'notmodified';
                      }
                      else {
                          textStatus = 'success';
                      }
                      if (dataType === 'json') {
                          try {
                              responseData =
                                  method === 'HEAD' ? undefined : JSON.parse(xhr.responseText);
                              eventParams.data = responseData;
                          }
                          catch (err) {
                              textStatus = 'parsererror';
                              trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
                              reject(new Error(textStatus));
                          }
                          if (textStatus !== 'parsererror') {
                              trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
                              resolve(responseData);
                          }
                      }
                      else {
                          responseData =
                              method === 'HEAD'
                                  ? undefined
                                  : xhr.responseType === 'text' || xhr.responseType === ''
                                      ? xhr.responseText
                                      : xhr.response;
                          eventParams.data = responseData;
                          trigger(ajaxEvents.ajaxSuccess, eventParams, 'success', responseData, textStatus, xhr);
                          resolve(responseData);
                      }
                  }
                  else {
                      textStatus = 'error';
                      trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, textStatus);
                      reject(new Error(textStatus));
                  }
                  // statusCode
                  each([globalOptions.statusCode, statusCode], function (_, func) {
                      if (func && func[xhr.status]) {
                          if (isHttpStatusSuccess) {
                              func[xhr.status](responseData, textStatus, xhr);
                          }
                          else {
                              func[xhr.status](xhr, textStatus);
                          }
                      }
                  });
                  trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, textStatus);
              };
              xhr.onerror = function () {
                  if (xhrTimeout) {
                      clearTimeout(xhrTimeout);
                  }
                  trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, xhr.statusText);
                  trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, 'error');
                  reject(new Error(xhr.statusText));
              };
              xhr.onabort = function () {
                  var statusText = 'abort';
                  if (xhrTimeout) {
                      statusText = 'timeout';
                      clearTimeout(xhrTimeout);
                  }
                  trigger(ajaxEvents.ajaxError, eventParams, 'error', xhr, statusText);
                  trigger(ajaxEvents.ajaxComplete, eventParams, 'complete', xhr, statusText);
                  reject(new Error(statusText));
              };
              // ajax start 回调
              trigger(ajaxEvents.ajaxStart, eventParams, 'beforeSend', xhr);
              if (isCanceled) {
                  reject(new Error('cancel'));
                  return;
              }
              // Timeout
              if (timeout > 0) {
                  xhrTimeout = setTimeout(function () {
                      xhr.abort();
                  }, timeout);
              }
              // 发送 XHR
              xhr.send(data);
          });
      }
      return XHR();
  }

  $.ajax = ajax;

  /**
   * 为 Ajax 请求设置全局配置参数
   * @param options 键值对参数
   * @example
  ```js
  ajaxSetup({
    dataType: 'json',
    method: 'POST',
  });
  ```
   */
  function ajaxSetup(options) {
      return extend(globalOptions, options);
  }

  $.ajaxSetup = ajaxSetup;

  $.contains = contains;

  var dataNS = '_mduiElementDataStorage';

  /**
   * 在元素上设置键值对数据
   * @param element
   * @param object
   */
  function setObjectToElement(element, object) {
      // @ts-ignore
      if (!element[dataNS]) {
          // @ts-ignore
          element[dataNS] = {};
      }
      each(object, function (key, value) {
          // @ts-ignore
          element[dataNS][toCamelCase(key)] = value;
      });
  }
  function data(element, key, value) {
      var obj;

      // 根据键值对设置值
      // data(element, { 'key' : 'value' })
      if (isObjectLike(key)) {
          setObjectToElement(element, key);
          return key;
      }
      // 根据 key、value 设置值
      // data(element, 'key', 'value')
      if (!isUndefined(value)) {
          setObjectToElement(element, ( obj = {}, obj[key] = value, obj ));
          return value;
      }
      // 获取所有值
      // data(element)
      if (isUndefined(key)) {
          // @ts-ignore
          return element[dataNS] ? element[dataNS] : {};
      }
      // 从 dataNS 中获取指定值
      // data(element, 'key')
      key = toCamelCase(key);
      // @ts-ignore
      if (element[dataNS] && key in element[dataNS]) {
          // @ts-ignore
          return element[dataNS][key];
      }
      return undefined;
  }

  $.data = data;

  $.each = each;

  $.extend = function () {
      var this$1 = this;
      var objectN = [], len = arguments.length;
      while ( len-- ) objectN[ len ] = arguments[ len ];

      if (objectN.length === 1) {
          each(objectN[0], function (prop, value) {
              this$1[prop] = value;
          });
          return this;
      }
      return extend.apply(void 0, [ objectN.shift(), objectN.shift() ].concat( objectN ));
  };

  function map(elements, callback) {
      var ref;

      var value;
      var ret = [];
      each(elements, function (i, element) {
          value = callback.call(window, element, i);
          if (value != null) {
              ret.push(value);
          }
      });
      return (ref = []).concat.apply(ref, ret);
  }

  $.map = map;

  $.merge = merge;

  $.param = param;

  /**
   * 移除指定元素上存放的数据
   * @param element 存放数据的元素
   * @param name
   * 数据键名
   *
   * 若未指定键名，将移除元素上所有数据
   *
   * 多个键名可以用空格分隔，或者用数组表示多个键名
    @example
  ```js
  // 移除元素上键名为 name 的数据
  removeData(document.body, 'name');
  ```
   * @example
  ```js
  // 移除元素上键名为 name1 和 name2 的数据
  removeData(document.body, 'name1 name2');
  ```
   * @example
  ```js
  // 移除元素上键名为 name1 和 name2 的数据
  removeData(document.body, ['name1', 'name2']);
  ```
   * @example
  ```js
  // 移除元素上所有数据
  removeData(document.body);
  ```
   */
  function removeData(element, name) {
      // @ts-ignore
      if (!element[dataNS]) {
          return;
      }
      var remove = function (nameItem) {
          nameItem = toCamelCase(nameItem);
          // @ts-ignore
          if (element[dataNS][nameItem]) {
              // @ts-ignore
              element[dataNS][nameItem] = null;
              // @ts-ignore
              delete element[dataNS][nameItem];
          }
      };
      if (isUndefined(name)) {
          // @ts-ignore
          element[dataNS] = null;
          // @ts-ignore
          delete element[dataNS];
          // @ts-ignore
      }
      else if (isString(name)) {
          name
              .split(' ')
              .filter(function (nameItem) { return nameItem; })
              .forEach(function (nameItem) { return remove(nameItem); });
      }
      else {
          each(name, function (_, nameItem) { return remove(nameItem); });
      }
  }

  $.removeData = removeData;

  /**
   * 过滤掉数组中的重复元素
   * @param arr 数组
   * @example
  ```js
  unique([1, 2, 12, 3, 2, 1, 2, 1, 1]);
  // [1, 2, 12, 3]
  ```
   */
  function unique(arr) {
      var result = [];
      each(arr, function (_, val) {
          if (result.indexOf(val) === -1) {
              result.push(val);
          }
      });
      return result;
  }

  $.unique = unique;

  $.fn.add = function (selector) {
      return new JQ(unique(merge(this.get(), $(selector).get())));
  };

  each(['add', 'remove', 'toggle'], function (_, name) {
      $.fn[(name + "Class")] = function (className) {
          if (name === 'remove' && !arguments.length) {
              return this.each(function (_, element) {
                  element.setAttribute('class', '');
              });
          }
          return this.each(function (i, element) {
              if (!isElement(element)) {
                  return;
              }
              var classes = (isFunction(className)
                  ? className.call(element, i, element.getAttribute('class') || '')
                  : className)
                  .split(' ')
                  .filter(function (name) { return name; });
              each(classes, function (_, cls) {
                  element.classList[name](cls);
              });
          });
      };
  });

  each(['insertBefore', 'insertAfter'], function (nameIndex, name) {
      $.fn[name] = function (target) {
          var $element = nameIndex ? $(this.get().reverse()) : this; // 顺序和 jQuery 保持一致
          var $target = $(target);
          var result = [];
          $target.each(function (index, target) {
              if (!target.parentNode) {
                  return;
              }
              $element.each(function (_, element) {
                  var newItem = index
                      ? element.cloneNode(true)
                      : element;
                  var existingItem = nameIndex ? target.nextSibling : target;
                  result.push(newItem);
                  target.parentNode.insertBefore(newItem, existingItem);
              });
          });
          return $(nameIndex ? result.reverse() : result);
      };
  });

  /**
   * 是否不是 HTML 字符串（包裹在 <> 中）
   * @param target
   */
  function isPlainText(target) {
      return (isString(target) && (target[0] !== '<' || target[target.length - 1] !== '>'));
  }
  each(['before', 'after'], function (nameIndex, name) {
      $.fn[name] = function () {
          var args = [], len = arguments.length;
          while ( len-- ) args[ len ] = arguments[ len ];

          // after 方法，多个参数需要按参数顺序添加到元素后面，所以需要将参数顺序反向处理
          if (nameIndex === 1) {
              args = args.reverse();
          }
          return this.each(function (index, element) {
              var targets = isFunction(args[0])
                  ? [args[0].call(element, index, element.innerHTML)]
                  : args;
              each(targets, function (_, target) {
                  var $target;
                  if (isPlainText(target)) {
                      $target = $(getChildNodesArray(target, 'div'));
                  }
                  else if (index && isElement(target)) {
                      $target = $(target.cloneNode(true));
                  }
                  else {
                      $target = $(target);
                  }
                  $target[nameIndex ? 'insertAfter' : 'insertBefore'](element);
              });
          });
      };
  });

  $.fn.off = function (types, selector, callback) {
      var this$1 = this;

      // types 是对象
      if (isObjectLike(types)) {
          each(types, function (type, fn) {
              // this.off('click', undefined, function () {})
              // this.off('click', '.box', function () {})
              this$1.off(type, selector, fn);
          });
          return this;
      }
      // selector 不存在
      if (selector === false || isFunction(selector)) {
          callback = selector;
          selector = undefined;
          // this.off('click', undefined, function () {})
      }
      // callback 传入 `false`，相当于 `return false`
      if (callback === false) {
          callback = returnFalse;
      }
      return this.each(function () {
          remove(this, types, callback, selector);
      });
  };

  $.fn.on = function (types, selector, data, callback, one) {
      var this$1 = this;

      // types 可以是 type/func 对象
      if (isObjectLike(types)) {
          // (types-Object, selector, data)
          if (!isString(selector)) {
              // (types-Object, data)
              data = data || selector;
              selector = undefined;
          }
          each(types, function (type, fn) {
              // selector 和 data 都可能是 undefined
              // @ts-ignore
              this$1.on(type, selector, data, fn, one);
          });
          return this;
      }
      if (data == null && callback == null) {
          // (types, fn)
          callback = selector;
          data = selector = undefined;
      }
      else if (callback == null) {
          if (isString(selector)) {
              // (types, selector, fn)
              callback = data;
              data = undefined;
          }
          else {
              // (types, data, fn)
              callback = data;
              data = selector;
              selector = undefined;
          }
      }
      if (callback === false) {
          callback = returnFalse;
      }
      else if (!callback) {
          return this;
      }
      // $().one()
      if (one) {
          // eslint-disable-next-line @typescript-eslint/no-this-alias
          var _this = this;
          var origCallback = callback;
          callback = function (event) {
              _this.off(event.type, selector, callback);
              // eslint-disable-next-line prefer-rest-params
              return origCallback.apply(this, arguments);
          };
      }
      return this.each(function () {
          add(this, types, callback, data, selector);
      });
  };

  each(ajaxEvents, function (name, eventName) {
      $.fn[name] = function (fn) {
          return this.on(eventName, function (e, params) {
              fn(e, params.xhr, params.options, params.data);
          });
      };
  });

  $.fn.map = function (callback) {
      return new JQ(map(this, function (element, i) { return callback.call(element, i, element); }));
  };

  $.fn.clone = function () {
      return this.map(function () {
          return this.cloneNode(true);
      });
  };

  $.fn.is = function (selector) {
      var isMatched = false;
      if (isFunction(selector)) {
          this.each(function (index, element) {
              if (selector.call(element, index, element)) {
                  isMatched = true;
              }
          });
          return isMatched;
      }
      if (isString(selector)) {
          this.each(function (_, element) {
              if (isDocument(element) || isWindow(element)) {
                  return;
              }
              // @ts-ignore
              var matches = element.matches || element.msMatchesSelector;
              if (matches.call(element, selector)) {
                  isMatched = true;
              }
          });
          return isMatched;
      }
      var $compareWith = $(selector);
      this.each(function (_, element) {
          $compareWith.each(function (_, compare) {
              if (element === compare) {
                  isMatched = true;
              }
          });
      });
      return isMatched;
  };

  $.fn.remove = function (selector) {
      return this.each(function (_, element) {
          if (element.parentNode && (!selector || $(element).is(selector))) {
              element.parentNode.removeChild(element);
          }
      });
  };

  each(['prepend', 'append'], function (nameIndex, name) {
      $.fn[name] = function () {
          var args = [], len = arguments.length;
          while ( len-- ) args[ len ] = arguments[ len ];

          return this.each(function (index, element) {
              var ref;

              var childNodes = element.childNodes;
              var childLength = childNodes.length;
              var child = childLength
                  ? childNodes[nameIndex ? childLength - 1 : 0]
                  : document.createElement('div');
              if (!childLength) {
                  element.appendChild(child);
              }
              var contents = isFunction(args[0])
                  ? [args[0].call(element, index, element.innerHTML)]
                  : args;
              // 如果不是字符串，则仅第一个元素使用原始元素，其他的都克隆自第一个元素
              if (index) {
                  contents = contents.map(function (content) {
                      return isString(content) ? content : $(content).clone();
                  });
              }
              (ref = $(child))[nameIndex ? 'after' : 'before'].apply(ref, contents);
              if (!childLength) {
                  element.removeChild(child);
              }
          });
      };
  });

  each(['appendTo', 'prependTo'], function (nameIndex, name) {
      $.fn[name] = function (target) {
          var extraChilds = [];
          var $target = $(target).map(function (_, element) {
              var childNodes = element.childNodes;
              var childLength = childNodes.length;
              if (childLength) {
                  return childNodes[nameIndex ? 0 : childLength - 1];
              }
              var child = document.createElement('div');
              element.appendChild(child);
              extraChilds.push(child);
              return child;
          });
          var $result = this[nameIndex ? 'insertBefore' : 'insertAfter']($target);
          $(extraChilds).remove();
          return $result;
      };
  });

  each(['attr', 'prop', 'css'], function (nameIndex, name) {
      function set(element, key, value) {
          // 值为 undefined 时，不修改
          if (isUndefined(value)) {
              return;
          }
          switch (nameIndex) {
              // attr
              case 0:
                  if (isNull(value)) {
                      element.removeAttribute(key);
                  }
                  else {
                      element.setAttribute(key, value);
                  }
                  break;
              // prop
              case 1:
                  // @ts-ignore
                  element[key] = value;
                  break;
              // css
              default:
                  key = toCamelCase(key);
                  // @ts-ignore
                  element.style[key] = isNumber(value)
                      ? ("" + value + (cssNumber.indexOf(key) > -1 ? '' : 'px'))
                      : value;
                  break;
          }
      }
      function get(element, key) {
          switch (nameIndex) {
              // attr
              case 0:
                  // 属性不存在时，原生 getAttribute 方法返回 null，而 jquery 返回 undefined。这里和 jquery 保持一致
                  var value = element.getAttribute(key);
                  return isNull(value) ? undefined : value;
              // prop
              case 1:
                  // @ts-ignore
                  return element[key];
              // css
              default:
                  return getStyle(element, key);
          }
      }
      $.fn[name] = function (key, value) {
          var this$1 = this;

          if (isObjectLike(key)) {
              each(key, function (k, v) {
                  // @ts-ignore
                  this$1[name](k, v);
              });
              return this;
          }
          if (arguments.length === 1) {
              var element = this[0];
              return isElement(element) ? get(element, key) : undefined;
          }
          return this.each(function (i, element) {
              set(element, key, isFunction(value) ? value.call(element, i, get(element, key)) : value);
          });
      };
  });

  $.fn.children = function (selector) {
      var children = [];
      this.each(function (_, element) {
          each(element.childNodes, function (__, childNode) {
              if (!isElement(childNode)) {
                  return;
              }
              if (!selector || $(childNode).is(selector)) {
                  children.push(childNode);
              }
          });
      });
      return new JQ(unique(children));
  };

  $.fn.slice = function () {
      var args = [], len = arguments.length;
      while ( len-- ) args[ len ] = arguments[ len ];

      return new JQ([].slice.apply(this, args));
  };

  $.fn.eq = function (index) {
      var ret = index === -1 ? this.slice(index) : this.slice(index, +index + 1);
      return new JQ(ret);
  };

  function dir($elements, nameIndex, node, selector, filter) {
      var ret = [];
      var target;
      $elements.each(function (_, element) {
          target = element[node];
          // 不能包含最顶层的 document 元素
          while (target && isElement(target)) {
              // prevUntil, nextUntil, parentsUntil
              if (nameIndex === 2) {
                  if (selector && $(target).is(selector)) {
                      break;
                  }
                  if (!filter || $(target).is(filter)) {
                      ret.push(target);
                  }
              }
              // prev, next, parent
              else if (nameIndex === 0) {
                  if (!selector || $(target).is(selector)) {
                      ret.push(target);
                  }
                  break;
              }
              // prevAll, nextAll, parents
              else {
                  if (!selector || $(target).is(selector)) {
                      ret.push(target);
                  }
              }
              // @ts-ignore
              target = target[node];
          }
      });
      return new JQ(unique(ret));
  }

  each(['', 's', 'sUntil'], function (nameIndex, name) {
      $.fn[("parent" + name)] = function (selector, filter) {
          // parents、parentsUntil 需要把元素的顺序反向处理，以便和 jQuery 的结果一致
          var $nodes = !nameIndex ? this : $(this.get().reverse());
          return dir($nodes, nameIndex, 'parentNode', selector, filter);
      };
  });

  $.fn.closest = function (selector) {
      if (this.is(selector)) {
          return this;
      }
      var matched = [];
      this.parents().each(function (_, element) {
          if ($(element).is(selector)) {
              matched.push(element);
              return false;
          }
      });
      return new JQ(matched);
  };

  var rbrace = /^(?:{[\w\W]*\}|\[[\w\W]*\])$/;
  // 从 `data-*` 中获取的值，需要经过该函数转换
  function getData(value) {
      if (value === 'true') {
          return true;
      }
      if (value === 'false') {
          return false;
      }
      if (value === 'null') {
          return null;
      }
      if (value === +value + '') {
          return +value;
      }
      if (rbrace.test(value)) {
          return JSON.parse(value);
      }
      return value;
  }
  // 若 value 不存在，则从 `data-*` 中获取值
  function dataAttr(element, key, value) {
      if (isUndefined(value) && element.nodeType === 1) {
          var name = 'data-' + toKebabCase(key);
          value = element.getAttribute(name);
          if (isString(value)) {
              try {
                  value = getData(value);
              }
              catch (e) { }
          }
          else {
              value = undefined;
          }
      }
      return value;
  }
  $.fn.data = function (key, value) {
      // 获取所有值
      if (isUndefined(key)) {
          if (!this.length) {
              return undefined;
          }
          var element = this[0];
          var resultData = data(element);
          // window, document 上不存在 `data-*` 属性
          if (element.nodeType !== 1) {
              return resultData;
          }
          // 从 `data-*` 中获取值
          var attrs = element.attributes;
          var i = attrs.length;
          while (i--) {
              if (attrs[i]) {
                  var name = attrs[i].name;
                  if (name.indexOf('data-') === 0) {
                      name = toCamelCase(name.slice(5));
                      resultData[name] = dataAttr(element, name, resultData[name]);
                  }
              }
          }
          return resultData;
      }
      // 同时设置多个值
      if (isObjectLike(key)) {
          return this.each(function () {
              data(this, key);
          });
      }
      // value 传入了 undefined
      if (arguments.length === 2 && isUndefined(value)) {
          return this;
      }
      // 设置值
      if (!isUndefined(value)) {
          return this.each(function () {
              data(this, key, value);
          });
      }
      // 获取值
      if (!this.length) {
          return undefined;
      }
      return dataAttr(this[0], key, data(this[0], key));
  };

  $.fn.empty = function () {
      return this.each(function () {
          this.innerHTML = '';
      });
  };

  $.fn.extend = function (obj) {
      each(obj, function (prop, value) {
          // 在 JQ 对象上扩展方法时，需要自己添加 typescript 的类型定义
          $.fn[prop] = value;
      });
      return this;
  };

  $.fn.filter = function (selector) {
      if (isFunction(selector)) {
          return this.map(function (index, element) { return selector.call(element, index, element) ? element : undefined; });
      }
      if (isString(selector)) {
          return this.map(function (_, element) { return $(element).is(selector) ? element : undefined; });
      }
      var $selector = $(selector);
      return this.map(function (_, element) { return $selector.get().indexOf(element) > -1 ? element : undefined; });
  };

  $.fn.first = function () {
      return this.eq(0);
  };

  $.fn.has = function (selector) {
      var $targets = isString(selector) ? this.find(selector) : $(selector);
      var length = $targets.length;
      return this.map(function () {
          for (var i = 0; i < length; i += 1) {
              if (contains(this, $targets[i])) {
                  return this;
              }
          }
          return;
      });
  };

  $.fn.hasClass = function (className) {
      return this[0].classList.contains(className);
  };

  /**
   * 值上面的 padding、border、margin 处理
   * @param element
   * @param name
   * @param value
   * @param funcIndex
   * @param includeMargin
   * @param multiply
   */
  function handleExtraWidth(element, name, value, funcIndex, includeMargin, multiply) {
      // 获取元素的 padding, border, margin 宽度（两侧宽度的和）
      var getExtraWidthValue = function (extra) {
          return (getExtraWidth(element, name.toLowerCase(), extra) *
              multiply);
      };
      if (funcIndex === 2 && includeMargin) {
          value += getExtraWidthValue('margin');
      }
      if (isBorderBox(element)) {
          // IE 为 box-sizing: border-box 时，得到的值不含 border 和 padding，这里先修复
          // 仅获取时需要处理，multiply === 1 为 get
          if (isIE() && multiply === 1) {
              value += getExtraWidthValue('border');
              value += getExtraWidthValue('padding');
          }
          if (funcIndex === 0) {
              value -= getExtraWidthValue('border');
          }
          if (funcIndex === 1) {
              value -= getExtraWidthValue('border');
              value -= getExtraWidthValue('padding');
          }
      }
      else {
          if (funcIndex === 0) {
              value += getExtraWidthValue('padding');
          }
          if (funcIndex === 2) {
              value += getExtraWidthValue('border');
              value += getExtraWidthValue('padding');
          }
      }
      return value;
  }
  /**
   * 获取元素的样式值
   * @param element
   * @param name
   * @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight
   * @param includeMargin
   */
  function get(element, name, funcIndex, includeMargin) {
      var clientProp = "client" + name;
      var scrollProp = "scroll" + name;
      var offsetProp = "offset" + name;
      var innerProp = "inner" + name;
      // $(window).width()
      if (isWindow(element)) {
          // outerWidth, outerHeight 需要包含滚动条的宽度
          return funcIndex === 2
              ? element[innerProp]
              : toElement(document)[clientProp];
      }
      // $(document).width()
      if (isDocument(element)) {
          var doc = toElement(element);
          return Math.max(
          // @ts-ignore
          element.body[scrollProp], doc[scrollProp], 
          // @ts-ignore
          element.body[offsetProp], doc[offsetProp], doc[clientProp]);
      }
      var value = parseFloat(getComputedStyleValue(element, name.toLowerCase()) || '0');
      return handleExtraWidth(element, name, value, funcIndex, includeMargin, 1);
  }
  /**
   * 设置元素的样式值
   * @param element
   * @param elementIndex
   * @param name
   * @param funcIndex 0: innerWidth, innerHeight; 1: width, height; 2: outerWidth, outerHeight
   * @param includeMargin
   * @param value
   */
  function set(element, elementIndex, name, funcIndex, includeMargin, value) {
      var computedValue = isFunction(value)
          ? value.call(element, elementIndex, get(element, name, funcIndex, includeMargin))
          : value;
      if (computedValue == null) {
          return;
      }
      var $element = $(element);
      var dimension = name.toLowerCase();
      // 特殊的值，不需要计算 padding、border、margin
      if (['auto', 'inherit', ''].indexOf(computedValue) > -1) {
          $element.css(dimension, computedValue);
          return;
      }
      // 其他值保留原始单位。注意：如果不使用 px 作为单位，则算出的值一般是不准确的
      var suffix = computedValue.toString().replace(/\b[0-9.]*/, '');
      var numerical = parseFloat(computedValue);
      computedValue =
          handleExtraWidth(element, name, numerical, funcIndex, includeMargin, -1) +
              (suffix || 'px');
      $element.css(dimension, computedValue);
  }
  each(['Width', 'Height'], function (_, name) {
      each([("inner" + name), name.toLowerCase(), ("outer" + name)], function (funcIndex, funcName) {
          $.fn[funcName] = function (margin, value) {
              // 是否是赋值操作
              var isSet = arguments.length && (funcIndex < 2 || !isBoolean(margin));
              var includeMargin = margin === true || value === true;
              // 获取第一个元素的值
              if (!isSet) {
                  return this.length
                      ? get(this[0], name, funcIndex, includeMargin)
                      : undefined;
              }
              // 设置每个元素的值
              return this.each(function (index, element) { return set(element, index, name, funcIndex, includeMargin, margin); });
          };
      });
  });

  $.fn.hide = function () {
      return this.each(function () {
          this.style.display = 'none';
      });
  };

  each(['val', 'html', 'text'], function (nameIndex, name) {
      var props = {
          0: 'value',
          1: 'innerHTML',
          2: 'textContent',
      };
      var propName = props[nameIndex];
      function get($elements) {
          // text() 获取所有元素的文本
          if (nameIndex === 2) {
              // @ts-ignore
              return map($elements, function (element) { return toElement(element)[propName]; }).join('');
          }
          // 空集合时，val() 和 html() 返回 undefined
          if (!$elements.length) {
              return undefined;
          }
          // val() 和 html() 仅获取第一个元素的内容
          var firstElement = $elements[0];
          // select multiple 返回数组
          if (nameIndex === 0 && $(firstElement).is('select[multiple]')) {
              return map($(firstElement).find('option:checked'), function (element) { return element.value; });
          }
          // @ts-ignore
          return firstElement[propName];
      }
      function set(element, value) {
          // text() 和 html() 赋值为 undefined，则保持原内容不变
          // val() 赋值为 undefined 则赋值为空
          if (isUndefined(value)) {
              if (nameIndex !== 0) {
                  return;
              }
              value = '';
          }
          if (nameIndex === 1 && isElement(value)) {
              value = value.outerHTML;
          }
          // @ts-ignore
          element[propName] = value;
      }
      $.fn[name] = function (value) {
          // 获取值
          if (!arguments.length) {
              return get(this);
          }
          // 设置值
          return this.each(function (i, element) {
              var computedValue = isFunction(value)
                  ? value.call(element, i, get($(element)))
                  : value;
              // value 是数组，则选中数组中的元素，反选不在数组中的元素
              if (nameIndex === 0 && Array.isArray(computedValue)) {
                  // select[multiple]
                  if ($(element).is('select[multiple]')) {
                      map($(element).find('option'), function (option) { return (option.selected =
                          computedValue.indexOf(option.value) >
                              -1); });
                  }
                  // 其他 checkbox, radio 等元素
                  else {
                      element.checked =
                          computedValue.indexOf(element.value) > -1;
                  }
              }
              else {
                  set(element, computedValue);
              }
          });
      };
  });

  $.fn.index = function (selector) {
      if (!arguments.length) {
          return this.eq(0).parent().children().get().indexOf(this[0]);
      }
      if (isString(selector)) {
          return $(selector).get().indexOf(this[0]);
      }
      return this.get().indexOf($(selector)[0]);
  };

  $.fn.last = function () {
      return this.eq(-1);
  };

  each(['', 'All', 'Until'], function (nameIndex, name) {
      $.fn[("next" + name)] = function (selector, filter) {
          return dir(this, nameIndex, 'nextElementSibling', selector, filter);
      };
  });

  $.fn.not = function (selector) {
      var $excludes = this.filter(selector);
      return this.map(function (_, element) { return $excludes.index(element) > -1 ? undefined : element; });
  };

  /**
   * 返回最近的用于定位的父元素
   */
  $.fn.offsetParent = function () {
      return this.map(function () {
          var offsetParent = this.offsetParent;
          while (offsetParent && $(offsetParent).css('position') === 'static') {
              offsetParent = offsetParent.offsetParent;
          }
          return offsetParent || document.documentElement;
      });
  };

  function floatStyle($element, name) {
      return parseFloat($element.css(name));
  }
  $.fn.position = function () {
      if (!this.length) {
          return undefined;
      }
      var $element = this.eq(0);
      var currentOffset;
      var parentOffset = {
          left: 0,
          top: 0,
      };
      if ($element.css('position') === 'fixed') {
          currentOffset = $element[0].getBoundingClientRect();
      }
      else {
          currentOffset = $element.offset();
          var $offsetParent = $element.offsetParent();
          parentOffset = $offsetParent.offset();
          parentOffset.top += floatStyle($offsetParent, 'border-top-width');
          parentOffset.left += floatStyle($offsetParent, 'border-left-width');
      }
      return {
          top: currentOffset.top - parentOffset.top - floatStyle($element, 'margin-top'),
          left: currentOffset.left -
              parentOffset.left -
              floatStyle($element, 'margin-left'),
      };
  };

  function get$1(element) {
      if (!element.getClientRects().length) {
          return { top: 0, left: 0 };
      }
      var rect = element.getBoundingClientRect();
      var win = element.ownerDocument.defaultView;
      return {
          top: rect.top + win.pageYOffset,
          left: rect.left + win.pageXOffset,
      };
  }
  function set$1(element, value, index) {
      var $element = $(element);
      var position = $element.css('position');
      if (position === 'static') {
          $element.css('position', 'relative');
      }
      var currentOffset = get$1(element);
      var currentTopString = $element.css('top');
      var currentLeftString = $element.css('left');
      var currentTop;
      var currentLeft;
      var calculatePosition = (position === 'absolute' || position === 'fixed') &&
          (currentTopString + currentLeftString).indexOf('auto') > -1;
      if (calculatePosition) {
          var currentPosition = $element.position();
          currentTop = currentPosition.top;
          currentLeft = currentPosition.left;
      }
      else {
          currentTop = parseFloat(currentTopString);
          currentLeft = parseFloat(currentLeftString);
      }
      var computedValue = isFunction(value)
          ? value.call(element, index, extend({}, currentOffset))
          : value;
      $element.css({
          top: computedValue.top != null
              ? computedValue.top - currentOffset.top + currentTop
              : undefined,
          left: computedValue.left != null
              ? computedValue.left - currentOffset.left + currentLeft
              : undefined,
      });
  }
  $.fn.offset = function (value) {
      // 获取坐标
      if (!arguments.length) {
          if (!this.length) {
              return undefined;
          }
          return get$1(this[0]);
      }
      // 设置坐标
      return this.each(function (index) {
          set$1(this, value, index);
      });
  };

  $.fn.one = function (types, selector, data, callback) {
      // @ts-ignore
      return this.on(types, selector, data, callback, true);
  };

  each(['', 'All', 'Until'], function (nameIndex, name) {
      $.fn[("prev" + name)] = function (selector, filter) {
          // prevAll、prevUntil 需要把元素的顺序倒序处理，以便和 jQuery 的结果一致
          var $nodes = !nameIndex ? this : $(this.get().reverse());
          return dir($nodes, nameIndex, 'previousElementSibling', selector, filter);
      };
  });

  $.fn.removeAttr = function (attributeName) {
      var names = attributeName.split(' ').filter(function (name) { return name; });
      return this.each(function () {
          var this$1 = this;

          each(names, function (_, name) {
              this$1.removeAttribute(name);
          });
      });
  };

  $.fn.removeData = function (name) {
      return this.each(function () {
          removeData(this, name);
      });
  };

  $.fn.removeProp = function (name) {
      return this.each(function () {
          try {
              // @ts-ignore
              delete this[name];
          }
          catch (e) { }
      });
  };

  $.fn.replaceWith = function (newContent) {
      this.each(function (index, element) {
          var content = newContent;
          if (isFunction(content)) {
              content = content.call(element, index, element.innerHTML);
          }
          else if (index && !isString(content)) {
              content = $(content).clone();
          }
          $(element).before(content);
      });
      return this.remove();
  };

  $.fn.replaceAll = function (target) {
      var this$1 = this;

      return $(target).map(function (index, element) {
          $(element).replaceWith(index ? this$1.clone() : this$1);
          return this$1.get();
      });
  };

  /**
   * 将表单元素的值组合成键值对数组
   * @returns {Array}
   */
  $.fn.serializeArray = function () {
      var result = [];
      this.each(function (_, element) {
          var elements = element instanceof HTMLFormElement ? element.elements : [element];
          $(elements).each(function (_, element) {
              var $element = $(element);
              var type = element.type;
              var nodeName = element.nodeName.toLowerCase();
              if (nodeName !== 'fieldset' &&
                  element.name &&
                  !element.disabled &&
                  ['input', 'select', 'textarea', 'keygen'].indexOf(nodeName) > -1 &&
                  ['submit', 'button', 'image', 'reset', 'file'].indexOf(type) === -1 &&
                  (['radio', 'checkbox'].indexOf(type) === -1 ||
                      element.checked)) {
                  var value = $element.val();
                  var valueArr = Array.isArray(value) ? value : [value];
                  valueArr.forEach(function (value) {
                      result.push({
                          name: element.name,
                          value: value,
                      });
                  });
              }
          });
      });
      return result;
  };

  $.fn.serialize = function () {
      return param(this.serializeArray());
  };

  var elementDisplay = {};
  /**
   * 获取元素的初始 display 值，用于 .show() 方法
   * @param nodeName
   */
  function defaultDisplay(nodeName) {
      var element;
      var display;
      if (!elementDisplay[nodeName]) {
          element = document.createElement(nodeName);
          document.body.appendChild(element);
          display = getStyle(element, 'display');
          element.parentNode.removeChild(element);
          if (display === 'none') {
              display = 'block';
          }
          elementDisplay[nodeName] = display;
      }
      return elementDisplay[nodeName];
  }
  /**
   * 显示指定元素
   * @returns {JQ}
   */
  $.fn.show = function () {
      return this.each(function () {
          if (this.style.display === 'none') {
              this.style.display = '';
          }
          if (getStyle(this, 'display') === 'none') {
              this.style.display = defaultDisplay(this.nodeName);
          }
      });
  };

  /**
   * 取得同辈元素的集合
   * @param selector {String=}
   * @returns {JQ}
   */
  $.fn.siblings = function (selector) {
      return this.prevAll(selector).add(this.nextAll(selector));
  };

  /**
   * 切换元素的显示状态
   */
  $.fn.toggle = function () {
      return this.each(function () {
          getStyle(this, 'display') === 'none' ? $(this).show() : $(this).hide();
      });
  };

  $.fn.reflow = function () {
      return this.each(function () {
          return this.clientLeft;
      });
  };

  $.fn.transition = function (duration) {
      if (isNumber(duration)) {
          duration = duration + "ms";
      }
      return this.each(function () {
          this.style.webkitTransitionDuration = duration;
          this.style.transitionDuration = duration;
      });
  };

  $.fn.transitionEnd = function (callback) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      var events = ['webkitTransitionEnd', 'transitionend'];
      function fireCallback(e) {
          if (e.target !== this) {
              return;
          }
          // @ts-ignore
          callback.call(this, e);
          each(events, function (_, event) {
              that.off(event, fireCallback);
          });
      }
      each(events, function (_, event) {
          that.on(event, fireCallback);
      });
      return this;
  };

  $.fn.transformOrigin = function (transformOrigin) {
      return this.each(function () {
          this.style.webkitTransformOrigin = transformOrigin;
          this.style.transformOrigin = transformOrigin;
      });
  };

  $.fn.transform = function (transform) {
      return this.each(function () {
          this.style.webkitTransform = transform;
          this.style.transform = transform;
      });
  };

  /**
   * CSS 选择器和初始化函数组成的对象
   */
  var entries = {};
  /**
   * 注册并执行初始化函数
   * @param selector CSS 选择器
   * @param apiInit 初始化函数
   * @param i 元素索引
   * @param element 元素
   */
  function mutation(selector, apiInit, i, element) {
      var selectors = data(element, '_mdui_mutation');
      if (!selectors) {
          selectors = [];
          data(element, '_mdui_mutation', selectors);
      }
      if (selectors.indexOf(selector) === -1) {
          selectors.push(selector);
          apiInit.call(element, i, element);
      }
  }

  $.fn.mutation = function () {
      return this.each(function (i, element) {
          var $this = $(element);
          each(entries, function (selector, apiInit) {
              if ($this.is(selector)) {
                  mutation(selector, apiInit, i, element);
              }
              $this.find(selector).each(function (i, element) {
                  mutation(selector, apiInit, i, element);
              });
          });
      });
  };

  $.showOverlay = function (zIndex) {
      var $overlay = $('.mdui-overlay');
      if ($overlay.length) {
          $overlay.data('_overlay_is_deleted', false);
          if (!isUndefined(zIndex)) {
              $overlay.css('z-index', zIndex);
          }
      }
      else {
          if (isUndefined(zIndex)) {
              zIndex = 2000;
          }
          $overlay = $('<div class="mdui-overlay">')
              .appendTo(document.body)
              .reflow()
              .css('z-index', zIndex);
      }
      var level = $overlay.data('_overlay_level') || 0;
      return $overlay.data('_overlay_level', ++level).addClass('mdui-overlay-show');
  };

  $.hideOverlay = function (force) {
      if ( force === void 0 ) force = false;

      var $overlay = $('.mdui-overlay');
      if (!$overlay.length) {
          return;
      }
      var level = force ? 1 : $overlay.data('_overlay_level');
      if (level > 1) {
          $overlay.data('_overlay_level', --level);
          return;
      }
      $overlay
          .data('_overlay_level', 0)
          .removeClass('mdui-overlay-show')
          .data('_overlay_is_deleted', true)
          .transitionEnd(function () {
          if ($overlay.data('_overlay_is_deleted')) {
              $overlay.remove();
          }
      });
  };

  $.lockScreen = function () {
      var $body = $('body');
      // 不直接把 body 设为 box-sizing: border-box，避免污染全局样式
      var newBodyWidth = $body.width();
      var level = $body.data('_lockscreen_level') || 0;
      $body
          .addClass('mdui-locked')
          .width(newBodyWidth)
          .data('_lockscreen_level', ++level);
  };

  $.unlockScreen = function (force) {
      if ( force === void 0 ) force = false;

      var $body = $('body');
      var level = force ? 1 : $body.data('_lockscreen_level');
      if (level > 1) {
          $body.data('_lockscreen_level', --level);
          return;
      }
      $body.data('_lockscreen_level', 0).removeClass('mdui-locked').width('');
  };

  $.throttle = function (fn, delay) {
      if ( delay === void 0 ) delay = 16;

      var timer = null;
      return function () {
          var this$1 = this;
          var args = [], len = arguments.length;
          while ( len-- ) args[ len ] = arguments[ len ];

          if (isNull(timer)) {
              timer = setTimeout(function () {
                  fn.apply(this$1, args);
                  timer = null;
              }, delay);
          }
      };
  };

  var GUID = {};
  $.guid = function (name) {
      if (!isUndefined(name) && !isUndefined(GUID[name])) {
          return GUID[name];
      }
      function s4() {
          return Math.floor((1 + Math.random()) * 0x10000)
              .toString(16)
              .substring(1);
      }
      var guid = '_' +
          s4() +
          s4() +
          '-' +
          s4() +
          '-' +
          s4() +
          '-' +
          s4() +
          '-' +
          s4() +
          s4() +
          s4();
      if (!isUndefined(name)) {
          GUID[name] = guid;
      }
      return guid;
  };

  mdui.mutation = function (selector, apiInit) {
      if (isUndefined(selector) || isUndefined(apiInit)) {
          $(document).mutation();
          return;
      }
      entries[selector] = apiInit;
      $(selector).each(function (i, element) { return mutation(selector, apiInit, i, element); });
  };

  /**
   * 触发组件上的事件
   * @param eventName 事件名
   * @param componentName 组件名
   * @param target 在该元素上触发事件
   * @param instance 组件实例
   * @param parameters 事件参数
   */
  function componentEvent(eventName, componentName, target, instance, parameters) {
      if (!parameters) {
          parameters = {};
      }
      // @ts-ignore
      parameters.inst = instance;
      var fullEventName = eventName + ".mdui." + componentName;
      // jQuery 事件
      // @ts-ignore
      if (typeof jQuery !== 'undefined') {
          // @ts-ignore
          jQuery(target).trigger(fullEventName, parameters);
      }
      var $target = $(target);
      // mdui.jq 事件
      $target.trigger(fullEventName, parameters);
      var eventParams = {
          bubbles: true,
          cancelable: true,
          detail: parameters,
      };
      var eventObject = new CustomEvent(fullEventName, eventParams);
      // @ts-ignore
      eventObject._detail = parameters;
      $target[0].dispatchEvent(eventObject);
  }

  var $document = $(document);
  var $window = $(window);
  var $body = $('body');

  var DEFAULT_OPTIONS = {
      tolerance: 5,
      offset: 0,
      initialClass: 'mdui-headroom',
      pinnedClass: 'mdui-headroom-pinned-top',
      unpinnedClass: 'mdui-headroom-unpinned-top',
  };
  var Headroom = function Headroom(selector, options) {
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS);
      /**
       * 当前 headroom 的状态
       */
      this.state = 'pinned';
      /**
       * 当前是否启用
       */
      this.isEnable = false;
      /**
       * 上次滚动后，垂直方向的距离
       */
      this.lastScrollY = 0;
      /**
       * AnimationFrame ID
       */
      this.rafId = 0;
      this.$element = $(selector).first();
      extend(this.options, options);
      // tolerance 参数若为数值，转换为对象
      var tolerance = this.options.tolerance;
      if (isNumber(tolerance)) {
          this.options.tolerance = {
              down: tolerance,
              up: tolerance,
          };
      }
      this.enable();
  };
  /**
   * 滚动时的处理
   */
  Headroom.prototype.onScroll = function onScroll () {
          var this$1 = this;

      this.rafId = window.requestAnimationFrame(function () {
          var currentScrollY = window.pageYOffset;
          var direction = currentScrollY > this$1.lastScrollY ? 'down' : 'up';
          var tolerance = this$1.options.tolerance[direction];
          var scrolled = Math.abs(currentScrollY - this$1.lastScrollY);
          var toleranceExceeded = scrolled >= tolerance;
          if (currentScrollY > this$1.lastScrollY &&
              currentScrollY >= this$1.options.offset &&
              toleranceExceeded) {
              this$1.unpin();
          }
          else if ((currentScrollY < this$1.lastScrollY && toleranceExceeded) ||
              currentScrollY <= this$1.options.offset) {
              this$1.pin();
          }
          this$1.lastScrollY = currentScrollY;
      });
  };
  /**
   * 触发组件事件
   * @param name
   */
  Headroom.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'headroom', this.$element, this);
  };
  /**
   * 动画结束的回调
   */
  Headroom.prototype.transitionEnd = function transitionEnd () {
      if (this.state === 'pinning') {
          this.state = 'pinned';
          this.triggerEvent('pinned');
      }
      if (this.state === 'unpinning') {
          this.state = 'unpinned';
          this.triggerEvent('unpinned');
      }
  };
  /**
   * 使元素固定住
   */
  Headroom.prototype.pin = function pin () {
          var this$1 = this;

      if (this.state === 'pinning' ||
          this.state === 'pinned' ||
          !this.$element.hasClass(this.options.initialClass)) {
          return;
      }
      this.triggerEvent('pin');
      this.state = 'pinning';
      this.$element
          .removeClass(this.options.unpinnedClass)
          .addClass(this.options.pinnedClass)
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 使元素隐藏
   */
  Headroom.prototype.unpin = function unpin () {
          var this$1 = this;

      if (this.state === 'unpinning' ||
          this.state === 'unpinned' ||
          !this.$element.hasClass(this.options.initialClass)) {
          return;
      }
      this.triggerEvent('unpin');
      this.state = 'unpinning';
      this.$element
          .removeClass(this.options.pinnedClass)
          .addClass(this.options.unpinnedClass)
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 启用 headroom 插件
   */
  Headroom.prototype.enable = function enable () {
          var this$1 = this;

      if (this.isEnable) {
          return;
      }
      this.isEnable = true;
      this.state = 'pinned';
      this.$element
          .addClass(this.options.initialClass)
          .removeClass(this.options.pinnedClass)
          .removeClass(this.options.unpinnedClass);
      this.lastScrollY = window.pageYOffset;
      $window.on('scroll', function () { return this$1.onScroll(); });
  };
  /**
   * 禁用 headroom 插件
   */
  Headroom.prototype.disable = function disable () {
          var this$1 = this;

      if (!this.isEnable) {
          return;
      }
      this.isEnable = false;
      this.$element
          .removeClass(this.options.initialClass)
          .removeClass(this.options.pinnedClass)
          .removeClass(this.options.unpinnedClass);
      $window.off('scroll', function () { return this$1.onScroll(); });
      window.cancelAnimationFrame(this.rafId);
  };
  /**
   * 获取当前状态。共包含四种状态：`pinning`、`pinned`、`unpinning`、`unpinned`
   */
  Headroom.prototype.getState = function getState () {
      return this.state;
  };
  mdui.Headroom = Headroom;

  /**
   * 解析 DATA API 参数
   * @param element 元素
   * @param name 属性名
   */
  function parseOptions(element, name) {
      var attr = $(element).attr(name);
      if (!attr) {
          return {};
      }
      return new Function('', ("var json = " + attr + "; return JSON.parse(JSON.stringify(json));"))();
  }

  var customAttr = 'mdui-headroom';
  $(function () {
      mdui.mutation(("[" + customAttr + "]"), function () {
          new mdui.Headroom(this, parseOptions(this, customAttr));
      });
  });

  var DEFAULT_OPTIONS$1 = {
      accordion: false,
  };
  var CollapseAbstract = function CollapseAbstract(selector, options) {
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$1);
      // CSS 类名
      var classPrefix = "mdui-" + (this.getNamespace()) + "-item";
      this.classItem = classPrefix;
      this.classItemOpen = classPrefix + "-open";
      this.classHeader = classPrefix + "-header";
      this.classBody = classPrefix + "-body";
      this.$element = $(selector).first();
      extend(this.options, options);
      this.bindEvent();
  };
  /**
   * 绑定事件
   */
  CollapseAbstract.prototype.bindEvent = function bindEvent () {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      // 点击 header 时，打开/关闭 item
      this.$element.on('click', ("." + (this.classHeader)), function () {
          var $header = $(this);
          var $item = $header.parent();
          var $items = that.getItems();
          $items.each(function (_, item) {
              if ($item.is(item)) {
                  that.toggle(item);
              }
          });
      });
      // 点击关闭按钮时，关闭 item
      this.$element.on('click', ("[mdui-" + (this.getNamespace()) + "-item-close]"), function () {
          var $target = $(this);
          var $item = $target.parents(("." + (that.classItem))).first();
          that.close($item);
      });
  };
  /**
   * 指定 item 是否处于打开状态
   * @param $item
   */
  CollapseAbstract.prototype.isOpen = function isOpen ($item) {
      return $item.hasClass(this.classItemOpen);
  };
  /**
   * 获取所有 item
   */
  CollapseAbstract.prototype.getItems = function getItems () {
      return this.$element.children(("." + (this.classItem)));
  };
  /**
   * 获取指定 item
   * @param item
   */
  CollapseAbstract.prototype.getItem = function getItem (item) {
      if (isNumber(item)) {
          return this.getItems().eq(item);
      }
      return $(item).first();
  };
  /**
   * 触发组件事件
   * @param name 事件名
   * @param $item 事件触发的目标 item
   */
  CollapseAbstract.prototype.triggerEvent = function triggerEvent (name, $item) {
      componentEvent(name, this.getNamespace(), $item, this);
  };
  /**
   * 动画结束回调
   * @param $content body 元素
   * @param $item item 元素
   */
  CollapseAbstract.prototype.transitionEnd = function transitionEnd ($content, $item) {
      if (this.isOpen($item)) {
          $content.transition(0).height('auto').reflow().transition('');
          this.triggerEvent('opened', $item);
      }
      else {
          $content.height('');
          this.triggerEvent('closed', $item);
      }
  };
  /**
   * 打开指定面板项
   * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
   */
  CollapseAbstract.prototype.open = function open (item) {
          var this$1 = this;

      var $item = this.getItem(item);
      if (this.isOpen($item)) {
          return;
      }
      // 关闭其他项
      if (this.options.accordion) {
          this.$element.children(("." + (this.classItemOpen))).each(function (_, element) {
              var $element = $(element);
              if (!$element.is($item)) {
                  this$1.close($element);
              }
          });
      }
      var $content = $item.children(("." + (this.classBody)));
      $content
          .height($content[0].scrollHeight)
          .transitionEnd(function () { return this$1.transitionEnd($content, $item); });
      this.triggerEvent('open', $item);
      $item.addClass(this.classItemOpen);
  };
  /**
   * 关闭指定面板项
   * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
   */
  CollapseAbstract.prototype.close = function close (item) {
          var this$1 = this;

      var $item = this.getItem(item);
      if (!this.isOpen($item)) {
          return;
      }
      var $content = $item.children(("." + (this.classBody)));
      this.triggerEvent('close', $item);
      $item.removeClass(this.classItemOpen);
      $content
          .transition(0)
          .height($content[0].scrollHeight)
          .reflow()
          .transition('')
          .height('')
          .transitionEnd(function () { return this$1.transitionEnd($content, $item); });
  };
  /**
   * 切换指定面板项的打开状态
   * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象
   */
  CollapseAbstract.prototype.toggle = function toggle (item) {
      var $item = this.getItem(item);
      this.isOpen($item) ? this.close($item) : this.open($item);
  };
  /**
   * 打开所有面板项
   */
  CollapseAbstract.prototype.openAll = function openAll () {
          var this$1 = this;

      this.getItems().each(function (_, element) { return this$1.open(element); });
  };
  /**
   * 关闭所有面板项
   */
  CollapseAbstract.prototype.closeAll = function closeAll () {
          var this$1 = this;

      this.getItems().each(function (_, element) { return this$1.close(element); });
  };

  var Collapse = /*@__PURE__*/(function (CollapseAbstract) {
      function Collapse () {
          CollapseAbstract.apply(this, arguments);
      }

      if ( CollapseAbstract ) Collapse.__proto__ = CollapseAbstract;
      Collapse.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype );
      Collapse.prototype.constructor = Collapse;

      Collapse.prototype.getNamespace = function getNamespace () {
          return 'collapse';
      };

      return Collapse;
  }(CollapseAbstract));
  mdui.Collapse = Collapse;

  var customAttr$1 = 'mdui-collapse';
  $(function () {
      mdui.mutation(("[" + customAttr$1 + "]"), function () {
          new mdui.Collapse(this, parseOptions(this, customAttr$1));
      });
  });

  var Panel = /*@__PURE__*/(function (CollapseAbstract) {
      function Panel () {
          CollapseAbstract.apply(this, arguments);
      }

      if ( CollapseAbstract ) Panel.__proto__ = CollapseAbstract;
      Panel.prototype = Object.create( CollapseAbstract && CollapseAbstract.prototype );
      Panel.prototype.constructor = Panel;

      Panel.prototype.getNamespace = function getNamespace () {
          return 'panel';
      };

      return Panel;
  }(CollapseAbstract));
  mdui.Panel = Panel;

  var customAttr$2 = 'mdui-panel';
  $(function () {
      mdui.mutation(("[" + customAttr$2 + "]"), function () {
          new mdui.Panel(this, parseOptions(this, customAttr$2));
      });
  });

  var Table = function Table(selector) {
      /**
       * 表头 tr 元素
       */
      this.$thRow = $();
      /**
       * 表格 body 中的 tr 元素
       */
      this.$tdRows = $();
      /**
       * 表头的 checkbox 元素
       */
      this.$thCheckbox = $();
      /**
       * 表格 body 中的 checkbox 元素
       */
      this.$tdCheckboxs = $();
      /**
       * 表格行是否可选择
       */
      this.selectable = false;
      /**
       * 已选中的行数
       */
      this.selectedRow = 0;
      this.$element = $(selector).first();
      this.init();
  };
  /**
   * 初始化表格
   */
  Table.prototype.init = function init () {
      this.$thRow = this.$element.find('thead tr');
      this.$tdRows = this.$element.find('tbody tr');
      this.selectable = this.$element.hasClass('mdui-table-selectable');
      this.updateThCheckbox();
      this.updateTdCheckbox();
      this.updateNumericCol();
  };
  /**
   * 生成 checkbox 的 HTML 结构
   * @param tag 标签名
   */
  Table.prototype.createCheckboxHTML = function createCheckboxHTML (tag) {
      return ("<" + tag + " class=\"mdui-table-cell-checkbox\">" +
          '<label class="mdui-checkbox">' +
          '<input type="checkbox"/>' +
          '<i class="mdui-checkbox-icon"></i>' +
          '</label>' +
          "</" + tag + ">");
  };
  /**
   * 更新表头 checkbox 的状态
   */
  Table.prototype.updateThCheckboxStatus = function updateThCheckboxStatus () {
      var checkbox = this.$thCheckbox[0];
      var selectedRow = this.selectedRow;
      var tdRowsLength = this.$tdRows.length;
      checkbox.checked = selectedRow === tdRowsLength;
      checkbox.indeterminate = !!selectedRow && selectedRow !== tdRowsLength;
  };
  /**
   * 更新表格行的 checkbox
   */
  Table.prototype.updateTdCheckbox = function updateTdCheckbox () {
          var this$1 = this;

      var rowSelectedClass = 'mdui-table-row-selected';
      this.$tdRows.each(function (_, row) {
          var $row = $(row);
          // 移除旧的 checkbox
          $row.find('.mdui-table-cell-checkbox').remove();
          if (!this$1.selectable) {
              return;
          }
          // 创建 DOM
          var $checkbox = $(this$1.createCheckboxHTML('td'))
              .prependTo($row)
              .find('input[type="checkbox"]');
          // 默认选中的行
          if ($row.hasClass(rowSelectedClass)) {
              $checkbox[0].checked = true;
              this$1.selectedRow++;
          }
          this$1.updateThCheckboxStatus();
          // 绑定事件
          $checkbox.on('change', function () {
              if ($checkbox[0].checked) {
                  $row.addClass(rowSelectedClass);
                  this$1.selectedRow++;
              }
              else {
                  $row.removeClass(rowSelectedClass);
                  this$1.selectedRow--;
              }
              this$1.updateThCheckboxStatus();
          });
          this$1.$tdCheckboxs = this$1.$tdCheckboxs.add($checkbox);
      });
  };
  /**
   * 更新表头的 checkbox
   */
  Table.prototype.updateThCheckbox = function updateThCheckbox () {
          var this$1 = this;

      // 移除旧的 checkbox
      this.$thRow.find('.mdui-table-cell-checkbox').remove();
      if (!this.selectable) {
          return;
      }
      this.$thCheckbox = $(this.createCheckboxHTML('th'))
          .prependTo(this.$thRow)
          .find('input[type="checkbox"]')
          .on('change', function () {
          var isCheckedAll = this$1.$thCheckbox[0].checked;
          this$1.selectedRow = isCheckedAll ? this$1.$tdRows.length : 0;
          this$1.$tdCheckboxs.each(function (_, checkbox) {
              checkbox.checked = isCheckedAll;
          });
          this$1.$tdRows.each(function (_, row) {
              isCheckedAll
                  ? $(row).addClass('mdui-table-row-selected')
                  : $(row).removeClass('mdui-table-row-selected');
          });
      });
  };
  /**
   * 更新数值列
   */
  Table.prototype.updateNumericCol = function updateNumericCol () {
          var this$1 = this;

      var numericClass = 'mdui-table-col-numeric';
      this.$thRow.find('th').each(function (i, th) {
          var isNumericCol = $(th).hasClass(numericClass);
          this$1.$tdRows.each(function (_, row) {
              var $td = $(row).find('td').eq(i);
              isNumericCol
                  ? $td.addClass(numericClass)
                  : $td.removeClass(numericClass);
          });
      });
  };
  var dataName = '_mdui_table';
  $(function () {
      mdui.mutation('.mdui-table', function () {
          var $element = $(this);
          if (!$element.data(dataName)) {
              $element.data(dataName, new Table($element));
          }
      });
  });
  mdui.updateTables = function (selector) {
      var $elements = isUndefined(selector) ? $('.mdui-table') : $(selector);
      $elements.each(function (_, element) {
          var $element = $(element);
          var instance = $element.data(dataName);
          if (instance) {
              instance.init();
          }
          else {
              $element.data(dataName, new Table($element));
          }
      });
  };

  /**
   * touch 事件后的 500ms 内禁用 mousedown 事件
   *
   * 不支持触控的屏幕上事件顺序为 mousedown -> mouseup -> click
   * 支持触控的屏幕上事件顺序为 touchstart -> touchend -> mousedown -> mouseup -> click
   *
   * 在每一个事件中都使用 TouchHandler.isAllow(event) 判断事件是否可执行
   * 在 touchstart 和 touchmove、touchend、touchcancel
   *
   * (function () {
   *   $document
   *     .on(start, function (e) {
   *       if (!isAllow(e)) {
   *         return;
   *       }
   *       register(e);
   *       console.log(e.type);
   *     })
   *     .on(move, function (e) {
   *       if (!isAllow(e)) {
   *         return;
   *       }
   *       console.log(e.type);
   *     })
   *     .on(end, function (e) {
   *       if (!isAllow(e)) {
   *         return;
   *       }
   *       console.log(e.type);
   *     })
   *     .on(unlock, register);
   * })();
   */
  var startEvent = 'touchstart mousedown';
  var moveEvent = 'touchmove mousemove';
  var endEvent = 'touchend mouseup';
  var cancelEvent = 'touchcancel mouseleave';
  var unlockEvent = 'touchend touchmove touchcancel';
  var touches = 0;
  /**
   * 该事件是否被允许，在执行事件前调用该方法判断事件是否可以执行
   * 若已触发 touch 事件，则阻止之后的鼠标事件
   * @param event
   */
  function isAllow(event) {
      return !(touches &&
          [
              'mousedown',
              'mouseup',
              'mousemove',
              'click',
              'mouseover',
              'mouseout',
              'mouseenter',
              'mouseleave' ].indexOf(event.type) > -1);
  }
  /**
   * 在 touchstart 和 touchmove、touchend、touchcancel 事件中调用该方法注册事件
   * @param event
   */
  function register(event) {
      if (event.type === 'touchstart') {
          // 触发了 touch 事件
          touches += 1;
      }
      else if (['touchmove', 'touchend', 'touchcancel'].indexOf(event.type) > -1) {
          // touch 事件结束 500ms 后解除对鼠标事件的阻止
          setTimeout(function () {
              if (touches) {
                  touches -= 1;
              }
          }, 500);
      }
  }

  /**
   * 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
   */
  /**
   * 显示涟漪动画
   * @param event
   * @param $ripple
   */
  function show(event, $ripple) {
      // 鼠标右键不产生涟漪
      if (event instanceof MouseEvent && event.button === 2) {
          return;
      }
      // 点击位置坐标
      var touchPosition = typeof TouchEvent !== 'undefined' &&
          event instanceof TouchEvent &&
          event.touches.length
          ? event.touches[0]
          : event;
      var touchStartX = touchPosition.pageX;
      var touchStartY = touchPosition.pageY;
      // 涟漪位置
      var offset = $ripple.offset();
      var height = $ripple.innerHeight();
      var width = $ripple.innerWidth();
      var center = {
          x: touchStartX - offset.left,
          y: touchStartY - offset.top,
      };
      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 结构，并缓存动画效果
      $("<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>")
          .data('_ripple_wave_translate', translate)
          .prependTo($ripple)
          .reflow()
          .transform(translate);
  }
  /**
   * 隐藏并移除涟漪
   * @param $wave
   */
  function removeRipple($wave) {
      if (!$wave.length || $wave.data('_ripple_wave_removed')) {
          return;
      }
      $wave.data('_ripple_wave_removed', true);
      var removeTimer = setTimeout(function () { return $wave.remove(); }, 400);
      var translate = $wave.data('_ripple_wave_translate');
      $wave
          .addClass('mdui-ripple-wave-fill')
          .transform(translate.replace('scale(1)', 'scale(1.01)'))
          .transitionEnd(function () {
          clearTimeout(removeTimer);
          $wave
              .addClass('mdui-ripple-wave-out')
              .transform(translate.replace('scale(1)', 'scale(1.01)'));
          removeTimer = setTimeout(function () { return $wave.remove(); }, 700);
          setTimeout(function () {
              $wave.transitionEnd(function () {
                  clearTimeout(removeTimer);
                  $wave.remove();
              });
          }, 0);
      });
  }
  /**
   * 隐藏涟漪动画
   * @param this
   */
  function hide() {
      var $ripple = $(this);
      $ripple.children('.mdui-ripple-wave').each(function (_, wave) {
          removeRipple($(wave));
      });
      $ripple.off((moveEvent + " " + endEvent + " " + cancelEvent), hide);
  }
  /**
   * 显示涟漪，并绑定 touchend 等事件
   * @param event
   */
  function showRipple(event) {
      if (!isAllow(event)) {
          return;
      }
      register(event);
      // Chrome 59 点击滚动条时，会在 document 上触发事件
      if (event.target === document) {
          return;
      }
      var $target = $(event.target);
      // 获取含 .mdui-ripple 类的元素
      var $ripple = $target.hasClass('mdui-ripple')
          ? $target
          : $target.parents('.mdui-ripple').first();
      if (!$ripple.length) {
          return;
      }
      // 禁用状态的元素上不产生涟漪效果
      if ($ripple.prop('disabled') || !isUndefined($ripple.attr('disabled'))) {
          return;
      }
      if (event.type === 'touchstart') {
          var hidden = false;
          // touchstart 触发指定时间后开始涟漪动画，避免手指滑动时也触发涟漪
          var timer = setTimeout(function () {
              timer = 0;
              show(event, $ripple);
          }, 200);
          var hideRipple = function () {
              // 如果手指没有移动，且涟漪动画还没有开始，则开始涟漪动画
              if (timer) {
                  clearTimeout(timer);
                  timer = 0;
                  show(event, $ripple);
              }
              if (!hidden) {
                  hidden = true;
                  hide.call($ripple);
              }
          };
          // 手指移动后，移除涟漪动画
          var touchMove = function () {
              if (timer) {
                  clearTimeout(timer);
                  timer = 0;
              }
              hideRipple();
          };
          $ripple.on('touchmove', touchMove).on('touchend touchcancel', hideRipple);
      }
      else {
          show(event, $ripple);
          $ripple.on((moveEvent + " " + endEvent + " " + cancelEvent), hide);
      }
  }
  $(function () {
      $document.on(startEvent, showRipple).on(unlockEvent, register);
  });

  var defaultData = {
      reInit: false,
      domLoadedEvent: false,
  };
  /**
   * 输入框事件
   * @param event
   * @param data
   */
  function inputEvent(event, data) {
      if ( data === void 0 ) data = {};

      data = extend({}, defaultData, data);
      var input = event.target;
      var $input = $(input);
      var eventType = event.type;
      var value = $input.val();
      // 文本框类型
      var inputType = $input.attr('type') || '';
      if (['checkbox', 'button', 'submit', 'range', 'radio', 'image'].indexOf(inputType) > -1) {
          return;
      }
      var $textfield = $input.parent('.mdui-textfield');
      // 输入框是否聚焦
      if (eventType === 'focus') {
          $textfield.addClass('mdui-textfield-focus');
      }
      if (eventType === 'blur') {
          $textfield.removeClass('mdui-textfield-focus');
      }
      // 输入框是否为空
      if (eventType === 'blur' || eventType === 'input') {
          value
              ? $textfield.addClass('mdui-textfield-not-empty')
              : $textfield.removeClass('mdui-textfield-not-empty');
      }
      // 输入框是否禁用
      input.disabled
          ? $textfield.addClass('mdui-textfield-disabled')
          : $textfield.removeClass('mdui-textfield-disabled');
      // 表单验证
      if ((eventType === 'input' || eventType === 'blur') &&
          !data.domLoadedEvent &&
          input.validity) {
          input.validity.valid
              ? $textfield.removeClass('mdui-textfield-invalid-html5')
              : $textfield.addClass('mdui-textfield-invalid-html5');
      }
      // textarea 高度自动调整
      if ($input.is('textarea')) {
          // IE bug：textarea 的值仅为多个换行，不含其他内容时，textarea 的高度不准确
          //         此时，在计算高度前，在值的开头加入一个空格，计算完后，移除空格
          var inputValue = value;
          var hasExtraSpace = false;
          if (inputValue.replace(/[\r\n]/g, '') === '') {
              $input.val(' ' + inputValue);
              hasExtraSpace = true;
          }
          // 设置 textarea 高度
          $input.outerHeight('');
          var height = $input.outerHeight();
          var scrollHeight = input.scrollHeight;
          if (scrollHeight > height) {
              $input.outerHeight(scrollHeight);
          }
          // 计算完，还原 textarea 的值
          if (hasExtraSpace) {
              $input.val(inputValue);
          }
      }
      // 实时字数统计
      if (data.reInit) {
          $textfield.find('.mdui-textfield-counter').remove();
      }
      var maxLength = $input.attr('maxlength');
      if (maxLength) {
          if (data.reInit || data.domLoadedEvent) {
              $('<div class="mdui-textfield-counter">' +
                  "<span class=\"mdui-textfield-counter-inputed\"></span> / " + maxLength +
                  '</div>').appendTo($textfield);
          }
          $textfield
              .find('.mdui-textfield-counter-inputed')
              .text(value.length.toString());
      }
      // 含 帮助文本、错误提示、字数统计 时，增加文本框底部内边距
      if ($textfield.find('.mdui-textfield-helper').length ||
          $textfield.find('.mdui-textfield-error').length ||
          maxLength) {
          $textfield.addClass('mdui-textfield-has-bottom');
      }
  }
  $(function () {
      // 绑定事件
      $document.on('input focus blur', '.mdui-textfield-input', { useCapture: true }, inputEvent);
      // 可展开文本框展开
      $document.on('click', '.mdui-textfield-expandable .mdui-textfield-icon', function () {
          $(this)
              .parents('.mdui-textfield')
              .addClass('mdui-textfield-expanded')
              .find('.mdui-textfield-input')[0]
              .focus();
      });
      // 可展开文本框关闭
      $document.on('click', '.mdui-textfield-expanded .mdui-textfield-close', function () {
          $(this)
              .parents('.mdui-textfield')
              .removeClass('mdui-textfield-expanded')
              .find('.mdui-textfield-input')
              .val('');
      });
      /**
       * 初始化文本框
       */
      mdui.mutation('.mdui-textfield', function () {
          $(this).find('.mdui-textfield-input').trigger('input', {
              domLoadedEvent: true,
          });
      });
  });
  mdui.updateTextFields = function (selector) {
      var $elements = isUndefined(selector) ? $('.mdui-textfield') : $(selector);
      $elements.each(function (_, element) {
          $(element).find('.mdui-textfield-input').trigger('input', {
              reInit: true,
          });
      });
  };

  /**
   * 滑块的值改变后修改滑块样式
   * @param $slider
   */
  function updateValueStyle($slider) {
      var data = $slider.data();
      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 value = $input.val();
      var percent = ((value - min) / (max - min)) * 100;
      $fill.width((percent + "%"));
      $track.width(((100 - percent) + "%"));
      if (isDisabled) {
          $fill.css('padding-right', '6px');
          $track.css('padding-left', '6px');
      }
      $thumb.css('left', (percent + "%"));
      if (isDiscrete) {
          $thumbText.text(value);
      }
      percent === 0
          ? $slider.addClass('mdui-slider-zero')
          : $slider.removeClass('mdui-slider-zero');
  }
  /**
   * 重新初始化滑块
   * @param $slider
   */
  function reInit($slider) {
      var $track = $('<div class="mdui-slider-track"></div>');
      var $fill = $('<div class="mdui-slider-fill"></div>');
      var $thumb = $('<div class="mdui-slider-thumb"></div>');
      var $input = $slider.find('input[type="range"]');
      var isDisabled = $input[0].disabled;
      var isDiscrete = $slider.hasClass('mdui-slider-discrete');
      // 禁用状态
      isDisabled
          ? $slider.addClass('mdui-slider-disabled')
          : $slider.removeClass('mdui-slider-disabled');
      // 重新填充 HTML
      $slider.find('.mdui-slider-track').remove();
      $slider.find('.mdui-slider-fill').remove();
      $slider.find('.mdui-slider-thumb').remove();
      $slider.append($track).append($fill).append($thumb);
      // 间续型滑块
      var $thumbText = $();
      if (isDiscrete) {
          $thumbText = $('<span></span>');
          $thumb.empty().append($thumbText);
      }
      $slider.data('_slider_$track', $track);
      $slider.data('_slider_$fill', $fill);
      $slider.data('_slider_$thumb', $thumb);
      $slider.data('_slider_$input', $input);
      $slider.data('_slider_min', $input.attr('min'));
      $slider.data('_slider_max', $input.attr('max'));
      $slider.data('_slider_disabled', isDisabled);
      $slider.data('_slider_discrete', isDiscrete);
      $slider.data('_slider_$thumbText', $thumbText);
      // 设置默认值
      updateValueStyle($slider);
  }
  var rangeSelector = '.mdui-slider input[type="range"]';
  $(function () {
      // 滑块滑动事件
      $document.on('input change', rangeSelector, function () {
          var $slider = $(this).parent();
          updateValueStyle($slider);
      });
      // 开始触摸滑块事件
      $document.on(startEvent, rangeSelector, function (event) {
          if (!isAllow(event)) {
              return;
          }
          register(event);
          if (this.disabled) {
              return;
          }
          var $slider = $(this).parent();
          $slider.addClass('mdui-slider-focus');
      });
      // 结束触摸滑块事件
      $document.on(endEvent, rangeSelector, function (event) {
          if (!isAllow(event)) {
              return;
          }
          if (this.disabled) {
              return;
          }
          var $slider = $(this).parent();
          $slider.removeClass('mdui-slider-focus');
      });
      $document.on(unlockEvent, rangeSelector, register);
      /**
       * 初始化滑块
       */
      mdui.mutation('.mdui-slider', function () {
          reInit($(this));
      });
  });
  mdui.updateSliders = function (selector) {
      var $elements = isUndefined(selector) ? $('.mdui-slider') : $(selector);
      $elements.each(function (_, element) {
          reInit($(element));
      });
  };

  var DEFAULT_OPTIONS$2 = {
      trigger: 'hover',
  };
  var Fab = function Fab(selector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$2);
      /**
       * 当前 fab 的状态
       */
      this.state = 'closed';
      this.$element = $(selector).first();
      extend(this.options, options);
      this.$btn = this.$element.find('.mdui-fab');
      this.$dial = this.$element.find('.mdui-fab-dial');
      this.$dialBtns = this.$dial.find('.mdui-fab');
      if (this.options.trigger === 'hover') {
          this.$btn.on('touchstart mouseenter', function () { return this$1.open(); });
          this.$element.on('mouseleave', function () { return this$1.close(); });
      }
      if (this.options.trigger === 'click') {
          this.$btn.on(startEvent, function () { return this$1.open(); });
      }
      // 触摸屏幕其他地方关闭快速拨号
      $document.on(startEvent, function (event) {
          if ($(event.target).parents('.mdui-fab-wrapper').length) {
              return;
          }
          this$1.close();
      });
  };
  /**
   * 触发组件事件
   * @param name
   */
  Fab.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'fab', this.$element, this);
  };
  /**
   * 当前是否为打开状态
   */
  Fab.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 打开快速拨号菜单
   */
  Fab.prototype.open = function open () {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      // 为菜单中的按钮添加不同的 transition-delay
      this.$dialBtns.each(function (index, btn) {
          var delay = (15 * (this$1.$dialBtns.length - index)) + "ms";
          btn.style.transitionDelay = delay;
          btn.style.webkitTransitionDelay = delay;
      });
      this.$dial.css('height', 'auto').addClass('mdui-fab-dial-show');
      // 如果按钮中存在 .mdui-fab-opened 的图标，则进行图标切换
      if (this.$btn.find('.mdui-fab-opened').length) {
          this.$btn.addClass('mdui-fab-opened');
      }
      this.state = 'opening';
      this.triggerEvent('open');
      // 打开顺序为从下到上逐个打开，最上面的打开后才表示动画完成
      this.$dialBtns.first().transitionEnd(function () {
          if (this$1.$btn.hasClass('mdui-fab-opened')) {
              this$1.state = 'opened';
              this$1.triggerEvent('opened');
          }
      });
  };
  /**
   * 关闭快速拨号菜单
   */
  Fab.prototype.close = function close () {
          var this$1 = this;

      if (!this.isOpen()) {
          return;
      }
      // 为菜单中的按钮添加不同的 transition-delay
      this.$dialBtns.each(function (index, btn) {
          var delay = (15 * index) + "ms";
          btn.style.transitionDelay = delay;
          btn.style.webkitTransitionDelay = delay;
      });
      this.$dial.removeClass('mdui-fab-dial-show');
      this.$btn.removeClass('mdui-fab-opened');
      this.state = 'closing';
      this.triggerEvent('close');
      // 从上往下依次关闭，最后一个关闭后才表示动画完成
      this.$dialBtns.last().transitionEnd(function () {
          if (this$1.$btn.hasClass('mdui-fab-opened')) {
              return;
          }
          this$1.state = 'closed';
          this$1.triggerEvent('closed');
          this$1.$dial.css('height', 0);
      });
  };
  /**
   * 切换快速拨号菜单的打开状态
   */
  Fab.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 以动画的形式显示整个浮动操作按钮
   */
  Fab.prototype.show = function show () {
      this.$element.removeClass('mdui-fab-hide');
  };
  /**
   * 以动画的形式隐藏整个浮动操作按钮
   */
  Fab.prototype.hide = function hide () {
      this.$element.addClass('mdui-fab-hide');
  };
  /**
   * 返回当前快速拨号菜单的打开状态。共包含四种状态：`opening`、`opened`、`closing`、`closed`
   */
  Fab.prototype.getState = function getState () {
      return this.state;
  };
  mdui.Fab = Fab;

  var customAttr$3 = 'mdui-fab';
  $(function () {
      // mouseenter 不冒泡，无法进行事件委托，这里用 mouseover 代替。
      // 不管是 click 、 mouseover 还是 touchstart ，都先初始化。
      $document.on('touchstart mousedown mouseover', ("[" + customAttr$3 + "]"), function () {
          new mdui.Fab(this, parseOptions(this, customAttr$3));
      });
  });

  /**
   * 最终生成的元素结构为：
   *  <select class="mdui-select" mdui-select="{position: 'top'}" style="display: none;"> // $native
   *    <option value="1">State 1</option>
   *    <option value="2">State 2</option>
   *    <option value="3" disabled="">State 3</option>
   *  </select>
   *  <div class="mdui-select mdui-select-position-top" style="" id="88dec0e4-d4a2-c6d0-0e7f-1ba4501e0553"> // $element
   *    <span class="mdui-select-selected">State 1</span> // $selected
   *    <div class="mdui-select-menu" style="transform-origin: center 100% 0px;"> // $menu
   *      <div class="mdui-select-menu-item mdui-ripple" selected="">State 1</div> // $items
   *      <div class="mdui-select-menu-item mdui-ripple">State 2</div>
   *      <div class="mdui-select-menu-item mdui-ripple" disabled="">State 3</div>
   *    </div>
   *  </div>
   */
  var DEFAULT_OPTIONS$3 = {
      position: 'auto',
      gutter: 16,
  };
  var Select = function Select(selector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 生成的 `<div class="mdui-select">` 元素的 JQ 对象
       */
      this.$element = $();
      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$3);
      /**
       * select 的 size 属性的值，根据该值设置 select 的高度
       */
      this.size = 0;
      /**
       * 占位元素，显示已选中菜单项的文本
       */
      this.$selected = $();
      /**
       * 菜单项的外层元素的 JQ 对象
       */
      this.$menu = $();
      /**
       * 菜单项数组的 JQ 对象
       */
      this.$items = $();
      /**
       * 当前选中的菜单项的索引号
       */
      this.selectedIndex = 0;
      /**
       * 当前选中菜单项的文本
       */
      this.selectedText = '';
      /**
       * 当前选中菜单项的值
       */
      this.selectedValue = '';
      /**
       * 当前 select 的状态
       */
      this.state = 'closed';
      this.$native = $(selector).first();
      this.$native.hide();
      extend(this.options, options);
      // 为当前 select 生成唯一 ID
      this.uniqueID = $.guid();
      // 生成 select
      this.handleUpdate();
      // 点击 select 外面区域关闭
      $document.on('click touchstart', function (event) {
          var $target = $(event.target);
          if (this$1.isOpen() &&
              !$target.is(this$1.$element) &&
              !contains(this$1.$element[0], $target[0])) {
              this$1.close();
          }
      });
  };
  /**
   * 调整菜单位置
   */
  Select.prototype.readjustMenu = function readjustMenu () {
      var windowHeight = $window.height();
      // mdui-select 高度
      var elementHeight = this.$element.height();
      // 菜单项高度
      var $itemFirst = this.$items.first();
      var itemHeight = $itemFirst.height();
      var itemMargin = parseInt($itemFirst.css('margin-top'));
      // 菜单高度
      var menuWidth = this.$element.innerWidth() + 0.01; // 必须比真实宽度多一点，不然会出现省略号
      var menuHeight = itemHeight * this.size + itemMargin * 2;
      // mdui-select 在窗口中的位置
      var elementTop = this.$element[0].getBoundingClientRect().top;
      var transformOriginY;
      var menuMarginTop;
      if (this.options.position === 'bottom') {
          menuMarginTop = elementHeight;
          transformOriginY = '0px';
      }
      else if (this.options.position === 'top') {
          menuMarginTop = -menuHeight - 1;
          transformOriginY = '100%';
      }
      else {
          // 菜单高度不能超过窗口高度
          var menuMaxHeight = windowHeight - this.options.gutter * 2;
          if (menuHeight > menuMaxHeight) {
              menuHeight = menuMaxHeight;
          }
          // 菜单的 margin-top
          menuMarginTop = -(itemMargin +
              this.selectedIndex * itemHeight +
              (itemHeight - elementHeight) / 2);
          var menuMaxMarginTop = -(itemMargin +
              (this.size - 1) * itemHeight +
              (itemHeight - elementHeight) / 2);
          if (menuMarginTop < menuMaxMarginTop) {
              menuMarginTop = menuMaxMarginTop;
          }
          // 菜单不能超出窗口
          var menuTop = elementTop + menuMarginTop;
          if (menuTop < this.options.gutter) {
              // 不能超出窗口上方
              menuMarginTop = -(elementTop - this.options.gutter);
          }
          else if (menuTop + menuHeight + this.options.gutter > windowHeight) {
              // 不能超出窗口下方
              menuMarginTop = -(elementTop +
                  menuHeight +
                  this.options.gutter -
                  windowHeight);
          }
          // transform 的 Y 轴坐标
          transformOriginY = (this.selectedIndex * itemHeight + itemHeight / 2 + itemMargin) + "px";
      }
      // 设置样式
      this.$element.innerWidth(menuWidth);
      this.$menu
          .innerWidth(menuWidth)
          .height(menuHeight)
          .css({
          'margin-top': menuMarginTop + 'px',
          'transform-origin': 'center ' + transformOriginY + ' 0',
      });
  };
  /**
   * select 是否为打开状态
   */
  Select.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 对原生 select 组件进行了修改后，需要调用该方法
   */
  Select.prototype.handleUpdate = function handleUpdate () {
          var this$1 = this;

      if (this.isOpen()) {
          this.close();
      }
      this.selectedValue = this.$native.val();
      var itemsData = [];
      this.$items = $();
      // 生成 HTML
      this.$native.find('option').each(function (index, option) {
          var text = option.textContent || '';
          var value = option.value;
          var disabled = option.disabled;
          var selected = this$1.selectedValue === value;
          itemsData.push({
              value: value,
              text: text,
              disabled: disabled,
              selected: selected,
              index: index,
          });
          if (selected) {
              this$1.selectedText = text;
              this$1.selectedIndex = index;
          }
          this$1.$items = this$1.$items.add('<div class="mdui-select-menu-item mdui-ripple"' +
              (disabled ? ' disabled' : '') +
              (selected ? ' selected' : '') +
              ">" + text + "</div>");
      });
      this.$selected = $(("<span class=\"mdui-select-selected\">" + (this.selectedText) + "</span>"));
      this.$element = $("<div class=\"mdui-select mdui-select-position-" + (this.options.position) + "\" " +
          "style=\"" + (this.$native.attr('style')) + "\" " +
          "id=\"" + (this.uniqueID) + "\"></div>")
          .show()
          .append(this.$selected);
      this.$menu = $('<div class="mdui-select-menu"></div>')
          .appendTo(this.$element)
          .append(this.$items);
      $(("#" + (this.uniqueID))).remove();
      this.$native.after(this.$element);
      // 根据 select 的 size 属性设置高度
      this.size = parseInt(this.$native.attr('size') || '0');
      if (this.size <= 0) {
          this.size = this.$items.length;
          if (this.size > 8) {
              this.size = 8;
          }
      }
      // 点击选项时关闭下拉菜单
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      this.$items.on('click', function () {
          if (that.state === 'closing') {
              return;
          }
          var $item = $(this);
          var index = $item.index();
          var data = itemsData[index];
          if (data.disabled) {
              return;
          }
          that.$selected.text(data.text);
          that.$native.val(data.value);
          that.$items.removeAttr('selected');
          $item.attr('selected', '');
          that.selectedIndex = data.index;
          that.selectedValue = data.value;
          that.selectedText = data.text;
          that.$native.trigger('change');
          that.close();
      });
      // 点击 $element 时打开下拉菜单
      this.$element.on('click', function (event) {
          var $target = $(event.target);
          // 在菜单上点击时不打开
          if ($target.is('.mdui-select-menu') ||
              $target.is('.mdui-select-menu-item')) {
              return;
          }
          this$1.toggle();
      });
  };
  /**
   * 动画结束的回调
   */
  Select.prototype.transitionEnd = function transitionEnd () {
      this.$element.removeClass('mdui-select-closing');
      if (this.state === 'opening') {
          this.state = 'opened';
          this.triggerEvent('opened');
          this.$menu.css('overflow-y', 'auto');
      }
      if (this.state === 'closing') {
          this.state = 'closed';
          this.triggerEvent('closed');
          // 恢复样式
          this.$element.innerWidth('');
          this.$menu.css({
              'margin-top': '',
              height: '',
              width: '',
          });
      }
  };
  /**
   * 触发组件事件
   * @param name
   */
  Select.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'select', this.$native, this);
  };
  /**
   * 切换下拉菜单的打开状态
   */
  Select.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 打开下拉菜单
   */
  Select.prototype.open = function open () {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      this.state = 'opening';
      this.triggerEvent('open');
      this.readjustMenu();
      this.$element.addClass('mdui-select-open');
      this.$menu.transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 关闭下拉菜单
   */
  Select.prototype.close = function close () {
          var this$1 = this;

      if (!this.isOpen()) {
          return;
      }
      this.state = 'closing';
      this.triggerEvent('close');
      this.$menu.css('overflow-y', '');
      this.$element
          .removeClass('mdui-select-open')
          .addClass('mdui-select-closing');
      this.$menu.transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 获取当前菜单的状态。共包含四种状态：`opening`、`opened`、`closing`、`closed`
   */
  Select.prototype.getState = function getState () {
      return this.state;
  };
  mdui.Select = Select;

  var customAttr$4 = 'mdui-select';
  $(function () {
      mdui.mutation(("[" + customAttr$4 + "]"), function () {
          new mdui.Select(this, parseOptions(this, customAttr$4));
      });
  });

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

  var DEFAULT_OPTIONS$4 = {
      trigger: 'click',
      loop: false,
  };
  var Tab = function Tab(selector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$4);
      /**
       * 当前激活的 tab 的索引号。为 -1 时表示没有激活的选项卡，或不存在选项卡
       */
      this.activeIndex = -1;
      this.$element = $(selector).first();
      extend(this.options, options);
      this.$tabs = this.$element.children('a');
      this.$indicator = $('<div class="mdui-tab-indicator"></div>').appendTo(this.$element);
      // 根据 url hash 获取默认激活的选项卡
      var hash = window.location.hash;
      if (hash) {
          this.$tabs.each(function (index, tab) {
              if ($(tab).attr('href') === hash) {
                  this$1.activeIndex = index;
                  return false;
              }
              return true;
          });
      }
      // 含 .mdui-tab-active 的元素默认激活
      if (this.activeIndex === -1) {
          this.$tabs.each(function (index, tab) {
              if ($(tab).hasClass('mdui-tab-active')) {
                  this$1.activeIndex = index;
                  return false;
              }
              return true;
          });
      }
      // 存在选项卡时，默认激活第一个选项卡
      if (this.$tabs.length && this.activeIndex === -1) {
          this.activeIndex = 0;
      }
      // 设置激活状态选项卡
      this.setActive();
      // 监听窗口大小变化事件，调整指示器位置
      $window.on('resize', $.throttle(function () { return this$1.setIndicatorPosition(); }, 100));
      // 监听点击选项卡事件
      this.$tabs.each(function (_, tab) {
          this$1.bindTabEvent(tab);
      });
  };
  /**
   * 指定选项卡是否已禁用
   * @param $tab
   */
  Tab.prototype.isDisabled = function isDisabled ($tab) {
      return $tab.attr('disabled') !== undefined;
  };
  /**
   * 绑定在 Tab 上点击或悬浮的事件
   * @param tab
   */
  Tab.prototype.bindTabEvent = function bindTabEvent (tab) {
          var this$1 = this;

      var $tab = $(tab);
      // 点击或鼠标移入触发的事件
      var clickEvent = function () {
          // 禁用状态的选项卡无法选中
          if (this$1.isDisabled($tab)) {
              return false;
          }
          this$1.activeIndex = this$1.$tabs.index(tab);
          this$1.setActive();
      };
      // 无论 trigger 是 click 还是 hover，都会响应 click 事件
      $tab.on('click', clickEvent);
      // trigger 为 hover 时，额外响应 mouseenter 事件
      if (this.options.trigger === 'hover') {
          $tab.on('mouseenter', clickEvent);
      }
      // 阻止链接的默认点击动作
      $tab.on('click', function () {
          if (($tab.attr('href') || '').indexOf('#') === 0) {
              return false;
          }
      });
  };
  /**
   * 触发组件事件
   * @param name
   * @param $element
   * @param parameters
   */
  Tab.prototype.triggerEvent = function triggerEvent (name, $element, parameters) {
          if ( parameters === void 0 ) parameters = {};

      componentEvent(name, 'tab', $element, this, parameters);
  };
  /**
   * 设置激活状态的选项卡
   */
  Tab.prototype.setActive = function setActive () {
          var this$1 = this;

      this.$tabs.each(function (index, tab) {
          var $tab = $(tab);
          var targetId = $tab.attr('href') || '';
          // 设置选项卡激活状态
          if (index === this$1.activeIndex && !this$1.isDisabled($tab)) {
              if (!$tab.hasClass('mdui-tab-active')) {
                  this$1.triggerEvent('change', this$1.$element, {
                      index: this$1.activeIndex,
                      id: targetId.substr(1),
                  });
                  this$1.triggerEvent('show', $tab);
                  $tab.addClass('mdui-tab-active');
              }
              $(targetId).show();
              this$1.setIndicatorPosition();
          }
          else {
              $tab.removeClass('mdui-tab-active');
              $(targetId).hide();
          }
      });
  };
  /**
   * 设置选项卡指示器的位置
   */
  Tab.prototype.setIndicatorPosition = function setIndicatorPosition () {
      // 选项卡数量为 0 时，不显示指示器
      if (this.activeIndex === -1) {
          this.$indicator.css({
              left: 0,
              width: 0,
          });
          return;
      }
      var $activeTab = this.$tabs.eq(this.activeIndex);
      if (this.isDisabled($activeTab)) {
          return;
      }
      var activeTabOffset = $activeTab.offset();
      this.$indicator.css({
          left: ((activeTabOffset.left +
              this.$element[0].scrollLeft -
              this.$element[0].getBoundingClientRect().left) + "px"),
          width: (($activeTab.innerWidth()) + "px"),
      });
  };
  /**
   * 切换到下一个选项卡
   */
  Tab.prototype.next = function next () {
      if (this.activeIndex === -1) {
          return;
      }
      if (this.$tabs.length > this.activeIndex + 1) {
          this.activeIndex++;
      }
      else if (this.options.loop) {
          this.activeIndex = 0;
      }
      this.setActive();
  };
  /**
   * 切换到上一个选项卡
   */
  Tab.prototype.prev = function prev () {
      if (this.activeIndex === -1) {
          return;
      }
      if (this.activeIndex > 0) {
          this.activeIndex--;
      }
      else if (this.options.loop) {
          this.activeIndex = this.$tabs.length - 1;
      }
      this.setActive();
  };
  /**
   * 显示指定索引号、或指定id的选项卡
   * @param index 索引号、或id
   */
  Tab.prototype.show = function show (index) {
          var this$1 = this;

      if (this.activeIndex === -1) {
          return;
      }
      if (isNumber(index)) {
          this.activeIndex = index;
      }
      else {
          this.$tabs.each(function (i, tab) {
              if (tab.id === index) {
                  this$1.activeIndex === i;
                  return false;
              }
          });
      }
      this.setActive();
  };
  /**
   * 在父元素的宽度变化时，需要调用该方法重新调整指示器位置
   * 在添加或删除选项卡时，需要调用该方法
   */
  Tab.prototype.handleUpdate = function handleUpdate () {
          var this$1 = this;

      var $oldTabs = this.$tabs; // 旧的 tabs JQ对象
      var $newTabs = this.$element.children('a'); // 新的 tabs JQ对象
      var oldTabsElement = $oldTabs.get(); // 旧的 tabs 元素数组
      var newTabsElement = $newTabs.get(); // 新的 tabs 元素数组
      if (!$newTabs.length) {
          this.activeIndex = -1;
          this.$tabs = $newTabs;
          this.setIndicatorPosition();
          return;
      }
      // 重新遍历选项卡，找出新增的选项卡
      $newTabs.each(function (index, tab) {
          // 有新增的选项卡
          if (oldTabsElement.indexOf(tab) < 0) {
              this$1.bindTabEvent(tab);
              if (this$1.activeIndex === -1) {
                  this$1.activeIndex = 0;
              }
              else if (index <= this$1.activeIndex) {
                  this$1.activeIndex++;
              }
          }
      });
      // 找出被移除的选项卡
      $oldTabs.each(function (index, tab) {
          // 有被移除的选项卡
          if (newTabsElement.indexOf(tab) < 0) {
              if (index < this$1.activeIndex) {
                  this$1.activeIndex--;
              }
              else if (index === this$1.activeIndex) {
                  this$1.activeIndex = 0;
              }
          }
      });
      this.$tabs = $newTabs;
      this.setActive();
  };
  mdui.Tab = Tab;

  var customAttr$5 = 'mdui-tab';
  $(function () {
      mdui.mutation(("[" + customAttr$5 + "]"), function () {
          new mdui.Tab(this, parseOptions(this, customAttr$5));
      });
  });

  /**
   * 在桌面设备上默认显示抽屉栏，不显示遮罩层
   * 在手机和平板设备上默认不显示抽屉栏，始终显示遮罩层，且覆盖导航栏
   */
  var DEFAULT_OPTIONS$5 = {
      overlay: false,
      swipe: false,
  };
  var Drawer = function Drawer(selector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$5);
      /**
       * 当前是否显示着遮罩层
       */
      this.overlay = false;
      this.$element = $(selector).first();
      extend(this.options, options);
      this.position = this.$element.hasClass('mdui-drawer-right')
          ? 'right'
          : 'left';
      if (this.$element.hasClass('mdui-drawer-close')) {
          this.state = 'closed';
      }
      else if (this.$element.hasClass('mdui-drawer-open')) {
          this.state = 'opened';
      }
      else if (this.isDesktop()) {
          this.state = 'opened';
      }
      else {
          this.state = 'closed';
      }
      // 浏览器窗口大小调整时
      $window.on('resize', $.throttle(function () {
          if (this$1.isDesktop()) {
              // 由手机平板切换到桌面时
              // 如果显示着遮罩，则隐藏遮罩
              if (this$1.overlay && !this$1.options.overlay) {
                  $.hideOverlay();
                  this$1.overlay = false;
                  $.unlockScreen();
              }
              // 没有强制关闭，则状态为打开状态
              if (!this$1.$element.hasClass('mdui-drawer-close')) {
                  this$1.state = 'opened';
              }
          }
          else if (!this$1.overlay && this$1.state === 'opened') {
              // 由桌面切换到手机平板时。如果抽屉栏是打开着的且没有遮罩层，则关闭抽屉栏
              if (this$1.$element.hasClass('mdui-drawer-open')) {
                  $.showOverlay();
                  this$1.overlay = true;
                  $.lockScreen();
                  $('.mdui-overlay').one('click', function () { return this$1.close(); });
              }
              else {
                  this$1.state = 'closed';
              }
          }
      }, 100));
      // 绑定关闭按钮事件
      this.$element.find('[mdui-drawer-close]').each(function (_, close) {
          $(close).on('click', function () { return this$1.close(); });
      });
      this.swipeSupport();
  };
  /**
   * 是否是桌面设备
   */
  Drawer.prototype.isDesktop = function isDesktop () {
      return $window.width() >= 1024;
  };
  /**
   * 滑动手势支持
   */
  Drawer.prototype.swipeSupport = function swipeSupport () {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      // 抽屉栏滑动手势控制
      var openNavEventHandler;
      var touchStartX;
      var touchStartY;
      var swipeStartX;
      var swiping = null;
      var maybeSwiping = false;
      var $body = $('body');
      // 手势触发的范围
      var swipeAreaWidth = 24;
      function setPosition(translateX) {
          var rtlTranslateMultiplier = that.position === 'right' ? -1 : 1;
          var transformCSS = "translate(" + (-1 * rtlTranslateMultiplier * translateX) + "px, 0) !important;";
          var transitionCSS = 'initial !important;';
          that.$element.css('cssText', ("transform: " + transformCSS + "; transition: " + transitionCSS + ";"));
      }
      function cleanPosition() {
          that.$element[0].style.transform = '';
          that.$element[0].style.webkitTransform = '';
          that.$element[0].style.transition = '';
          that.$element[0].style.webkitTransition = '';
      }
      function getMaxTranslateX() {
          return that.$element.width() + 10;
      }
      function getTranslateX(currentX) {
          return Math.min(Math.max(swiping === 'closing'
              ? swipeStartX - currentX
              : getMaxTranslateX() + swipeStartX - currentX, 0), getMaxTranslateX());
      }
      function onBodyTouchEnd(event) {
          if (swiping) {
              var touchX = event.changedTouches[0].pageX;
              if (that.position === 'right') {
                  touchX = $body.width() - touchX;
              }
              var translateRatio = getTranslateX(touchX) / getMaxTranslateX();
              maybeSwiping = false;
              var swipingState = swiping;
              swiping = null;
              if (swipingState === 'opening') {
                  if (translateRatio < 0.92) {
                      cleanPosition();
                      that.open();
                  }
                  else {
                      cleanPosition();
                  }
              }
              else {
                  if (translateRatio > 0.08) {
                      cleanPosition();
                      that.close();
                  }
                  else {
                      cleanPosition();
                  }
              }
              $.unlockScreen();
          }
          else {
              maybeSwiping = false;
          }
          $body.off({
              // eslint-disable-next-line @typescript-eslint/no-use-before-define
              touchmove: onBodyTouchMove,
              touchend: onBodyTouchEnd,
              // eslint-disable-next-line @typescript-eslint/no-use-before-define
              touchcancel: onBodyTouchMove,
          });
      }
      function onBodyTouchMove(event) {
          var touchX = event.touches[0].pageX;
          if (that.position === 'right') {
              touchX = $body.width() - touchX;
          }
          var touchY = event.touches[0].pageY;
          if (swiping) {
              setPosition(getTranslateX(touchX));
          }
          else if (maybeSwiping) {
              var dXAbs = Math.abs(touchX - touchStartX);
              var dYAbs = Math.abs(touchY - touchStartY);
              var threshold = 8;
              if (dXAbs > threshold && dYAbs <= threshold) {
                  swipeStartX = touchX;
                  swiping = that.state === 'opened' ? 'closing' : 'opening';
                  $.lockScreen();
                  setPosition(getTranslateX(touchX));
              }
              else if (dXAbs <= threshold && dYAbs > threshold) {
                  onBodyTouchEnd();
              }
          }
      }
      function onBodyTouchStart(event) {
          touchStartX = event.touches[0].pageX;
          if (that.position === 'right') {
              touchStartX = $body.width() - touchStartX;
          }
          touchStartY = event.touches[0].pageY;
          if (that.state !== 'opened') {
              if (touchStartX > swipeAreaWidth ||
                  openNavEventHandler !== onBodyTouchStart) {
                  return;
              }
          }
          maybeSwiping = true;
          $body.on({
              touchmove: onBodyTouchMove,
              touchend: onBodyTouchEnd,
              touchcancel: onBodyTouchMove,
          });
      }
      function enableSwipeHandling() {
          if (!openNavEventHandler) {
              $body.on('touchstart', onBodyTouchStart);
              openNavEventHandler = onBodyTouchStart;
          }
      }
      if (this.options.swipe) {
          enableSwipeHandling();
      }
  };
  /**
   * 触发组件事件
   * @param name
   */
  Drawer.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'drawer', this.$element, this);
  };
  /**
   * 动画结束回调
   */
  Drawer.prototype.transitionEnd = function transitionEnd () {
      if (this.$element.hasClass('mdui-drawer-open')) {
          this.state = 'opened';
          this.triggerEvent('opened');
      }
      else {
          this.state = 'closed';
          this.triggerEvent('closed');
      }
  };
  /**
   * 是否处于打开状态
   */
  Drawer.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 打开抽屉栏
   */
  Drawer.prototype.open = function open () {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      this.state = 'opening';
      this.triggerEvent('open');
      if (!this.options.overlay) {
          $('body').addClass(("mdui-drawer-body-" + (this.position)));
      }
      this.$element
          .removeClass('mdui-drawer-close')
          .addClass('mdui-drawer-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
      if (!this.isDesktop() || this.options.overlay) {
          this.overlay = true;
          $.showOverlay().one('click', function () { return this$1.close(); });
          $.lockScreen();
      }
  };
  /**
   * 关闭抽屉栏
   */
  Drawer.prototype.close = function close () {
          var this$1 = this;

      if (!this.isOpen()) {
          return;
      }
      this.state = 'closing';
      this.triggerEvent('close');
      if (!this.options.overlay) {
          $('body').removeClass(("mdui-drawer-body-" + (this.position)));
      }
      this.$element
          .addClass('mdui-drawer-close')
          .removeClass('mdui-drawer-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
      if (this.overlay) {
          $.hideOverlay();
          this.overlay = false;
          $.unlockScreen();
      }
  };
  /**
   * 切换抽屉栏打开/关闭状态
   */
  Drawer.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 返回当前抽屉栏的状态。共包含四种状态：`opening`、`opened`、`closing`、`closed`
   */
  Drawer.prototype.getState = function getState () {
      return this.state;
  };
  mdui.Drawer = Drawer;

  var customAttr$6 = 'mdui-drawer';
  $(function () {
      mdui.mutation(("[" + customAttr$6 + "]"), function () {
          var $element = $(this);
          var options = parseOptions(this, customAttr$6);
          var selector = options.target;
          // @ts-ignore
          delete options.target;
          var $drawer = $(selector).first();
          var instance = new mdui.Drawer($drawer, options);
          $element.on('click', function () { return instance.toggle(); });
      });
  });

  var container = {};
  function queue(name, func) {
      if (isUndefined(container[name])) {
          container[name] = [];
      }
      if (isUndefined(func)) {
          return container[name];
      }
      container[name].push(func);
  }
  /**
   * 从队列中移除第一个函数，并执行该函数
   * @param name 队列满
   */
  function dequeue(name) {
      if (isUndefined(container[name])) {
          return;
      }
      if (!container[name].length) {
          return;
      }
      var func = container[name].shift();
      func();
  }

  var DEFAULT_OPTIONS$6 = {
      history: true,
      overlay: true,
      modal: false,
      closeOnEsc: true,
      closeOnCancel: true,
      closeOnConfirm: true,
      destroyOnClosed: false,
  };
  /**
   * 当前显示的对话框实例
   */
  var currentInst = null;
  /**
   * 队列名
   */
  var queueName = '_mdui_dialog';
  /**
   * 窗口是否已锁定
   */
  var isLockScreen = false;
  /**
   * 遮罩层元素
   */
  var $overlay;
  var Dialog = function Dialog(selector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$6);
      /**
       * 当前 dialog 的状态
       */
      this.state = 'closed';
      /**
       * dialog 元素是否是动态添加的
       */
      this.append = false;
      this.$element = $(selector).first();
      // 如果对话框元素没有在当前文档中，则需要添加
      if (!contains(document.body, this.$element[0])) {
          this.append = true;
          $('body').append(this.$element);
      }
      extend(this.options, options);
      // 绑定取消按钮事件
      this.$element.find('[mdui-dialog-cancel]').each(function (_, cancel) {
          $(cancel).on('click', function () {
              this$1.triggerEvent('cancel');
              if (this$1.options.closeOnCancel) {
                  this$1.close();
              }
          });
      });
      // 绑定确认按钮事件
      this.$element.find('[mdui-dialog-confirm]').each(function (_, confirm) {
          $(confirm).on('click', function () {
              this$1.triggerEvent('confirm');
              if (this$1.options.closeOnConfirm) {
                  this$1.close();
              }
          });
      });
      // 绑定关闭按钮事件
      this.$element.find('[mdui-dialog-close]').each(function (_, close) {
          $(close).on('click', function () { return this$1.close(); });
      });
  };
  /**
   * 触发组件事件
   * @param name
   */
  Dialog.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'dialog', this.$element, this);
  };
  /**
   * 窗口宽度变化，或对话框内容变化时，调整对话框位置和对话框内的滚动条
   */
  Dialog.prototype.readjust = function readjust () {
      if (!currentInst) {
          return;
      }
      var $element = currentInst.$element;
      var $title = $element.children('.mdui-dialog-title');
      var $content = $element.children('.mdui-dialog-content');
      var $actions = $element.children('.mdui-dialog-actions');
      // 调整 dialog 的 top 和 height 值
      $element.height('');
      $content.height('');
      var elementHeight = $element.height();
      $element.css({
          top: ((($window.height() - elementHeight) / 2) + "px"),
          height: (elementHeight + "px"),
      });
      // 调整 mdui-dialog-content 的高度
      $content.innerHeight(elementHeight -
          ($title.innerHeight() || 0) -
          ($actions.innerHeight() || 0));
  };
  /**
   * hashchange 事件触发时关闭对话框
   */
  Dialog.prototype.hashchangeEvent = function hashchangeEvent () {
      if (window.location.hash.substring(1).indexOf('mdui-dialog') < 0) {
          currentInst.close(true);
      }
  };
  /**
   * 点击遮罩层关闭对话框
   * @param event
   */
  Dialog.prototype.overlayClick = function overlayClick (event) {
      if ($(event.target).hasClass('mdui-overlay') &&
          currentInst) {
          currentInst.close();
      }
  };
  /**
   * 动画结束回调
   */
  Dialog.prototype.transitionEnd = function transitionEnd () {
      if (this.$element.hasClass('mdui-dialog-open')) {
          this.state = 'opened';
          this.triggerEvent('opened');
      }
      else {
          this.state = 'closed';
          this.triggerEvent('closed');
          this.$element.hide();
          // 所有对话框都关闭，且当前没有打开的对话框时，解锁屏幕
          if (!queue(queueName).length && !currentInst && isLockScreen) {
              $.unlockScreen();
              isLockScreen = false;
          }
          $window.off('resize', $.throttle(this.readjust, 100));
          if (this.options.destroyOnClosed) {
              this.destroy();
          }
      }
  };
  /**
   * 打开指定对话框
   */
  Dialog.prototype.doOpen = function doOpen () {
          var this$1 = this;

      currentInst = this;
      if (!isLockScreen) {
          $.lockScreen();
          isLockScreen = true;
      }
      this.$element.show();
      this.readjust();
      $window.on('resize', $.throttle(this.readjust, 100));
      // 打开消息框
      this.state = 'opening';
      this.triggerEvent('open');
      this.$element
          .addClass('mdui-dialog-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
      // 不存在遮罩层元素时，添加遮罩层
      if (!$overlay) {
          $overlay = $.showOverlay(5100);
      }
      // 点击遮罩层时是否关闭对话框
      if (this.options.modal) {
          $overlay.off('click', this.overlayClick);
      }
      else {
          $overlay.on('click', this.overlayClick);
      }
      // 是否显示遮罩层，不显示时，把遮罩层背景透明
      $overlay.css('opacity', this.options.overlay ? '' : 0);
      if (this.options.history) {
          // 如果 hash 中原来就有 mdui-dialog，先删除，避免后退历史纪录后仍然有 mdui-dialog 导致无法关闭
          // 包括 mdui-dialog 和 &mdui-dialog 和 ?mdui-dialog
          var hash = window.location.hash.substring(1);
          if (hash.indexOf('mdui-dialog') > -1) {
              hash = hash.replace(/[&?]?mdui-dialog/g, '');
          }
          // 后退按钮关闭对话框
          if (hash) {
              window.location.hash = "" + hash + (hash.indexOf('?') > -1 ? '&' : '?') + "mdui-dialog";
          }
          else {
              window.location.hash = 'mdui-dialog';
          }
          $window.on('hashchange', this.hashchangeEvent);
      }
  };
  /**
   * 当前对话框是否为打开状态
   */
  Dialog.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 打开对话框
   */
  Dialog.prototype.open = function open () {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      // 如果当前有正在打开或已经打开的对话框,或队列不为空，则先加入队列，等旧对话框开始关闭时再打开
      if ((currentInst &&
          (currentInst.state === 'opening' || currentInst.state === 'opened')) ||
          queue(queueName).length) {
          queue(queueName, function () { return this$1.doOpen(); });
          return;
      }
      this.doOpen();
  };
  /**
   * 关闭对话框
   */
  Dialog.prototype.close = function close (historyBack) {
          var this$1 = this;
          if ( historyBack === void 0 ) historyBack = false;

      // historyBack 是否需要后退历史纪录，默认为 `false`。该参数仅内部使用
      // 为 `false` 时是通过 js 关闭，需要后退一个历史记录
      // 为 `true` 时是通过后退按钮关闭，不需要后退历史记录
      // setTimeout 的作用是：
      // 当同时关闭一个对话框，并打开另一个对话框时，使打开对话框的操作先执行，以使需要打开的对话框先加入队列
      setTimeout(function () {
          if (!this$1.isOpen()) {
              return;
          }
          currentInst = null;
          this$1.state = 'closing';
          this$1.triggerEvent('close');
          // 所有对话框都关闭，且当前没有打开的对话框时，隐藏遮罩
          if (!queue(queueName).length && $overlay) {
              $.hideOverlay();
              $overlay = null;
              // 若仍存在遮罩，恢复遮罩的 z-index
              $('.mdui-overlay').css('z-index', 2000);
          }
          this$1.$element
              .removeClass('mdui-dialog-open')
              .transitionEnd(function () { return this$1.transitionEnd(); });
          if (this$1.options.history && !queue(queueName).length) {
              if (!historyBack) {
                  window.history.back();
              }
              $window.off('hashchange', this$1.hashchangeEvent);
          }
          // 关闭旧对话框，打开新对话框。
          // 加一点延迟，仅仅为了视觉效果更好。不加延时也不影响功能
          setTimeout(function () {
              dequeue(queueName);
          }, 100);
      });
  };
  /**
   * 切换对话框打开/关闭状态
   */
  Dialog.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 获取对话框状态。共包含四种状态：`opening`、`opened`、`closing`、`closed`
   */
  Dialog.prototype.getState = function getState () {
      return this.state;
  };
  /**
   * 销毁对话框
   */
  Dialog.prototype.destroy = function destroy () {
      if (this.append) {
          this.$element.remove();
      }
      if (!queue(queueName).length && !currentInst) {
          if ($overlay) {
              $.hideOverlay();
              $overlay = null;
          }
          if (isLockScreen) {
              $.unlockScreen();
              isLockScreen = false;
          }
      }
  };
  /**
   * 对话框内容变化时，需要调用该方法来调整对话框位置和滚动条高度
   */
  Dialog.prototype.handleUpdate = function handleUpdate () {
      this.readjust();
  };

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

  var customAttr$7 = 'mdui-dialog';
  var dataName$1 = '_mdui_dialog';
  $(function () {
      $document.on('click', ("[" + customAttr$7 + "]"), function () {
          var options = parseOptions(this, customAttr$7);
          var selector = options.target;
          // @ts-ignore
          delete options.target;
          var $dialog = $(selector).first();
          var instance = $dialog.data(dataName$1);
          if (!instance) {
              instance = new mdui.Dialog($dialog, options);
              $dialog.data(dataName$1, instance);
          }
          instance.open();
      });
  });

  var DEFAULT_BUTTON = {
      text: '',
      bold: false,
      close: true,
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClick: function () { },
  };
  var DEFAULT_OPTIONS$7 = {
      title: '',
      content: '',
      buttons: [],
      stackedButtons: false,
      cssClass: '',
      history: true,
      overlay: true,
      modal: false,
      closeOnEsc: true,
      destroyOnClosed: true,
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onOpen: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onOpened: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClose: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClosed: function () { },
  };
  mdui.dialog = function (options) {
      var _a, _b;
      // 合并配置参数
      options = extend({}, DEFAULT_OPTIONS$7, options);
      each(options.buttons, function (i, button) {
          options.buttons[i] = extend({}, DEFAULT_BUTTON, button);
      });
      // 按钮的 HTML
      var buttonsHTML = '';
      if ((_a = options.buttons) === null || _a === void 0 ? void 0 : _a.length) {
          buttonsHTML = "<div class=\"mdui-dialog-actions" + (options.stackedButtons ? ' mdui-dialog-actions-stacked' : '') + "\">";
          each(options.buttons, function (_, 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 instance = new mdui.Dialog(HTML, {
          history: options.history,
          overlay: options.overlay,
          modal: options.modal,
          closeOnEsc: options.closeOnEsc,
          destroyOnClosed: options.destroyOnClosed,
      });
      // 绑定按钮事件
      if ((_b = options.buttons) === null || _b === void 0 ? void 0 : _b.length) {
          instance.$element
              .find('.mdui-dialog-actions .mdui-btn')
              .each(function (index, button) {
              $(button).on('click', function () {
                  options.buttons[index].onClick(instance);
                  if (options.buttons[index].close) {
                      instance.close();
                  }
              });
          });
      }
      // 绑定打开关闭事件
      instance.$element
          .on('open.mdui.dialog', function () {
          options.onOpen(instance);
      })
          .on('opened.mdui.dialog', function () {
          options.onOpened(instance);
      })
          .on('close.mdui.dialog', function () {
          options.onClose(instance);
      })
          .on('closed.mdui.dialog', function () {
          options.onClosed(instance);
      });
      instance.open();
      return instance;
  };

  var DEFAULT_OPTIONS$8 = {
      confirmText: 'ok',
      history: true,
      modal: false,
      closeOnEsc: true,
      closeOnConfirm: true,
  };
  mdui.alert = function (text, title, onConfirm, options) {
      if (isFunction(title)) {
          options = onConfirm;
          onConfirm = title;
          title = '';
      }
      if (isUndefined(onConfirm)) {
          // eslint-disable-next-line @typescript-eslint/no-empty-function
          onConfirm = function () { };
      }
      if (isUndefined(options)) {
          options = {};
      }
      options = extend({}, DEFAULT_OPTIONS$8, options);
      return mdui.dialog({
          title: title,
          content: text,
          buttons: [
              {
                  text: options.confirmText,
                  bold: false,
                  close: options.closeOnConfirm,
                  onClick: onConfirm,
              } ],
          cssClass: 'mdui-dialog-alert',
          history: options.history,
          modal: options.modal,
          closeOnEsc: options.closeOnEsc,
      });
  };

  var DEFAULT_OPTIONS$9 = {
      confirmText: 'ok',
      cancelText: 'cancel',
      history: true,
      modal: false,
      closeOnEsc: true,
      closeOnCancel: true,
      closeOnConfirm: true,
  };
  mdui.confirm = function (text, title, onConfirm, onCancel, options) {
      if (isFunction(title)) {
          options = onCancel;
          onCancel = onConfirm;
          onConfirm = title;
          title = '';
      }
      if (isUndefined(onConfirm)) {
          // eslint-disable-next-line @typescript-eslint/no-empty-function
          onConfirm = function () { };
      }
      if (isUndefined(onCancel)) {
          // eslint-disable-next-line @typescript-eslint/no-empty-function
          onCancel = function () { };
      }
      if (isUndefined(options)) {
          options = {};
      }
      options = extend({}, DEFAULT_OPTIONS$9, options);
      return mdui.dialog({
          title: title,
          content: text,
          buttons: [
              {
                  text: options.cancelText,
                  bold: false,
                  close: options.closeOnCancel,
                  onClick: onCancel,
              },
              {
                  text: options.confirmText,
                  bold: false,
                  close: options.closeOnConfirm,
                  onClick: onConfirm,
              } ],
          cssClass: 'mdui-dialog-confirm',
          history: options.history,
          modal: options.modal,
          closeOnEsc: options.closeOnEsc,
      });
  };

  var DEFAULT_OPTIONS$a = {
      confirmText: 'ok',
      cancelText: 'cancel',
      history: true,
      modal: false,
      closeOnEsc: true,
      closeOnCancel: true,
      closeOnConfirm: true,
      type: 'text',
      maxlength: 0,
      defaultValue: '',
      confirmOnEnter: false,
  };
  mdui.prompt = function (label, title, onConfirm, onCancel, options) {
      if (isFunction(title)) {
          options = onCancel;
          onCancel = onConfirm;
          onConfirm = title;
          title = '';
      }
      if (isUndefined(onConfirm)) {
          // eslint-disable-next-line @typescript-eslint/no-empty-function
          onConfirm = function () { };
      }
      if (isUndefined(onCancel)) {
          // eslint-disable-next-line @typescript-eslint/no-empty-function
          onCancel = function () { };
      }
      if (isUndefined(options)) {
          options = {};
      }
      options = extend({}, DEFAULT_OPTIONS$a, 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>';
      var onCancelClick = function (dialog) {
          var value = dialog.$element.find('.mdui-textfield-input').val();
          onCancel(value, dialog);
      };
      var onConfirmClick = function (dialog) {
          var value = dialog.$element.find('.mdui-textfield-input').val();
          onConfirm(value, dialog);
      };
      return mdui.dialog({
          title: title,
          content: content,
          buttons: [
              {
                  text: options.cancelText,
                  bold: false,
                  close: options.closeOnCancel,
                  onClick: onCancelClick,
              },
              {
                  text: options.confirmText,
                  bold: false,
                  close: options.closeOnConfirm,
                  onClick: onConfirmClick,
              } ],
          cssClass: 'mdui-dialog-prompt',
          history: options.history,
          modal: options.modal,
          closeOnEsc: options.closeOnEsc,
          onOpen: function (dialog) {
              // 初始化输入框
              var $input = dialog.$element.find('.mdui-textfield-input');
              mdui.updateTextFields($input);
              // 聚焦到输入框
              $input[0].focus();
              // 捕捉文本框回车键，在单行文本框的情况下触发回调
              if (options.type !== 'textarea' && options.confirmOnEnter === true) {
                  $input.on('keydown', function (event) {
                      if (event.keyCode === 13) {
                          var value = dialog.$element.find('.mdui-textfield-input').val();
                          onConfirm(value, dialog);
                          if (options.closeOnConfirm) {
                              dialog.close();
                          }
                          return false;
                      }
                      return;
                  });
              }
              // 如果是多行输入框，监听输入框的 input 事件，更新对话框高度
              if (options.type === 'textarea') {
                  $input.on('input', function () { return dialog.handleUpdate(); });
              }
              // 有字符数限制时，加载完文本框后 DOM 会变化，需要更新对话框高度
              if (options.maxlength) {
                  dialog.handleUpdate();
              }
          },
      });
  };

  var DEFAULT_OPTIONS$b = {
      position: 'auto',
      delay: 0,
      content: '',
  };
  var Tooltip = function Tooltip(selector, options) {
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$b);
      /**
       * 当前 tooltip 的状态
       */
      this.state = 'closed';
      /**
       * setTimeout 的返回值
       */
      this.timeoutId = null;
      this.$target = $(selector).first();
      extend(this.options, options);
      // 创建 Tooltip HTML
      this.$element = $(("<div class=\"mdui-tooltip\" id=\"" + ($.guid()) + "\">" + (this.options.content) + "</div>")).appendTo(document.body);
      // 绑定事件。元素处于 disabled 状态时无法触发鼠标事件，为了统一，把 touch 事件也禁用
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      this.$target
          .on('touchstart mouseenter', function (event) {
          if (that.isDisabled(this)) {
              return;
          }
          if (!isAllow(event)) {
              return;
          }
          register(event);
          that.open();
      })
          .on('touchend mouseleave', function (event) {
          if (that.isDisabled(this)) {
              return;
          }
          if (!isAllow(event)) {
              return;
          }
          that.close();
      })
          .on(unlockEvent, function (event) {
          if (that.isDisabled(this)) {
              return;
          }
          register(event);
      });
  };
  /**
   * 元素是否已禁用
   * @param element
   */
  Tooltip.prototype.isDisabled = function isDisabled (element) {
      return (element.disabled ||
          $(element).attr('disabled') !== undefined);
  };
  /**
   * 是否是桌面设备
   */
  Tooltip.prototype.isDesktop = function isDesktop () {
      return $window.width() > 1024;
  };
  /**
   * 设置 Tooltip 的位置
   */
  Tooltip.prototype.setPosition = function setPosition () {
      var marginLeft;
      var marginTop;
      // 触发的元素
      var targetProps = this.$target[0].getBoundingClientRect();
      // 触发的元素和 Tooltip 之间的距离
      var targetMargin = this.isDesktop() ? 14 : 24;
      // Tooltip 的宽度和高度
      var tooltipWidth = this.$element[0].offsetWidth;
      var tooltipHeight = this.$element[0].offsetHeight;
      // Tooltip 的方向
      var position = this.options.position;
      // 自动判断位置，加 2px，使 Tooltip 距离窗口边框至少有 2px 的间距
      if (position === 'auto') {
          if (targetProps.top +
              targetProps.height +
              targetMargin +
              tooltipHeight +
              2 <
              $window.height()) {
              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 <
              $window.width() - targetProps.left) {
              position = 'right';
          }
          else {
              position = 'bottom';
          }
      }
      // 设置位置
      switch (position) {
          case 'bottom':
              marginLeft = -1 * (tooltipWidth / 2);
              marginTop = targetProps.height / 2 + targetMargin;
              this.$element.transformOrigin('top center');
              break;
          case 'top':
              marginLeft = -1 * (tooltipWidth / 2);
              marginTop =
                  -1 * (tooltipHeight + targetProps.height / 2 + targetMargin);
              this.$element.transformOrigin('bottom center');
              break;
          case 'left':
              marginLeft = -1 * (tooltipWidth + targetProps.width / 2 + targetMargin);
              marginTop = -1 * (tooltipHeight / 2);
              this.$element.transformOrigin('center right');
              break;
          case 'right':
              marginLeft = targetProps.width / 2 + targetMargin;
              marginTop = -1 * (tooltipHeight / 2);
              this.$element.transformOrigin('center left');
              break;
      }
      var targetOffset = this.$target.offset();
      this.$element.css({
          top: ((targetOffset.top + targetProps.height / 2) + "px"),
          left: ((targetOffset.left + targetProps.width / 2) + "px"),
          'margin-left': (marginLeft + "px"),
          'margin-top': (marginTop + "px"),
      });
  };
  /**
   * 触发组件事件
   * @param name
   */
  Tooltip.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'tooltip', this.$target, this);
  };
  /**
   * 动画结束回调
   */
  Tooltip.prototype.transitionEnd = function transitionEnd () {
      if (this.$element.hasClass('mdui-tooltip-open')) {
          this.state = 'opened';
          this.triggerEvent('opened');
      }
      else {
          this.state = 'closed';
          this.triggerEvent('closed');
      }
  };
  /**
   * 当前 tooltip 是否为打开状态
   */
  Tooltip.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 执行打开 tooltip
   */
  Tooltip.prototype.doOpen = function doOpen () {
          var this$1 = this;

      this.state = 'opening';
      this.triggerEvent('open');
      this.$element
          .addClass('mdui-tooltip-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 打开 Tooltip
   * @param options 允许每次打开时设置不同的参数
   */
  Tooltip.prototype.open = function open (options) {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      var oldOptions = extend({}, this.options);
      if (options) {
          extend(this.options, options);
      }
      // tooltip 的内容有更新
      if (oldOptions.content !== this.options.content) {
          this.$element.html(this.options.content);
      }
      this.setPosition();
      if (this.options.delay) {
          this.timeoutId = setTimeout(function () { return this$1.doOpen(); }, this.options.delay);
      }
      else {
          this.timeoutId = null;
          this.doOpen();
      }
  };
  /**
   * 关闭 Tooltip
   */
  Tooltip.prototype.close = function close () {
          var this$1 = this;

      if (this.timeoutId) {
          clearTimeout(this.timeoutId);
          this.timeoutId = null;
      }
      if (!this.isOpen()) {
          return;
      }
      this.state = 'closing';
      this.triggerEvent('close');
      this.$element
          .removeClass('mdui-tooltip-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 切换 Tooltip 的打开状态
   */
  Tooltip.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 获取 Tooltip 状态。共包含四种状态：`opening`、`opened`、`closing`、`closed`
   */
  Tooltip.prototype.getState = function getState () {
      return this.state;
  };
  mdui.Tooltip = Tooltip;

  var customAttr$8 = 'mdui-tooltip';
  var dataName$2 = '_mdui_tooltip';
  $(function () {
      // mouseenter 不能冒泡，所以这里用 mouseover 代替
      $document.on('touchstart mouseover', ("[" + customAttr$8 + "]"), function () {
          var $target = $(this);
          var instance = $target.data(dataName$2);
          if (!instance) {
              instance = new mdui.Tooltip(this, parseOptions(this, customAttr$8));
              $target.data(dataName$2, instance);
          }
      });
  });

  var DEFAULT_OPTIONS$c = {
      message: '',
      timeout: 4000,
      position: 'bottom',
      buttonText: '',
      buttonColor: '',
      closeOnButtonClick: true,
      closeOnOutsideClick: true,
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClick: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onButtonClick: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onOpen: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onOpened: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClose: function () { },
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      onClosed: function () { },
  };
  /**
   * 当前打开着的 Snackbar
   */
  var currentInst$1 = null;
  /**
   * 队列名
   */
  var queueName$1 = '_mdui_snackbar';
  var Snackbar = function Snackbar(options) {
      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$c);
      /**
       * 当前 Snackbar 的状态
       */
      this.state = 'closed';
      /**
       * setTimeout 的 ID
       */
      this.timeoutId = null;
      extend(this.options, options);
      // 按钮颜色
      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
      this.$element = $('<div class="mdui-snackbar">' +
          "<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>').appendTo(document.body);
      // 设置位置
      this.setPosition('close');
      this.$element.reflow().addClass(("mdui-snackbar-" + (this.options.position)));
  };
  /**
   * 点击 Snackbar 外面的区域关闭
   * @param event
   */
  Snackbar.prototype.closeOnOutsideClick = function closeOnOutsideClick (event) {
      var $target = $(event.target);
      if (!$target.hasClass('mdui-snackbar') &&
          !$target.parents('.mdui-snackbar').length) {
          currentInst$1.close();
      }
  };
  /**
   * 设置 Snackbar 的位置
   * @param state
   */
  Snackbar.prototype.setPosition = function setPosition (state) {
      var snackbarHeight = this.$element[0].clientHeight;
      var position = this.options.position;
      var translateX;
      var translateY;
      // translateX
      if (position === 'bottom' || position === 'top') {
          translateX = '-50%';
      }
      else {
          translateX = '0';
      }
      // translateY
      if (state === 'open') {
          translateY = '0';
      }
      else {
          if (position === 'bottom') {
              translateY = snackbarHeight;
          }
          if (position === 'top') {
              translateY = -snackbarHeight;
          }
          if (position === 'left-top' || position === 'right-top') {
              translateY = -snackbarHeight - 24;
          }
          if (position === 'left-bottom' || position === 'right-bottom') {
              translateY = snackbarHeight + 24;
          }
      }
      this.$element.transform(("translate(" + translateX + "," + translateY + "px"));
  };
  /**
   * 打开 Snackbar
   */
  Snackbar.prototype.open = function open () {
          var this$1 = this;

      if (this.state === 'opening' || this.state === 'opened') {
          return;
      }
      // 如果当前有正在显示的 Snackbar，则先加入队列，等旧 Snackbar 关闭后再打开
      if (currentInst$1) {
          queue(queueName$1, function () { return this$1.open(); });
          return;
      }
      currentInst$1 = this;
      // 开始打开
      this.state = 'opening';
      this.options.onOpen(this);
      this.setPosition('open');
      this.$element.transitionEnd(function () {
          if (this$1.state !== 'opening') {
              return;
          }
          this$1.state = 'opened';
          this$1.options.onOpened(this$1);
          // 有按钮时绑定事件
          if (this$1.options.buttonText) {
              this$1.$element.find('.mdui-snackbar-action').on('click', function () {
                  this$1.options.onButtonClick(this$1);
                  if (this$1.options.closeOnButtonClick) {
                      this$1.close();
                  }
              });
          }
          // 点击 snackbar 的事件
          this$1.$element.on('click', function (event) {
              if (!$(event.target).hasClass('mdui-snackbar-action')) {
                  this$1.options.onClick(this$1);
              }
          });
          // 点击 Snackbar 外面的区域关闭
          if (this$1.options.closeOnOutsideClick) {
              $document.on(startEvent, this$1.closeOnOutsideClick);
          }
          // 超时后自动关闭
          if (this$1.options.timeout) {
              this$1.timeoutId = setTimeout(function () { return this$1.close(); }, this$1.options.timeout);
          }
      });
  };
  /**
   * 关闭 Snackbar
   */
  Snackbar.prototype.close = function close () {
          var this$1 = this;

      if (this.state === 'closing' || this.state === 'closed') {
          return;
      }
      if (this.timeoutId) {
          clearTimeout(this.timeoutId);
      }
      if (this.options.closeOnOutsideClick) {
          $document.off(startEvent, this.closeOnOutsideClick);
      }
      this.state = 'closing';
      this.options.onClose(this);
      this.setPosition('close');
      this.$element.transitionEnd(function () {
          if (this$1.state !== 'closing') {
              return;
          }
          currentInst$1 = null;
          this$1.state = 'closed';
          this$1.options.onClosed(this$1);
          this$1.$element.remove();
          dequeue(queueName$1);
      });
  };
  mdui.snackbar = function (message, options) {
      if ( options === void 0 ) options = {};

      if (isString(message)) {
          options.message = message;
      }
      else {
          options = message;
      }
      var instance = new Snackbar(options);
      instance.open();
      return instance;
  };

  $(function () {
      // 切换导航项
      $document.on('click', '.mdui-bottom-nav>a', function () {
          var $item = $(this);
          var $bottomNav = $item.parent();
          $bottomNav.children('a').each(function (index, item) {
              var isThis = $item.is(item);
              if (isThis) {
                  componentEvent('change', 'bottomNav', $bottomNav[0], undefined, {
                      index: index,
                  });
              }
              isThis
                  ? $(item).addClass('mdui-bottom-nav-active')
                  : $(item).removeClass('mdui-bottom-nav-active');
          });
      });
      // 滚动时隐藏 mdui-bottom-nav-scroll-hide
      mdui.mutation('.mdui-bottom-nav-scroll-hide', function () {
          new mdui.Headroom(this, {
              pinnedClass: 'mdui-headroom-pinned-down',
              unpinnedClass: 'mdui-headroom-unpinned-down',
          });
      });
  });

  /**
   * layer 的 HTML 结构
   * @param index
   */
  function layerHTML(index) {
      if ( index === void 0 ) index = false;

      return ("<div class=\"mdui-spinner-layer " + (index ? ("mdui-spinner-layer-" + index) : '') + "\">" +
          '<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
   */
  function fillHTML(spinner) {
      var $spinner = $(spinner);
      var layer = $spinner.hasClass('mdui-spinner-colorful')
          ? layerHTML(1) + layerHTML(2) + layerHTML(3) + layerHTML(4)
          : layerHTML();
      $spinner.html(layer);
  }
  $(function () {
      // 页面加载完后自动填充 HTML 结构
      mdui.mutation('.mdui-spinner', function () {
          fillHTML(this);
      });
  });
  mdui.updateSpinners = function (selector) {
      var $elements = isUndefined(selector) ? $('.mdui-spinner') : $(selector);
      $elements.each(function () {
          fillHTML(this);
      });
  };

  var DEFAULT_OPTIONS$d = {
      position: 'auto',
      align: 'auto',
      gutter: 16,
      fixed: false,
      covered: 'auto',
      subMenuTrigger: 'hover',
      subMenuDelay: 200,
  };
  var Menu = function Menu(anchorSelector, menuSelector, options) {
      var this$1 = this;
      if ( options === void 0 ) options = {};

      /**
       * 配置参数
       */
      this.options = extend({}, DEFAULT_OPTIONS$d);
      /**
       * 当前菜单状态
       */
      this.state = 'closed';
      this.$anchor = $(anchorSelector).first();
      this.$element = $(menuSelector).first();
      // 触发菜单的元素 和 菜单必须是同级的元素，否则菜单可能不能定位
      if (!this.$anchor.parent().is(this.$element.parent())) {
          throw new Error('anchorSelector and menuSelector must be siblings');
      }
      extend(this.options, options);
      // 是否是级联菜单
      this.isCascade = this.$element.hasClass('mdui-menu-cascade');
      // covered 参数处理
      this.isCovered =
          this.options.covered === 'auto' ? !this.isCascade : this.options.covered;
      // 点击触发菜单切换
      this.$anchor.on('click', function () { return this$1.toggle(); });
      // 点击菜单外面区域关闭菜单
      $document.on('click touchstart', function (event) {
          var $target = $(event.target);
          if (this$1.isOpen() &&
              !$target.is(this$1.$element) &&
              !contains(this$1.$element[0], $target[0]) &&
              !$target.is(this$1.$anchor) &&
              !contains(this$1.$anchor[0], $target[0])) {
              this$1.close();
          }
      });
      // 点击不含子菜单的菜单条目关闭菜单
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      $document.on('click', '.mdui-menu-item', function () {
          var $item = $(this);
          if (!$item.find('.mdui-menu').length &&
              $item.attr('disabled') === undefined) {
              that.close();
          }
      });
      // 绑定点击或鼠标移入含子菜单的条目的事件
      this.bindSubMenuEvent();
      // 窗口大小变化时，重新调整菜单位置
      $window.on('resize', $.throttle(function () { return this$1.readjust(); }, 100));
  };
  /**
   * 是否为打开状态
   */
  Menu.prototype.isOpen = function isOpen () {
      return this.state === 'opening' || this.state === 'opened';
  };
  /**
   * 触发组件事件
   * @param name
   */
  Menu.prototype.triggerEvent = function triggerEvent (name) {
      componentEvent(name, 'menu', this.$element, this);
  };
  /**
   * 调整主菜单位置
   */
  Menu.prototype.readjust = function readjust () {
      var menuLeft;
      var menuTop;
      // 菜单位置和方向
      var position;
      var align;
      // window 窗口的宽度和高度
      var windowHeight = $window.height();
      var windowWidth = $window.width();
      // 配置参数
      var gutter = this.options.gutter;
      var isCovered = this.isCovered;
      var isFixed = this.options.fixed;
      // 动画方向参数
      var transformOriginX;
      var transformOriginY;
      // 菜单的原始宽度和高度
      var menuWidth = this.$element.width();
      var menuHeight = this.$element.height();
      // 触发菜单的元素在窗口中的位置
      var anchorRect = this.$anchor[0].getBoundingClientRect();
      var anchorTop = anchorRect.top;
      var anchorLeft = anchorRect.left;
      var anchorHeight = anchorRect.height;
      var anchorWidth = anchorRect.width;
      var anchorBottom = windowHeight - anchorTop - anchorHeight;
      var anchorRight = windowWidth - anchorLeft - anchorWidth;
      // 触发元素相对其拥有定位属性的父元素的位置
      var anchorOffsetTop = this.$anchor[0].offsetTop;
      var anchorOffsetLeft = this.$anchor[0].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.isCascade) {
              if (menuHeight + gutter * 2 > windowHeight) {
                  menuHeightTemp = windowHeight - gutter * 2;
                  this.$element.height(menuHeightTemp);
              }
          }
          menuTop =
              (windowHeight - menuHeightTemp) / 2 +
                  (isFixed ? 0 : anchorOffsetTop - anchorTop);
      }
      this.$element.css('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.$element.width(menuWidthTemp);
          }
          menuLeft =
              (windowWidth - menuWidthTemp) / 2 +
                  (isFixed ? 0 : anchorOffsetLeft - anchorLeft);
      }
      this.$element.css('left', (menuLeft + "px"));
      // 设置菜单动画方向
      this.$element.transformOrigin((transformOriginX + " " + transformOriginY));
  };
  /**
   * 调整子菜单的位置
   * @param $submenu
   */
  Menu.prototype.readjustSubmenu = function readjustSubmenu ($submenu) {
      var $item = $submenu.parent('.mdui-menu-item');
      var submenuTop;
      var submenuLeft;
      // 子菜单位置和方向
      var position;
      var align;
      // window 窗口的宽度和高度
      var windowHeight = $window.height();
      var windowWidth = $window.width();
      // 动画方向参数
      var transformOriginX;
      var transformOriginY;
      // 子菜单的原始宽度和高度
      var submenuWidth = $submenu.width();
      var submenuHeight = $submenu.height();
      // 触发子菜单的菜单项的宽度高度
      var itemRect = $item[0].getBoundingClientRect();
      var itemWidth = itemRect.width;
      var itemHeight = itemRect.height;
      var itemLeft = itemRect.left;
      var itemTop = itemRect.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.css('top', (submenuTop + "px"));
      // 设置菜单对齐方式
      if (align === 'left') {
          transformOriginX = '0';
          submenuLeft = itemWidth;
      }
      else if (align === 'right') {
          transformOriginX = '100%';
          submenuLeft = -submenuWidth;
      }
      $submenu.css('left', (submenuLeft + "px"));
      // 设置菜单动画方向
      $submenu.transformOrigin((transformOriginX + " " + transformOriginY));
  };
  /**
   * 打开子菜单
   * @param $submenu
   */
  Menu.prototype.openSubMenu = function openSubMenu ($submenu) {
      this.readjustSubmenu($submenu);
      $submenu
          .addClass('mdui-menu-open')
          .parent('.mdui-menu-item')
          .addClass('mdui-menu-item-active');
  };
  /**
   * 关闭子菜单，及其嵌套的子菜单
   * @param $submenu
   */
  Menu.prototype.closeSubMenu = function closeSubMenu ($submenu) {
      // 关闭子菜单
      $submenu
          .removeClass('mdui-menu-open')
          .addClass('mdui-menu-closing')
          .transitionEnd(function () { return $submenu.removeClass('mdui-menu-closing'); })
          // 移除激活状态的样式
          .parent('.mdui-menu-item')
          .removeClass('mdui-menu-item-active');
      // 循环关闭嵌套的子菜单
      $submenu.find('.mdui-menu').each(function (_, menu) {
          var $subSubmenu = $(menu);
          $subSubmenu
              .removeClass('mdui-menu-open')
              .addClass('mdui-menu-closing')
              .transitionEnd(function () { return $subSubmenu.removeClass('mdui-menu-closing'); })
              .parent('.mdui-menu-item')
              .removeClass('mdui-menu-item-active');
      });
  };
  /**
   * 切换子菜单状态
   * @param $submenu
   */
  Menu.prototype.toggleSubMenu = function toggleSubMenu ($submenu) {
      $submenu.hasClass('mdui-menu-open')
          ? this.closeSubMenu($submenu)
          : this.openSubMenu($submenu);
  };
  /**
   * 绑定子菜单事件
   */
  Menu.prototype.bindSubMenuEvent = function bindSubMenuEvent () {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      var that = this;
      // 点击打开子菜单
      this.$element.on('click', '.mdui-menu-item', function (event) {
          var $item = $(this);
          var $target = $(event.target);
          // 禁用状态菜单不操作
          if ($item.attr('disabled') !== undefined) {
              return;
          }
          // 没有点击在子菜单的菜单项上时，不操作（点在了子菜单的空白区域、或分隔线上）
          if ($target.is('.mdui-menu') || $target.is('.mdui-divider')) {
              return;
          }
          // 阻止冒泡，点击菜单项时只在最后一级的 mdui-menu-item 上生效，不向上冒泡
          if (!$target.parents('.mdui-menu-item').first().is($item)) {
              return;
          }
          // 当前菜单的子菜单
          var $submenu = $item.children('.mdui-menu');
          // 先关闭除当前子菜单外的所有同级子菜单
          $item
              .parent('.mdui-menu')
              .children('.mdui-menu-item')
              .each(function (_, item) {
              var $tmpSubmenu = $(item).children('.mdui-menu');
              if ($tmpSubmenu.length &&
                  (!$submenu.length || !$tmpSubmenu.is($submenu))) {
                  that.closeSubMenu($tmpSubmenu);
              }
          });
          // 切换当前子菜单
          if ($submenu.length) {
              that.toggleSubMenu($submenu);
          }
      });
      if (this.options.subMenuTrigger === 'hover') {
          // 临时存储 setTimeout 对象
          var timeout = null;
          var timeoutOpen = null;
          this.$element.on('mouseover mouseout', '.mdui-menu-item', function (event) {
              var $item = $(this);
              var eventType = event.type;
              var $relatedTarget = $(event.relatedTarget);
              // 禁用状态的菜单不操作
              if ($item.attr('disabled') !== undefined) {
                  return;
              }
              // 用 mouseover 模拟 mouseenter
              if (eventType === 'mouseover') {
                  if (!$item.is($relatedTarget) &&
                      contains($item[0], $relatedTarget[0])) {
                      return;
                  }
              }
              // 用 mouseout 模拟 mouseleave
              else if (eventType === 'mouseout') {
                  if ($item.is($relatedTarget) ||
                      contains($item[0], $relatedTarget[0])) {
                      return;
                  }
              }
              // 当前菜单项下的子菜单，未必存在
              var $submenu = $item.children('.mdui-menu');
              // 鼠标移入菜单项时，显示菜单项下的子菜单
              if (eventType === 'mouseover') {
                  if ($submenu.length) {
                      // 当前子菜单准备打开时，如果当前子菜单正准备着关闭，不用再关闭了
                      var tmpClose = $submenu.data('timeoutClose.mdui.menu');
                      if (tmpClose) {
                          clearTimeout(tmpClose);
                      }
                      // 如果当前子菜单已经打开，不操作
                      if ($submenu.hasClass('mdui-menu-open')) {
                          return;
                      }
                      // 当前子菜单准备打开时，其他准备打开的子菜单不用再打开了
                      clearTimeout(timeoutOpen);
                      // 准备打开当前子菜单
                      timeout = timeoutOpen = setTimeout(function () { return that.openSubMenu($submenu); }, that.options.subMenuDelay);
                      $submenu.data('timeoutOpen.mdui.menu', timeout);
                  }
              }
              // 鼠标移出菜单项时，关闭菜单项下的子菜单
              else if (eventType === 'mouseout') {
                  if ($submenu.length) {
                      // 鼠标移出菜单项时，如果当前菜单项下的子菜单正准备打开，不用再打开了
                      var tmpOpen = $submenu.data('timeoutOpen.mdui.menu');
                      if (tmpOpen) {
                          clearTimeout(tmpOpen);
                      }
                      // 准备关闭当前子菜单
                      timeout = setTimeout(function () { return that.closeSubMenu($submenu); }, that.options.subMenuDelay);
                      $submenu.data('timeoutClose.mdui.menu', timeout);
                  }
              }
          });
      }
  };
  /**
   * 动画结束回调
   */
  Menu.prototype.transitionEnd = function transitionEnd () {
      this.$element.removeClass('mdui-menu-closing');
      if (this.state === 'opening') {
          this.state = 'opened';
          this.triggerEvent('opened');
      }
      if (this.state === 'closing') {
          this.state = 'closed';
          this.triggerEvent('closed');
          // 关闭后，恢复菜单样式到默认状态，并恢复 fixed 定位
          this.$element.css({
              top: '',
              left: '',
              width: '',
              position: 'fixed',
          });
      }
  };
  /**
   * 切换菜单状态
   */
  Menu.prototype.toggle = function toggle () {
      this.isOpen() ? this.close() : this.open();
  };
  /**
   * 打开菜单
   */
  Menu.prototype.open = function open () {
          var this$1 = this;

      if (this.isOpen()) {
          return;
      }
      this.state = 'opening';
      this.triggerEvent('open');
      this.readjust();
      this.$element
          // 菜单隐藏状态使用使用 fixed 定位。
          .css('position', this.options.fixed ? 'fixed' : 'absolute')
          .addClass('mdui-menu-open')
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  /**
   * 关闭菜单
   */
  Menu.prototype.close = function close () {
          var this$1 = this;

      if (!this.isOpen()) {
          return;
      }
      this.state = 'closing';
      this.triggerEvent('close');
      // 菜单开始关闭时，关闭所有子菜单
      this.$element.find('.mdui-menu').each(function (_, submenu) {
          this$1.closeSubMenu($(submenu));
      });
      this.$element
          .removeClass('mdui-menu-open')
          .addClass('mdui-menu-closing')
          .transitionEnd(function () { return this$1.transitionEnd(); });
  };
  mdui.Menu = Menu;

  var customAttr$9 = 'mdui-menu';
  var dataName$3 = '_mdui_menu';
  $(function () {
      $document.on('click', ("[" + customAttr$9 + "]"), function () {
          var $this = $(this);
          var instance = $this.data(dataName$3);
          if (!instance) {
              var options = parseOptions(this, customAttr$9);
              var menuSelector = options.target;
              // @ts-ignore
              delete options.target;
              instance = new mdui.Menu($this, menuSelector, options);
              $this.data(dataName$3, instance);
              instance.toggle();
          }
      });
  });

  return mdui;

})));
//# sourceMappingURL=mdui.js.map
