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

import { camelcase, hyphenate } from './string';
import { each } from './object';
/**
 * 是否能使用 DOM 方法
 * @type {Boolean}
 */

export var hasDOM = typeof window !== 'undefined' && !!window.document && !!document.createElement;
/**
 * 节点是否包含指定 className
 * @param  {Element}  node
 * @param  {String}  className
 * @return {Boolean}
 *
 * @example
 * dom.hasClass(document.body, 'foo');
 */

export function hasClass(node, className) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return false;
  }

  if (node.classList) {
    return node.classList.contains(className);
  } else {
    return node.className.indexOf(className) > -1;
  }
}
/**
 * 添加 className
 * @param {Element} node
 * @param {String} className
 *
 * @example
 * dom.addClass(document.body, 'foo');
 */

export function addClass(node, className, _force) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return;
  }

  if (node.classList) {
    node.classList.add(className);
  } else if (_force === true || !hasClass(node, className)) {
    node.className += " ".concat(className);
  }
}
/**
 * 移除 className
 * @param  {Element} node
 * @param  {String} className
 *
 * @example
 * dom.removeClass(document.body, 'foo');
 */

export function removeClass(node, className, _force) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return;
  }

  if (node.classList) {
    node.classList.remove(className);
  } else if (_force === true || hasClass(node, className)) {
    node.className = node.className.replace(className, '').replace(/\s+/g, ' ').trim();
  }
}
/**
 * 切换 className
 * @param  {Element} node
 * @param  {String} className
 * @return {Boolean}           执行后节点上是否还有此 className
 *
 * @example
 * dom.toggleClass(document.body, 'foo');
 */

export function toggleClass(node, className) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return false;
  }

  if (node.classList) {
    return node.classList.toggle(className);
  } else {
    var flag = hasClass(node, className);
    flag ? removeClass(node, className, true) : addClass(node, className, true);
    return !flag;
  }
}
/**
 * 元素是否匹配 CSS 选择器
 * @param  {Element} node       DOM 节点
 * @param  {String}  selector   CSS 选择器
 * @return {Boolean}
 *
 * @example
 * dom.matches(mountNode, '.container'); // boolean
 */

export var matches = function () {
  var matchesFn = null;
  /* istanbul ignore else */

  if (hasDOM) {
    var _body = document.body || document.head;

    matchesFn = _body.matches ? 'matches' : _body.webkitMatchesSelector ? 'webkitMatchesSelector' : _body.msMatchesSelector ? 'msMatchesSelector' : _body.mozMatchesSelector ? 'mozMatchesSelector' : null;
  }

  return function (node, selector) {
    if (!hasDOM || !node) {
      return false;
    }

    return matchesFn ? node[matchesFn](selector) : false;
  };
}();
/**
 * 获取元素计算后的样式
 * @private
 * @param  {Element} node
 * @return {Object}
 */

function _getComputedStyle(node) {
  return node && node.nodeType === 1 ? window.getComputedStyle(node, null) : {};
}

var PIXEL_PATTERN = /margin|padding|width|height|max|min|offset|size/i;
var removePixel = {
  left: 1,
  top: 1,
  right: 1,
  bottom: 1
};
/**
 * 校验并修正元素的样式属性值
 * @private
 * @param  {Element} node
 * @param  {String} type
 * @param  {Number} value
 */

function _getStyleValue(node, type, value) {
  type = type.toLowerCase();

  if (value === 'auto') {
    if (type === 'height') {
      return node.offsetHeight || 0;
    }

    if (type === 'width') {
      return node.offsetWidth || 0;
    }
  }

  if (!(type in removePixel)) {
    // 属性值是否需要去掉 px 单位，这里假定此类的属性值都是 px 为单位的
    removePixel[type] = PIXEL_PATTERN.test(type);
  }

  return removePixel[type] ? parseFloat(value) || 0 : value;
}

var floatMap = {
  cssFloat: 1,
  styleFloat: 1,
  "float": 1
};
/**
 * 获取元素计算后的样式
 * @param  {Element} node DOM 节点
 * @param  {String} name 属性名
 * @return {Number|Object}
 */

export function getStyle(node, name) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return null;
  }

  var style = _getComputedStyle(node); // 如果不指定属性名，则返回全部值


  if (arguments.length === 1) {
    return style;
  }

  name = floatMap[name] ? 'cssFloat' in node.style ? 'cssFloat' : 'styleFloat' : name;
  return _getStyleValue(node, name, style.getPropertyValue(hyphenate(name)) || node.style[camelcase(name)]);
}
/**
 * 设置元素的样式
 * @param {Element} node  DOM 节点
 * @param {Object|String} name  属性名，或者是一个对象，包含多个属性
 * @param {Number|String} value 属性值
 *
 * @example
 * // 设置单个属性值
 * dom.setStyle(mountNode, 'width', 100);
 * // 设置多条属性值
 * dom.setStyle(mountNode, {
 *     width: 100,
 *     height: 200
 * });
 */

export function setStyle(node, name, value) {
  /* istanbul ignore if */
  if (!hasDOM || !node) {
    return false;
  } // 批量设置多个值


  if (_typeof(name) === 'object' && arguments.length === 2) {
    each(name, function (val, key) {
      return setStyle(node, key, val);
    });
  } else {
    name = floatMap[name] ? 'cssFloat' in node.style ? 'cssFloat' : 'styleFloat' : name;

    if (typeof value === 'number' && PIXEL_PATTERN.test(name)) {
      value = "".concat(value, "px");
    }

    node.style[camelcase(name)] = value; // IE8 support
  }
}
/**
 * 获取默认的滚动条大小
 * @return {Object} width, height
 */

export function scrollbar() {
  var scrollDiv = document.createElement('div');
  setStyle(scrollDiv, {
    position: 'absolute',
    width: '100px',
    height: '100px',
    overflow: 'scroll',
    top: '-9999px'
  });
  document.body.appendChild(scrollDiv);
  var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  var scrollbarHeight = scrollDiv.offsetHeight - scrollDiv.clientHeight;
  document.body.removeChild(scrollDiv);
  return {
    width: scrollbarWidth,
    height: scrollbarHeight
  };
}
/**
 * 获取元素距离视口顶部和左边的偏移距离
 * @return {Object} top, left
 */

export function getOffset(node) {
  var rect = node.getBoundingClientRect();
  var win = node.ownerDocument.defaultView;
  return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
  };
}
/**
 * 强制访问元素的布局属性以触发重排，通常用于保证动画的执行
 * @param  {Element} el
 * @return {void}
 */

export function forceReflow(el) {
  if (el) {
    el.offsetHeight;
  }
}