/*!
 * Picker.js v1.2.1
 * https://fengyuanchen.github.io/pickerjs
 *
 * Copyright 2016-present Chen Fengyuan
 * Released under the MIT license
 *
 * Date: 2019-02-18T13:08:12.801Z
 */

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.Picker = factory());
}(this, function () { 'use strict';

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

    return _typeof(obj);
  }

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

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

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
  }

  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) {
      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

      return arr2;
    }
  }

  function _iterableToArray(iter) {
    if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
  }

  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance");
  }

  var DEFAULTS = {
    // Define the container for putting the picker.
    container: null,
    // Indicate whether show the prev and next arrow controls on each column.
    controls: false,
    // The initial date. If not present, use the current date.
    date: null,
    // The date string format, also as the sorting order for columns.
    format: 'YYYY-MM-DD HH:mm',
    // Indicate whether show the column headers.
    headers: false,
    // Define the increment for each date / time part.
    increment: 1,
    // Enable inline mode.
    inline: false,
    // Define the language. (An ISO language code).
    language: '',
    // Months' name.
    months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    // Shorter months' name.
    monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    // Define the number of rows for showing.
    rows: 5,
    // Define the text of the picker.
    text: {
      title: 'Pick a date and time',
      cancel: 'Cancel',
      confirm: 'OK',
      year: 'Year',
      month: 'Month',
      day: 'Day',
      hour: 'Hour',
      minute: 'Minute',
      second: 'Second',
      millisecond: 'Millisecond'
    },
    // Translate date / time text.
    translate: function translate(type, text) {
      return text;
    },
    // Shortcuts of custom events.
    show: null,
    shown: null,
    hide: null,
    hidden: null,
    pick: null
  };

  var TEMPLATE = '<div class="picker" data-picker-action="hide" touch-action="none" tabindex="-1" role="dialog">' + '<div class="picker-dialog" role="document">' + '<div class="picker-header">' + '<h4 class="picker-title">{{ title }}</h4>' + '<button type="button" class="picker-close" data-picker-action="hide" aria-label="Close">&times;</button>' + '</div>' + '<div class="picker-body">' + '<div class="picker-grid"></div>' + '</div>' + '<div class="picker-footer">' + '<button type="button" class="picker-cancel" data-picker-action="hide">{{ cancel }}</button>' + '<button type="button" class="picker-confirm" data-picker-action="pick">{{ confirm }}</button>' + '</div>' + '</div>' + '</div>';

  var IS_BROWSER = typeof window !== 'undefined';
  var WINDOW = IS_BROWSER ? window : {};
  var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
  var NAMESPACE = 'picker';
  var LANGUAGES = {}; // Actions

  var ACTION_HIDE = 'hide';
  var ACTION_NEXT = 'next';
  var ACTION_PICK = 'pick';
  var ACTION_PREV = 'prev'; // Classes

  var CLASS_OPEN = "".concat(NAMESPACE, "-open");
  var CLASS_OPENED = "".concat(NAMESPACE, "-opened");
  var CLASS_PICKED = "".concat(NAMESPACE, "-picked"); // Data keys
  // Add namespace to avoid to conflict to some other libraries.

  var DATA_ACTION = "".concat(NAMESPACE, "Action");
  var DATA_TOKEN = 'token';
  var DATA_TYPE = 'type';
  var DATA_NAME = 'name';
  var DATA_VALUE = 'value'; // Events

  var EVENT_CLICK = 'click';
  var EVENT_FOCUS = 'focus';
  var EVENT_HIDDEN = 'hidden';
  var EVENT_HIDE = 'hide';
  var EVENT_KEY_DOWN = 'keydown';
  var EVENT_PICK = 'pick';
  var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
  var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
  var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
  var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
  var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
  var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
  var EVENT_SHOW = 'show';
  var EVENT_SHOWN = 'shown';
  var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';

  var _Object$prototype = Object.prototype,
      hasOwnProperty = _Object$prototype.hasOwnProperty,
      toString = _Object$prototype.toString;
  /**
   * Detect the type of the given value.
   * @param {*} value - The value to detect.
   * @returns {string} Returns the type.
   */

  function typeOf(value) {
    return toString.call(value).slice(8, -1).toLowerCase();
  }
  /**
   * Check if the given value is a string.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a string, else `false`.
   */

  function isString(value) {
    return typeof value === 'string';
  }
  /**
   * Check if the given value is finite.
   */

  var isFinite = Number.isFinite || WINDOW.isFinite;
  /**
   * Check if the given value is not a number.
   */

  var isNaN = Number.isNaN || WINDOW.isNaN;
  /**
   * Check if the given value is a number.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a number, else `false`.
   */

  function isNumber(value) {
    return typeof value === 'number' && !isNaN(value);
  }
  /**
   * Check if the given value is an object.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is an object, else `false`.
   */

  function isObject(value) {
    return _typeof(value) === 'object' && value !== null;
  }
  /**
   * Check if the given value is a plain object.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
   */

  function isPlainObject(value) {
    if (!isObject(value)) {
      return false;
    }

    try {
      var _constructor = value.constructor;
      var prototype = _constructor.prototype;
      return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
    } catch (error) {
      return false;
    }
  }
  /**
   * Check if the given value is a function.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a function, else `false`.
   */

  function isFunction(value) {
    return typeof value === 'function';
  }
  /**
   * Check if the given value is a date.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a date, else `false`.
   */

  function isDate(value) {
    return typeOf(value) === 'date';
  }
  /**
   * Check if the given value is a valid date.
   * @param {*} value - The value to check.
   * @returns {boolean} Returns `true` if the given value is a valid date, else `false`.
   */

  function isValidDate(value) {
    return isDate(value) && value.toString() !== 'Invalid Date';
  }
  /**
   * Iterate the given data.
   * @param {*} data - The data to iterate.
   * @param {Function} callback - The process function for each element.
   * @returns {*} The original data.
   */

  function forEach(data, callback) {
    if (data && isFunction(callback)) {
      if (Array.isArray(data) || isNumber(data.length)
      /* array-like */
      ) {
          var length = data.length;
          var i;

          for (i = 0; i < length; i += 1) {
            if (callback.call(data, data[i], i, data) === false) {
              break;
            }
          }
        } else if (isObject(data)) {
        Object.keys(data).forEach(function (key) {
          callback.call(data, data[key], key, data);
        });
      }
    }

    return data;
  }
  /**
   * Recursively assigns own enumerable properties of source objects to the target object.
   * @param {Object} target - The target object.
   * @param {Object[]} sources - The source objects.
   * @returns {Object} The target object.
   */

  function deepAssign(target) {
    for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      sources[_key - 1] = arguments[_key];
    }

    if (isObject(target) && sources.length > 0) {
      sources.forEach(function (source) {
        if (isObject(source)) {
          Object.keys(source).forEach(function (key) {
            if (isPlainObject(target[key]) && isPlainObject(source[key])) {
              target[key] = deepAssign({}, target[key], source[key]);
            } else {
              target[key] = source[key];
            }
          });
        }
      });
    }

    return target;
  }
  /**
   * Add classes to the given element.
   * @param {Element} element - The target element.
   * @param {string} value - The classes to be added.
   */

  function addClass(element, value) {
    if (!value) {
      return;
    }

    if (isNumber(element.length)) {
      forEach(element, function (elem) {
        addClass(elem, value);
      });
      return;
    }

    if (element.classList) {
      element.classList.add(value);
      return;
    }

    var className = element.className.trim();

    if (!className) {
      element.className = value;
    } else if (className.indexOf(value) < 0) {
      element.className = "".concat(className, " ").concat(value);
    }
  }
  /**
   * Remove classes from the given element.
   * @param {Element} element - The target element.
   * @param {string} value - The classes to be removed.
   */

  function removeClass(element, value) {
    if (!value) {
      return;
    }

    if (isNumber(element.length)) {
      forEach(element, function (elem) {
        removeClass(elem, value);
      });
      return;
    }

    if (element.classList) {
      element.classList.remove(value);
      return;
    }

    if (element.className.indexOf(value) >= 0) {
      element.className = element.className.replace(value, '');
    }
  }
  var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
  /**
   * Transform the given string from camelCase to kebab-case
   * @param {string} value - The value to transform.
   * @returns {string} The transformed value.
   */

  function hyphenate(value) {
    return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
  }
  /**
   * Get data from the given element.
   * @param {Element} element - The target element.
   * @param {string} name - The data key to get.
   * @returns {string} The data value.
   */

  function getData(element, name) {
    if (isObject(element[name])) {
      return element[name];
    }

    if (element.dataset) {
      return element.dataset[name];
    }

    return element.getAttribute("data-".concat(hyphenate(name)));
  }
  /**
   * Set data to the given element.
   * @param {Element} element - The target element.
   * @param {string} name - The data key to set.
   * @param {string} data - The data value.
   */

  function setData(element, name, data) {
    if (isObject(data)) {
      element[name] = data;
    } else if (element.dataset) {
      element.dataset[name] = data;
    } else {
      element.setAttribute("data-".concat(hyphenate(name)), data);
    }
  }
  /**
   * Remove data from the given element.
   * @param {Element} element - The target element.
   * @param {string} name - The data key to remove.
   */

  function removeData(element, name) {
    if (isObject(element[name])) {
      try {
        delete element[name];
      } catch (error) {
        element[name] = undefined;
      }
    } else if (element.dataset) {
      // #128 Safari not allows to delete dataset property
      try {
        delete element.dataset[name];
      } catch (error) {
        element.dataset[name] = undefined;
      }
    } else {
      element.removeAttribute("data-".concat(hyphenate(name)));
    }
  }
  var REGEXP_SPACES = /\s\s*/;

  var onceSupported = function () {
    var supported = false;

    if (IS_BROWSER) {
      var once = false;

      var listener = function listener() {};

      var options = Object.defineProperty({}, 'once', {
        get: function get() {
          supported = true;
          return once;
        },

        /**
         * This setter can fix a `TypeError` in strict mode
         * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
         * @param {boolean} value - The value to set
         */
        set: function set(value) {
          once = value;
        }
      });
      WINDOW.addEventListener('test', listener, options);
      WINDOW.removeEventListener('test', listener, options);
    }

    return supported;
  }();
  /**
   * Remove event listener from the target element.
   * @param {Element} element - The event target.
   * @param {string} type - The event type(s).
   * @param {Function} listener - The event listener.
   * @param {Object} options - The event options.
   */


  function removeListener(element, type, listener) {
    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    var handler = listener;
    type.trim().split(REGEXP_SPACES).forEach(function (event) {
      if (!onceSupported) {
        var listeners = element.listeners;

        if (listeners && listeners[event] && listeners[event][listener]) {
          handler = listeners[event][listener];
          delete listeners[event][listener];

          if (Object.keys(listeners[event]).length === 0) {
            delete listeners[event];
          }

          if (Object.keys(listeners).length === 0) {
            delete element.listeners;
          }
        }
      }

      element.removeEventListener(event, handler, options);
    });
  }
  /**
   * Add event listener to the target element.
   * @param {Element} element - The event target.
   * @param {string} type - The event type(s).
   * @param {Function} listener - The event listener.
   * @param {Object} options - The event options.
   */

  function addListener(element, type, listener) {
    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    var _handler = listener;
    type.trim().split(REGEXP_SPACES).forEach(function (event) {
      if (options.once && !onceSupported) {
        var _element$listeners = element.listeners,
            listeners = _element$listeners === void 0 ? {} : _element$listeners;

        _handler = function handler() {
          delete listeners[event][listener];
          element.removeEventListener(event, _handler, options);

          for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
            args[_key2] = arguments[_key2];
          }

          listener.apply(element, args);
        };

        if (!listeners[event]) {
          listeners[event] = {};
        }

        if (listeners[event][listener]) {
          element.removeEventListener(event, listeners[event][listener], options);
        }

        listeners[event][listener] = _handler;
        element.listeners = listeners;
      }

      element.addEventListener(event, _handler, options);
    });
  }
  /**
   * Dispatch event on the target element.
   * @param {Element} element - The event target.
   * @param {string} type - The event type(s).
   * @param {Object} data - The additional event data.
   * @returns {boolean} Indicate if the event is default prevented or not.
   */

  function dispatchEvent(element, type, data) {
    var event; // Event and CustomEvent on IE9-11 are global objects, not constructors

    if (isFunction(Event) && isFunction(CustomEvent)) {
      event = new CustomEvent(type, {
        detail: data,
        bubbles: true,
        cancelable: true
      });
    } else {
      event = document.createEvent('CustomEvent');
      event.initCustomEvent(type, true, true, data);
    }

    return element.dispatchEvent(event);
  }
  /**
   * Check if the given year is a leap year.
   * @param {number} year - The year to check.
   * @returns {boolean} Returns `true` if the given year is a leap year, else `false`.
   */

  function isLeapYear(year) {
    return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
  }
  /**
   * Get days number of the given month.
   * @param {number} year - The target year.
   * @param {number} month - The target month.
   * @returns {number} Returns days number.
   */

  function getDaysInMonth(year, month) {
    return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
  }
  /**
   * Add leading zeroes to the given value
   * @param {number} value - The value to add.
   * @param {number} [length=1] - The number of the leading zeroes.
   * @returns {string} Returns converted value.
   */

  function addLeadingZero(value) {
    var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
    var str = String(Math.abs(value));
    var i = str.length;
    var result = '';

    if (value < 0) {
      result += '-';
    }

    while (i < length) {
      i += 1;
      result += '0';
    }

    return result + str;
  }
  /**
   * Map token to type name
   * @param {string} token - The token to map.
   * @returns {string} Returns mapped type name.
   */

  function tokenToType(token) {
    return {
      Y: 'year',
      M: 'month',
      D: 'day',
      H: 'hour',
      m: 'minute',
      s: 'second',
      S: 'millisecond'
    }[token.charAt(0)];
  }
  var REGEXP_TOKENS = /(Y|M|D|H|m|s|S)\1*/g;
  /**
   * Parse date format.
   * @param {string} format - The format to parse.
   * @returns {Object} Returns parsed format data.
   */

  function parseFormat(format) {
    var tokens = format.match(REGEXP_TOKENS);

    if (!tokens) {
      throw new Error('Invalid format.');
    } // Remove duplicate tokens (#22)


    tokens = tokens.filter(function (token, index) {
      return tokens.indexOf(token) === index;
    });
    var result = {
      tokens: tokens
    };
    tokens.forEach(function (token) {
      result[tokenToType(token)] = token;
    });
    return result;
  }

  var events = {
    bind: function bind() {
      var element = this.element,
          options = this.options,
          grid = this.grid;

      if (isFunction(options.show)) {
        addListener(element, EVENT_SHOW, options.show);
      }

      if (isFunction(options.shown)) {
        addListener(element, EVENT_SHOWN, options.shown);
      }

      if (isFunction(options.hide)) {
        addListener(element, EVENT_HIDE, options.hide);
      }

      if (isFunction(options.hidden)) {
        addListener(element, EVENT_HIDDEN, options.hidden);
      }

      if (isFunction(options.pick)) {
        addListener(element, EVENT_PICK, options.pick);
      }

      addListener(element, EVENT_FOCUS, this.onFocus = this.focus.bind(this));
      addListener(element, EVENT_CLICK, this.onFocus);
      addListener(this.picker, EVENT_CLICK, this.onClick = this.click.bind(this));
      addListener(grid, EVENT_WHEEL, this.onWheel = this.wheel.bind(this));
      addListener(grid, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
      addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
      addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
      addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
    },
    unbind: function unbind() {
      var element = this.element,
          options = this.options,
          grid = this.grid;

      if (isFunction(options.show)) {
        removeListener(element, EVENT_SHOW, options.show);
      }

      if (isFunction(options.shown)) {
        removeListener(element, EVENT_SHOWN, options.shown);
      }

      if (isFunction(options.hide)) {
        removeListener(element, EVENT_HIDE, options.hide);
      }

      if (isFunction(options.hidden)) {
        removeListener(element, EVENT_HIDDEN, options.hidden);
      }

      if (isFunction(options.pick)) {
        removeListener(element, EVENT_PICK, options.pick);
      }

      removeListener(element, EVENT_FOCUS, this.onFocus);
      removeListener(element, EVENT_CLICK, this.onFocus);
      removeListener(this.picker, EVENT_CLICK, this.onClick);
      removeListener(grid, EVENT_WHEEL, this.onWheel);
      removeListener(grid, EVENT_POINTER_DOWN, this.onPointerDown);
      removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
      removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
      removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
    }
  };

  var handlers = {
    focus: function focus(event) {
      event.target.blur();
      this.show();
    },
    click: function click(event) {
      var target = event.target;
      var action = getData(target, DATA_ACTION);

      switch (action) {
        case ACTION_HIDE:
          this.hide();
          break;

        case ACTION_PICK:
          this.pick();
          break;

        case ACTION_PREV:
        case ACTION_NEXT:
          this[action](getData(target.parentElement, DATA_TYPE));
          break;

        default:
      }
    },
    wheel: function wheel(event) {
      var target = event.target;

      if (target === this.grid) {
        return;
      }

      event.preventDefault();

      while (target.parentElement && target.parentElement !== this.grid) {
        target = target.parentElement;
      }

      var type = getData(target, DATA_TYPE);

      if (event.deltaY < 0) {
        this.prev(type);
      } else {
        this.next(type);
      }
    },
    pointerdown: function pointerdown(event) {
      var target = event.target;

      if (target === this.grid || getData(target, DATA_ACTION)) {
        return;
      } // This line is required for preventing page scrolling in iOS browsers


      event.preventDefault();

      while (target.parentElement && target.parentElement !== this.grid) {
        target = target.parentElement;
      }

      var list = target.querySelector(".".concat(NAMESPACE, "-list"));
      var itemHeight = list.firstElementChild.offsetHeight;
      this.cell = {
        elem: target,
        list: list,
        moveY: 0,
        maxMoveY: itemHeight,
        minMoveY: itemHeight / 2,
        startY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY,
        type: getData(target, DATA_TYPE)
      };
    },
    pointermove: function pointermove(event) {
      var cell = this.cell;

      if (!cell) {
        return;
      }

      event.preventDefault();
      var endY = event.changedTouches ? event.changedTouches[0].pageY : event.pageY;
      var moveY = cell.moveY + (endY - cell.startY);
      cell.startY = endY;
      cell.moveY = moveY;

      if (Math.abs(moveY) < cell.maxMoveY) {
        cell.list.style.top = "".concat(moveY, "px");
        return;
      }

      cell.list.style.top = 0;
      cell.moveY = 0;

      if (moveY >= cell.maxMoveY) {
        this.prev(cell.type);
      } else if (moveY <= -cell.maxMoveY) {
        this.next(cell.type);
      }
    },
    pointerup: function pointerup(event) {
      var cell = this.cell;

      if (!cell) {
        return;
      }

      event.preventDefault();
      cell.list.style.top = 0;

      if (cell.moveY >= cell.minMoveY) {
        this.prev(cell.type);
      } else if (cell.moveY <= -cell.minMoveY) {
        this.next(cell.type);
      }

      this.cell = null;
    },
    keydown: function keydown(event) {
      if (this.shown && (event.key === 'Escape' || event.keyCode === 27)) {
        this.hide();
      }
    }
  };

  var helpers = {
    render: function render(type) {
      var _this = this;

      if (!type) {
        this.format.tokens.forEach(function (token) {
          return _this.render(tokenToType(token));
        });
        return;
      }

      var options = this.options;
      var data = this.data[type];
      var current = this.current(type);
      var max = isFunction(data.max) ? data.max() : data.max;
      var min = isFunction(data.min) ? data.min() : data.min;
      var base = 0;

      if (isFinite(max)) {
        base = min > 0 ? max : max + 1;
      }

      data.list.innerHTML = '';
      data.current = current;

      for (var i = 0; i < options.rows + 2; i += 1) {
        var item = document.createElement('li');
        var position = i - data.index;
        var newValue = current + position * data.increment;

        if (base) {
          newValue %= base;

          if (newValue < min) {
            newValue += base;
          }
        }

        item.textContent = options.translate(type, data.aliases ? data.aliases[newValue] : addLeadingZero(newValue + data.offset, data.digit));
        setData(item, DATA_NAME, type);
        setData(item, DATA_VALUE, newValue);
        addClass(item, "".concat(NAMESPACE, "-item"));

        if (position === 0) {
          addClass(item, CLASS_PICKED);
          data.item = item;
        }

        data.list.appendChild(item);
      }
    },
    current: function current(type, value) {
      var date = this.date;
      var format = this.format;
      var token = format[type];

      switch (token.charAt(0)) {
        case 'Y':
          if (isNumber(value)) {
            date.setFullYear(token.length === 2 ? 2000 + value : value);

            if (format.month) {
              this.render(tokenToType(format.month));
            }

            if (format.day) {
              this.render(tokenToType(format.day));
            }
          }

          return date.getFullYear();

        case 'M':
          if (isNumber(value)) {
            date.setMonth(value, // The current day should not exceed its maximum day in current month
            Math.min(date.getDate(), getDaysInMonth(date.getFullYear(), value)));

            if (format.day) {
              this.render(tokenToType(format.day));
            }
          }

          return date.getMonth();

        case 'D':
          if (isNumber(value)) {
            date.setDate(value);
          }

          return date.getDate();

        case 'H':
          if (isNumber(value)) {
            date.setHours(value);
          }

          return date.getHours();

        case 'm':
          if (isNumber(value)) {
            date.setMinutes(value);
          }

          return date.getMinutes();

        case 's':
          if (isNumber(value)) {
            date.setSeconds(value);
          }

          return date.getSeconds();

        case 'S':
          if (isNumber(value)) {
            date.setMilliseconds(value);
          }

          return date.getMilliseconds();

        default:
      }

      return date;
    },
    getValue: function getValue() {
      var element = this.element;
      return this.isInput ? element.value : element.textContent;
    },
    setValue: function setValue(value) {
      var element = this.element;

      if (this.isInput) {
        element.value = value;
      } else if (this.options.container) {
        element.textContent = value;
      }
    },
    open: function open() {
      var body = this.body;
      body.style.overflow = 'hidden';
      body.style.paddingRight = "".concat(this.scrollBarWidth + (parseFloat(this.initialBodyPaddingRight) || 0), "px");
    },
    close: function close() {
      var body = this.body;
      body.style.overflow = '';
      body.style.paddingRight = this.initialBodyPaddingRight;
    }
  };

  var methods = {
    /**
     * Show the picker.
     * @param {boolean} [immediate=false] - Indicate if show the picker immediately or not.
     * @returns {Picker} this
     */
    show: function show() {
      var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
      var element = this.element,
          picker = this.picker;

      if (this.inline || this.shown) {
        return this;
      }

      if (dispatchEvent(element, EVENT_SHOW) === false) {
        return this;
      }

      this.shown = true;
      this.open();
      addClass(picker, CLASS_OPEN);

      var done = function done() {
        dispatchEvent(element, EVENT_SHOWN);
      };

      if (!immediate) {
        // Reflow to enable transition
        // eslint-disable-next-line
        picker.offsetWidth;
      }

      addClass(picker, CLASS_OPENED);

      if (immediate) {
        done();
      } else {
        setTimeout(done, 300);
      }

      return this;
    },

    /**
     * Hide the picker.
     * @param {boolean} [immediate=false] - Indicate if hide the picker immediately or not.
     * @returns {Picker} this
     */
    hide: function hide() {
      var _this = this;

      var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
      var element = this.element,
          picker = this.picker;

      if (this.inline || !this.shown) {
        return this;
      }

      if (dispatchEvent(element, EVENT_HIDE) === false) {
        return this;
      }

      this.shown = false;
      removeClass(picker, CLASS_OPENED);

      var done = function done() {
        _this.close();

        removeClass(picker, CLASS_OPEN);
        dispatchEvent(element, EVENT_HIDDEN);
      };

      if (immediate) {
        done();
      } else {
        setTimeout(done, 300);
      }

      return this;
    },

    /**
     * Pick to the previous item.
     * @param {string} type - The column type.
     * @returns {Picker} this
     */
    prev: function prev(type) {
      var options = this.options;
      var token = this.format[type];
      var data = this.data[type];
      var list = data.list;
      var item = list.lastElementChild;
      var max = isFunction(data.max) ? data.max() : data.max;
      var min = isFunction(data.min) ? data.min() : data.min;
      var prev = data.item.previousElementSibling;
      var value = Number(getData(list.firstElementChild, DATA_VALUE)) - data.increment;

      if (value < min) {
        value += max - min + 1;
      }

      item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
      setData(item, DATA_VALUE, value);

      if (prev) {
        removeClass(data.item, CLASS_PICKED);
        addClass(prev, CLASS_PICKED);
        data.item = prev;
      }

      list.insertBefore(item, list.firstElementChild);
      data.current = Number(getData(data.item, DATA_VALUE));
      this.current(type, data.current);

      if (this.inline && options.container) {
        this.pick();
      }

      return this;
    },

    /**
     * Pick to the next item.
     * @param {String} type - The column type.
     * @returns {Picker} this
     */
    next: function next(type) {
      var options = this.options;
      var token = this.format[type];
      var data = this.data[type];
      var list = data.list;
      var item = list.firstElementChild;
      var max = isFunction(data.max) ? data.max() : data.max;
      var min = isFunction(data.min) ? data.min() : data.min;
      var next = data.item.nextElementSibling;
      var value = Number(getData(list.lastElementChild, DATA_VALUE)) + data.increment;

      if (value > max) {
        value -= max - min + 1;
      }

      item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
      setData(item, DATA_VALUE, value);
      list.appendChild(item);

      if (next) {
        removeClass(data.item, CLASS_PICKED);
        addClass(next, CLASS_PICKED);
        data.item = next;
      }

      data.current = Number(getData(data.item, DATA_VALUE));
      this.current(type, data.current);

      if (this.inline && options.container) {
        this.pick();
      }

      return this;
    },
    // Pick the current date to the target element.
    pick: function pick() {
      var element = this.element;

      if (dispatchEvent(element, EVENT_PICK) === false) {
        return this;
      }

      var value = this.formatDate(this.date);
      this.setValue(value);

      if (this.isInput && dispatchEvent(element, 'change') === false) {
        this.reset();
      }

      this.hide();
      return this;
    },

    /**
     * Get the current date.
     * @param {boolean} [formatted=false] - Indicate if format the date or not.
     * @return {Date|string} The output date.
     */
    getDate: function getDate() {
      var formatted = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
      var date = this.date;
      return formatted ? this.formatDate(date) : new Date(date);
    },

    /**
     * Override the current date with a new date.
     * @param {Date|string} date - The date to set.
     * @returns {Picker} this
     */
    setDate: function setDate(date) {
      if (date) {
        this.date = this.parseDate(date);
        this.render();
      }

      return this;
    },
    // Update the picker with the current element value / text.
    update: function update() {
      this.date = this.parseDate(this.getValue());
      this.render();
      return this;
    },
    // Reset the picker and element value / text.
    reset: function reset() {
      this.setValue(this.initialValue);
      this.date = new Date(this.initialDate);
      this.render();
      return this;
    },

    /**
     * Parse a date with the set date format.
     * @param {Date|string} date - The date to parse.
     * @returns {Date} The parsed date object.
     */
    parseDate: function parseDate(date) {
      var options = this.options,
          format = this.format;
      var digits = [];

      if (isDate(date)) {
        return new Date(date);
      }

      if (isString(date)) {
        var groups = [].concat(_toConsumableArray(options.months), _toConsumableArray(options.monthsShort), ['\\d+']);
        digits = date.match(new RegExp("(".concat(groups.join('|'), ")"), 'g')); // Parse `11111111` (YYYYMMDD) to ['1111', '11', '11']

        if (digits && date.length === options.format.length && digits.length !== format.tokens.length) {
          digits = format.tokens.map(function (token) {
            return date.substr(options.format.indexOf(token), token.length);
          });
        }

        if (!digits || digits.length !== format.tokens.length) {
          return new Date();
        }
      }

      var parsedDate = new Date();
      digits.forEach(function (digit, i) {
        var token = format.tokens[i];
        var n = Number(digit);

        switch (token) {
          case 'YYYY':
          case 'YYY':
          case 'Y':
            {
              var index = date.indexOf(digit);
              var isHyphen = date.substr(index - 1, 1) === '-';
              var isBC = index > 1 && isHyphen && /\S/.test(date.substr(index - 2, 1)) || index === 1 && isHyphen;
              parsedDate.setFullYear(isBC ? -n : n);
              break;
            }

          case 'YY':
            parsedDate.setFullYear(2000 + n);
            break;

          case 'MMMM':
            parsedDate.setMonth(options.months.indexOf(digit));
            break;

          case 'MMM':
            parsedDate.setMonth(options.monthsShort.indexOf(digit));
            break;

          case 'MM':
          case 'M':
            parsedDate.setMonth(n - 1);
            break;

          case 'DD':
          case 'D':
            parsedDate.setDate(n);
            break;

          case 'HH':
          case 'H':
            parsedDate.setHours(n);
            break;

          case 'mm':
          case 'm':
            parsedDate.setMinutes(n);
            break;

          case 'ss':
          case 's':
            parsedDate.setSeconds(n);
            break;

          case 'SSS':
          case 'SS':
          case 'S':
            parsedDate.setMilliseconds(n);
            break;

          default:
        }
      });
      return parsedDate;
    },

    /**
     * Format a date object to a string with the set date format.
     * @param {Date} date - The date to format.
     * @return {string} THe formatted date.
     */
    formatDate: function formatDate(date) {
      var options = this.options,
          format = this.format;
      var formatted = '';

      if (isValidDate(date)) {
        var year = date.getFullYear();
        var month = date.getMonth();
        var day = date.getDate();
        var hours = date.getHours();
        var minutes = date.getMinutes();
        var seconds = date.getSeconds();
        var milliseconds = date.getMilliseconds();
        formatted = options.format;
        format.tokens.forEach(function (token) {
          var replacement = '';

          switch (token) {
            case 'YYYY':
            case 'YYY':
            case 'Y':
              replacement = addLeadingZero(year, token.length);
              break;

            case 'YY':
              replacement = addLeadingZero(year % 100, 2);
              break;

            case 'MMMM':
              replacement = options.months[month];
              break;

            case 'MMM':
              replacement = options.monthsShort[month];
              break;

            case 'MM':
            case 'M':
              replacement = addLeadingZero(month + 1, token.length);
              break;

            case 'DD':
            case 'D':
              replacement = addLeadingZero(day, token.length);
              break;

            case 'HH':
            case 'H':
              replacement = addLeadingZero(hours, token.length);
              break;

            case 'mm':
            case 'm':
              replacement = addLeadingZero(minutes, token.length);
              break;

            case 'ss':
            case 's':
              replacement = addLeadingZero(seconds, token.length);
              break;

            case 'SSS':
            case 'SS':
            case 'S':
              replacement = addLeadingZero(milliseconds, token.length);
              break;

            default:
          }

          formatted = formatted.replace(token, replacement);
        });
      }

      return formatted;
    },
    // Destroy the picker and remove the instance from the target element.
    destroy: function destroy() {
      var element = this.element,
          picker = this.picker;

      if (!getData(element, NAMESPACE)) {
        return this;
      }

      this.hide(true);
      this.unbind();
      removeData(element, NAMESPACE);
      picker.parentNode.removeChild(picker);
      return this;
    }
  };

  var REGEXP_DELIMITER = /\{\{\s*(\w+)\s*\}\}/g;
  var REGEXP_INPUTS = /input|textarea/i;
  var AnotherPicker = WINDOW.Picker;

  var Picker =
  /*#__PURE__*/
  function () {
    /**
     * Create a new Picker.
     * @param {Element} element - The target element for picking.
     * @param {Object} [options={}] - The configuration options.
     */
    function Picker(element) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      _classCallCheck(this, Picker);

      if (!element || element.nodeType !== 1) {
        throw new Error('The first argument is required and must be an element.');
      }

      this.element = element;
      this.options = deepAssign({}, DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
      this.shown = false;
      this.init();
    }

    _createClass(Picker, [{
      key: "init",
      value: function init() {
        var _this = this;

        var element = this.element;

        if (getData(element, NAMESPACE)) {
          return;
        }

        setData(element, NAMESPACE, this);
        var options = this.options;
        var isInput = REGEXP_INPUTS.test(element.tagName);
        var inline = options.inline && (options.container || !isInput);
        var template = document.createElement('div');
        template.insertAdjacentHTML('afterbegin', TEMPLATE.replace(REGEXP_DELIMITER, function () {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }

          return options.text[args[1]];
        }));
        var picker = template.getElementsByClassName(NAMESPACE)[0];
        var grid = picker.getElementsByClassName("".concat(NAMESPACE, "-grid"))[0];
        var container = options.container;

        if (isString(container)) {
          container = document.querySelector(container);
        }

        if (inline) {
          addClass(picker, CLASS_OPEN);
          addClass(picker, CLASS_OPENED);

          if (!container) {
            container = element;
          }
        } else {
          var ownerDocument = element.ownerDocument;
          var body = ownerDocument.body || ownerDocument.documentElement;
          this.body = body;
          this.scrollBarWidth = WINDOW.innerWidth - ownerDocument.documentElement.clientWidth;
          this.initialBodyPaddingRight = WINDOW.getComputedStyle(body).paddingRight;
          addClass(picker, "".concat(NAMESPACE, "-fixed"));

          if (!container) {
            container = document.body;
          }
        }

        this.isInput = isInput;
        this.inline = inline;
        this.container = container;
        this.picker = picker;
        this.grid = grid;
        this.cell = null;
        this.format = parseFormat(options.format);
        var initialValue = this.getValue();
        var date = this.parseDate(options.date || initialValue);
        this.date = date;
        this.initialDate = new Date(date);
        this.initialValue = initialValue;
        this.data = {};
        var rows = Number(options.rows);

        if (!(rows % 2)) {
          rows += 1;
        }

        options.rows = rows || 5;
        addClass(grid, "".concat(NAMESPACE, "-").concat(options.rows > 1 ? 'multiple' : 'single'));

        if (options.controls) {
          addClass(grid, "".concat(NAMESPACE, "-controls"));
        }

        var headers = options.headers,
            increment = options.increment;

        if (headers) {
          addClass(grid, "".concat(NAMESPACE, "-headers")); // TODO: Drop the `headers` option's object support in v2.

          headers = isPlainObject(headers) ? headers : options.text;
        }

        if (!isPlainObject(increment)) {
          increment = {
            year: increment,
            month: increment,
            day: increment,
            hour: increment,
            minute: increment,
            second: increment,
            millisecond: increment
          };
        }

        this.format.tokens.forEach(function (token) {
          var type = tokenToType(token);
          var cell = document.createElement('div');
          var cellBody = document.createElement('div');
          var list = document.createElement('ul');
          var data = {
            digit: token.length,
            increment: Math.abs(Number(increment[type])) || 1,
            list: list,
            max: Infinity,
            min: -Infinity,
            index: Math.floor((options.rows + 2) / 2),
            offset: 0
          };

          switch (token.charAt(0)) {
            case 'Y':
              if (data.digit === 2) {
                data.max = 99;
                data.min = 0;
              }

              break;

            case 'M':
              data.max = 11;
              data.min = 0;
              data.offset = 1;

              if (data.digit === 3) {
                data.aliases = options.monthsShort;
              } else if (data.digit === 4) {
                data.aliases = options.months;
              }

              break;

            case 'D':
              // XXX: Use the latest date to calculate the max day (#23)
              data.max = function () {
                return getDaysInMonth(_this.date.getFullYear(), _this.date.getMonth());
              };

              data.min = 1;
              break;

            case 'H':
              data.max = 23;
              data.min = 0;
              break;

            case 'm':
              data.max = 59;
              data.min = 0;
              break;

            case 's':
              data.max = 59;
              data.min = 0;
              break;

            case 'S':
              data.max = 999;
              data.min = 0;
              break;

            default:
          }

          setData(cell, DATA_TYPE, type);
          setData(cell, DATA_TOKEN, token);

          if (headers) {
            var cellHeader = document.createElement('div');
            addClass(cellHeader, "".concat(NAMESPACE, "-cell__header"));
            cellHeader.textContent = headers[type] || type[0].toUpperCase() + type.substr(1);
            cell.appendChild(cellHeader);
          }

          if (options.controls) {
            var prev = document.createElement('div');
            addClass(prev, "".concat(NAMESPACE, "-cell__control"));
            addClass(prev, "".concat(NAMESPACE, "-cell__control--prev"));
            setData(prev, DATA_ACTION, ACTION_PREV);
            cell.appendChild(prev);
          }

          addClass(list, "".concat(NAMESPACE, "-list"));
          addClass(cellBody, "".concat(NAMESPACE, "-cell__body"));
          addClass(cell, "".concat(NAMESPACE, "-cell"));
          addClass(cell, "".concat(NAMESPACE, "-").concat(type, "s"));
          cellBody.appendChild(list);
          cell.appendChild(cellBody);

          if (options.controls) {
            var next = document.createElement('div');
            addClass(next, "".concat(NAMESPACE, "-cell__control"));
            addClass(next, "".concat(NAMESPACE, "-cell__control--next"));
            setData(next, DATA_ACTION, ACTION_NEXT);
            cell.appendChild(next);
          }

          grid.appendChild(cell);
          _this.data[type] = data;

          _this.render(type);
        });

        if (inline) {
          container.innerHTML = '';
        }

        container.appendChild(picker);
        this.bind();
      }
      /**
       * Get the no conflict picker class.
       * @returns {Picker} The picker class.
       */

    }], [{
      key: "noConflict",
      value: function noConflict() {
        WINDOW.Picker = AnotherPicker;
        return Picker;
      }
      /**
       * Change the default options.
       * @param {Object} options - The new default options.
       */

    }, {
      key: "setDefaults",
      value: function setDefaults(options) {
        deepAssign(DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
      }
    }]);

    return Picker;
  }();

  deepAssign(Picker.prototype, events, handlers, helpers, methods);
  Picker.languages = LANGUAGES;

  return Picker;

}));
