'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

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

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _utils = require('./utils');

require('./react-dnd-ax.css');

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

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

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

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

var DragNDropItem = function DragNDropItem(WrappedComponent) {
  var Wrapper = function (_React$Component) {
    _inherits(Wrapper, _React$Component);

    function Wrapper() {
      var _ref;

      var _temp, _this, _ret;

      _classCallCheck(this, Wrapper);

      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Wrapper.__proto__ || Object.getPrototypeOf(Wrapper)).call.apply(_ref, [this].concat(args))), _this), _this.havePropsChanged = function (nextProps) {
        var propagatableProps = _extends({}, (0, _utils.omit)(nextProps, 'state', 'key', 'actions', 'onReorderItem', 'index'));

        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = Object.keys(propagatableProps)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var key = _step.value;

            if (propagatableProps[key] !== _this.props[key]) {
              return true;
            }
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator.return) {
              _iterator.return();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }

        return false;
      }, _this.onSetImageDragStart = function (e) {
        var _this$props = _this.props,
            index = _this$props.index,
            actions = _this$props.actions;
        // hide the default drag preview image
        // IE and Edge do not have this method

        e.dataTransfer.setDragImage ? // eslint-disable-line no-unused-expressions
        e.dataTransfer.setDragImage(document.getElementsByClassName('dnd-drag-placeholder')[0], 0, 0) : '';
        e.dataTransfer.setData('text', ''); // make dnd work in FF, IE and Edge
        actions.onDragStart(e, index);
      }, _this.onTouchStart = function (e) {
        e.preventDefault();
        var _this$props2 = _this.props,
            index = _this$props2.index,
            actions = _this$props2.actions;


        actions.onDragStart(e, index);
      }, _this.onClick = function (e) {
        e.stopPropagation();
        var _this$props3 = _this.props,
            index = _this$props3.index,
            actions = _this$props3.actions,
            preview = _this$props3.preview;


        actions.onClickDrag(e, index, preview);
      }, _this.onDropNextIndex = function (e) {
        var _this$props4 = _this.props,
            index = _this$props4.index,
            actions = _this$props4.actions;


        actions.onDrop(e, index + 1);
      }, _this.onDragOverNextIndex = function (e) {
        var _this$props5 = _this.props,
            index = _this$props5.index,
            actions = _this$props5.actions;


        actions.onDragOver(e, index + 1);
      }, _this.onDragLeave = function (e) {
        var _this$props6 = _this.props,
            index = _this$props6.index,
            actions = _this$props6.actions;


        actions.onDragLeave(e, index);
      }, _this.onDragOver = function (e) {
        var _this$props7 = _this.props,
            index = _this$props7.index,
            actions = _this$props7.actions;


        actions.onDragOver(e, index);
      }, _this.onDrop = function (e) {
        var _this$props8 = _this.props,
            index = _this$props8.index,
            actions = _this$props8.actions;


        actions.onDrop(e, index);
      }, _temp), _possibleConstructorReturn(_this, _ret);
    }

    _createClass(Wrapper, [{
      key: 'componentDidMount',
      value: function componentDidMount() {
        var _this2 = this;

        var actions = this.props.actions;


        if (this.dragPointElem) {
          this.dragPointElem.addEventListener('touchstart', this.onTouchStart);
          this.dragPointElem.addEventListener('touchend', actions.onTouchDrop);
          this.dragPointElem.addEventListener('drag', function (e) {
            actions.onDrag(e, _this2.dragPreviewRef);
          });
          this.dragPointElem.addEventListener('dragstart', this.onSetImageDragStart);
          this.dragPointElem.addEventListener('dragend', actions.onDragEnd);
          this.dragPointElem.addEventListener('touchmove', function (e) {
            actions.onTouchMove(e, _this2.dragPreviewRef);
          });
          this.dragPointElem.addEventListener('click', this.onClick);
          this.itemRef.addEventListener('keydown', actions.onKeyChangeOrder);
        }
      }

      // only render necessary components

    }, {
      key: 'shouldComponentUpdate',
      value: function shouldComponentUpdate(nextProps) {
        var _props = this.props,
            state = _props.state,
            index = _props.index;

        // need to render all when toggling drag status

        if (nextProps.state.isDragging !== state.isDragging) {
          return true;
        }

        if (nextProps.state.isKeyboardMoving !== state.isKeyboardMoving) {
          return true;
        }

        if (state.isDragging) {
          // only render component around hot zone
          if (nextProps.state.sourceIndex === index || state.sourceIndex === index || nextProps.state.lastOverIndex === index || // as drag over does not happen sequentially, we need to render the last over element
          index >= nextProps.state.overIndex - 2 && index <= nextProps.state.overIndex + 2) {
            return true;
          }

          // when hovering on dragging element
          if (nextProps.state.overIndex === -1 && nextProps.state.overIndex !== state.overIndex) {
            if (index >= state.sourceIndex - 2 && index <= state.sourceIndex + 1) {
              return true;
            }
          }
        }

        // only render source and destination item
        if (state.isKeyboardMoving) {
          if (index + 1 === state.keyInsertIndex || index + 1 === nextProps.state.keyInsertIndex || index === 0) {
            // improve: should not always render index === 0
            return true;
          }
        }

        return this.havePropsChanged(nextProps);
      }
    }, {
      key: 'componentDidUpdate',
      value: function componentDidUpdate() {
        if (this.dragPointElem) {
          // we need to update index and preview value as we don't recreate dnd-item every time
          this.dragPointElem.removeEventListener('touchstart', this.onTouchStart);
          this.dragPointElem.addEventListener('touchstart', this.onTouchStart);
          this.dragPointElem.removeEventListener('dragstart', this.onSetImageDragStart);
          this.dragPointElem.addEventListener('dragstart', this.onSetImageDragStart);
          this.dragPointElem.removeEventListener('click', this.onClick);
          this.dragPointElem.addEventListener('click', this.onClick);
        }

        if (this.firstKeyInsertPlaceHolderRef && this.firstKeyInsertPlaceHolderRef.className.includes('show')) {
          this.firstKeyInsertPlaceHolderRef.focus();
        } else if (this.downKeyInsertPlaceHolderRef.className.includes('show')) {
          this.downKeyInsertPlaceHolderRef.focus();
        } else if (this.itemRef.className.includes('is-keyboard-moving') && this.itemRef.className.includes('should-on-focus')) {
          this.itemRef.focus();
        }
        if (this.dragPreviewRef.className.includes('show')) {
          this.dragPreviewRef.style.width = getComputedStyle(this.itemRef).getPropertyValue('width');
        }
      }
    }, {
      key: 'render',
      value: function render() {
        var _this3 = this;

        var _props2 = this.props,
            state = _props2.state,
            index = _props2.index,
            actions = _props2.actions,
            preview = _props2.preview;

        var itemSectionClass = (0, _classnames2.default)({
          'module-section': true,
          'is-dragging': state.isDragging && state.sourceIndex === index,
          'is-keyboard-moving': state.isKeyboardMoving && index === state.sourceIndex,
          'should-on-focus': state.isKeyboardMoving && (index === state.keyInsertIndex || index + 1 === state.keyInsertIndex)
        });
        var dropUpHalfClass = (0, _classnames2.default)({
          'drop-up-half': true,
          show: state.isDragging && index !== state.sourceIndex && index !== state.sourceIndex + 1
        });
        var dropDownHalfClass = (0, _classnames2.default)({
          'drop-down-half': true,
          show: state.isDragging && index !== state.sourceIndex && index !== state.sourceIndex - 1
        });
        var firstKeyInsertPlaceHolderClass = (0, _classnames2.default)({
          'key-insert-placeholder': true,
          show: state.isKeyboardMoving && state.keyInsertIndex === 0 && state.sourceIndex !== 0
        });
        var firstInsertPlaceHolderClass = (0, _classnames2.default)({
          'insert-placeholder first-insert-placeholder': true,
          show: state.isDragging && state.overIndex === 0
        });
        var insertPlaceholderClass = (0, _classnames2.default)({
          'insert-placeholder': true,
          show: state.isDragging && index === state.overIndex - 1
        });
        var dragPreviewItemClass = (0, _classnames2.default)({
          'drag-preview-item': true,
          show: state.isDragging && index === state.sourceIndex
        });
        var downKeyInsertPlaceHolderRef = (0, _classnames2.default)({
          'key-insert-placeholder': true,
          show: state.isKeyboardMoving && index + 1 === state.keyInsertIndex && index !== state.sourceIndex
        });

        return _react2.default.createElement(
          'div',
          { className: itemSectionClass, ref: function ref(_ref5) {
              _this3.itemRef = _ref5;
            }, tabIndex: '-1' },
          index === 0 ? _react2.default.createElement('div', { className: firstInsertPlaceHolderClass }) : '',
          index === 0 ? _react2.default.createElement(
            'div',
            {
              tabIndex: '-1',
              className: firstKeyInsertPlaceHolderClass,
              onKeyDown: actions.onKeyChangeOrder,
              ref: function ref(_ref2) {
                _this3.firstKeyInsertPlaceHolderRef = _ref2;
              }
            },
            state.curPreview
          ) : '',
          _react2.default.createElement(
            'div',
            { className: 'item-container' },
            _react2.default.createElement(WrappedComponent, _extends({}, (0, _utils.omit)(this.props, 'state', 'key', 'actions', 'onReorderItem'), {
              dragPointRef: function dragPointRef(el) {
                _this3.dragPointElem = el;
              }
            }))
          ),
          _react2.default.createElement('div', {
            className: dropUpHalfClass,
            'data-position': index,
            onDrop: this.onDrop,
            onDragOver: this.onDragOver,
            onDragLeave: this.onDragLeave
          }),
          _react2.default.createElement('div', {
            className: dropDownHalfClass,
            'data-position': index + 1,
            onDrop: this.onDropNextIndex,
            onDragOver: this.onDragOverNextIndex,
            onDragLeave: this.onDragLeave
          }),
          _react2.default.createElement('div', { className: insertPlaceholderClass }),
          _react2.default.createElement(
            'div',
            {
              className: dragPreviewItemClass,
              ref: function ref(_ref3) {
                _this3.dragPreviewRef = _ref3;
              }
            },
            preview
          ),
          _react2.default.createElement(
            'div',
            {
              tabIndex: '-1',
              className: downKeyInsertPlaceHolderRef,
              onKeyDown: actions.onKeyChangeOrder,
              ref: function ref(_ref4) {
                _this3.downKeyInsertPlaceHolderRef = _ref4;
              }
            },
            state.curPreview
          )
        );
      }
    }]);

    return Wrapper;
  }(_react2.default.Component);

  Wrapper.propTypes = {
    index: _propTypes2.default.number.isRequired,
    actions: _propTypes2.default.object.isRequired,
    state: _propTypes2.default.object.isRequired,
    preview: _propTypes2.default.element.isRequired
  };

  Wrapper.displayName = 'DragNDropItem(' + (0, _utils.getDisplayName)(WrappedComponent) + ')';

  return Wrapper;
};

exports.default = DragNDropItem;