"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.chainTransactions = chainTransactions;
exports.filter = exports.clearNodes = void 0;
exports.findCutBefore = findCutBefore;
exports.selectNode = exports.isFirstChildOfParent = exports.isEmptySelectionAtStart = exports.isEmptySelectionAtEnd = exports.insertContentDeleteRange = void 0;
exports.setAlignment = setAlignment;
exports.setHeadLine = setHeadLine;
exports.walkPrevNode = exports.walkNextNode = void 0;

var _prosemirrorCommands = require("prosemirror-commands");

var _prosemirrorState = require("prosemirror-state");

var _prosemirrorTransform = require("prosemirror-transform");

var _schemas = _interopRequireDefault(require("../schemas"));

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

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

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

  return function (state, dispatch) {
    var dispatcher = function dispatcher(tr) {
      state = state.apply(tr);
      dispatch(tr);
    };

    var last = commands.pop();
    var reduced = commands.reduce(function (result, command) {
      return result || command(state, dispatcher);
    }, false);
    return reduced && last !== undefined && last(state, dispatch);
  };
}

function setHeadLine(state, dispatchTransiction, level) {
  var $from = state.selection.$from;
  var node = $from.node();

  if (node.type === _schemas["default"].nodes.heading && level === node.attrs.level) {
    return (0, _prosemirrorCommands.setBlockType)(_schemas["default"].nodes.paragraph, node.attrs)(state, dispatchTransiction);
  }

  return chainTransactions(clearNodes(), (0, _prosemirrorCommands.setBlockType)(_schemas["default"].nodes.heading, _objectSpread(_objectSpread({}, node.attrs), {}, {
    level: level
  })))(state, dispatchTransiction);
}

function setAlignment(state, dispatchTransiction, alignment) {
  var $from = state.selection.$from;
  var node = $from.node();
  return (0, _prosemirrorCommands.setBlockType)(node.type, _objectSpread(_objectSpread({}, node.attrs), {}, {
    textAlign: alignment
  }))(state, dispatchTransiction);
}

var clearNodes = function clearNodes() {
  return function (state, dispatch) {
    var tr = state.tr;
    var selection = tr.selection;
    var ranges = selection.ranges;
    ranges.forEach(function (range) {
      state.doc.nodesBetween(range.$from.pos, range.$to.pos, function (node, pos) {
        if (node.type.isText) {
          return;
        }

        var $fromPos = tr.doc.resolve(tr.mapping.map(pos));
        var $toPos = tr.doc.resolve(tr.mapping.map(pos + node.nodeSize));
        var nodeRange = $fromPos.blockRange($toPos);

        if (!nodeRange) {
          return;
        }

        var targetLiftDepth = (0, _prosemirrorTransform.liftTarget)(nodeRange);

        if (node.type.isTextblock && dispatch) {
          var _$fromPos$parent$cont = $fromPos.parent.contentMatchAt($fromPos.index()),
              defaultType = _$fromPos$parent$cont.defaultType;

          tr.setNodeMarkup(nodeRange.start, defaultType);
        }

        if ((targetLiftDepth || targetLiftDepth === 0) && dispatch) {
          tr.lift(nodeRange, targetLiftDepth);
        }
      });
    });
    tr.docChanged && dispatch(tr);
    return true;
  };
};

exports.clearNodes = clearNodes;

var filter = function filter(predicates, cmd) {
  return function (state, dispatch, view) {
    if (!Array.isArray(predicates)) {
      predicates = [predicates];
    }

    if (predicates.some(function (pred) {
      return !pred(state, view);
    })) {
      return false;
    }

    return cmd(state, dispatch, view) || false;
  };
};

exports.filter = filter;

var isFirstChildOfParent = function isFirstChildOfParent(state) {
  var $from = state.selection.$from;
  return $from.depth > 1 ? // ? (state.selection instanceof GapCursorSelection &&
  //     $from.parentOffset === 0) ||
  $from.index($from.depth - 1) === 0 : true;
};

exports.isFirstChildOfParent = isFirstChildOfParent;

function findCutBefore($pos) {
  // parent is non-isolating, so we can look across this boundary
  if (!$pos.parent.type.spec.isolating) {
    // search up the tree from the pos's *parent*
    for (var i = $pos.depth - 1; i >= 0; i--) {
      // starting from the inner most node's parent, find out
      // if we're not its first child
      if ($pos.index(i) > 0) {
        return $pos.doc.resolve($pos.before(i + 1));
      }

      if ($pos.node(i).type.spec.isolating) {
        break;
      }
    }
  }

  return null;
}

var isEmptySelectionAtStart = function isEmptySelectionAtStart(state) {
  var _state$selection = state.selection,
      empty = _state$selection.empty,
      $from = _state$selection.$from;
  return empty && $from.parentOffset === 0;
};

exports.isEmptySelectionAtStart = isEmptySelectionAtStart;

var isEmptySelectionAtEnd = function isEmptySelectionAtEnd(state) {
  var _state$selection2 = state.selection,
      empty = _state$selection2.empty,
      $from = _state$selection2.$from;
  return empty && $from.end() === $from.pos;
};

exports.isEmptySelectionAtEnd = isEmptySelectionAtEnd;

/**
 * Walk backwards from a position until we encounter the (inside) end of
 * the previous node, or reach the start of the document.
 *
 * @param $startPos Position to start walking from.
 */
var walkPrevNode = function walkPrevNode($startPos) {
  var $pos = $startPos;

  while ($pos.pos > 0 && ($pos.pos === $startPos.pos || $pos.parentOffset < $pos.parent.nodeSize - 2)) {
    $pos = $pos.doc.resolve($pos.pos - 1);
  }

  return {
    $pos: $pos,
    foundNode: $pos.pos > 0
  };
};

exports.walkPrevNode = walkPrevNode;

var walkNextNode = function walkNextNode($startPos) {
  var $pos = $startPos; // invariant 1: don't walk past the end of the document
  // invariant 2: we are at the beginning or
  //              we haven't walked to the start of *any* node
  //              parentOffset includes textOffset.

  while ($pos.pos < $pos.doc.nodeSize - 2 && ($pos.pos === $startPos.pos || $pos.parentOffset > 0)) {
    $pos = $pos.doc.resolve($pos.pos + 1);
  }

  return {
    $pos: $pos,
    foundNode: $pos.pos < $pos.doc.nodeSize - 2
  };
};
/**
 * Insert content, delete a range and create a new selection
 * This function automatically handles the mapping of positions for insertion and deletion.
 * The new selection is handled as a function since it may not always be necessary to resolve a position to the transactions mapping
 *
 * @param getSelectionResolvedPos get the resolved position to create a new selection
 * @param insertions content to insert at the specified position
 * @param deletions the ranges to delete
 */


exports.walkNextNode = walkNextNode;

var insertContentDeleteRange = function insertContentDeleteRange(tr, getSelectionResolvedPos, insertions, deletions) {
  insertions.forEach(function (contentInsert) {
    var _contentInsert = _slicedToArray(contentInsert, 2),
        content = _contentInsert[0],
        pos = _contentInsert[1];

    tr.insert(tr.mapping.map(pos), content);
  });
  deletions.forEach(function (deleteRange) {
    var _deleteRange = _slicedToArray(deleteRange, 2),
        firstPos = _deleteRange[0],
        lastPos = _deleteRange[1];

    tr["delete"](tr.mapping.map(firstPos), tr.mapping.map(lastPos));
  });
  tr.setSelection(new _prosemirrorState.TextSelection(getSelectionResolvedPos(tr)));
};

exports.insertContentDeleteRange = insertContentDeleteRange;

var selectNode = function selectNode(pos) {
  return function (state, dispatch) {
    if (dispatch) {
      dispatch(state.tr.setSelection(new _prosemirrorState.NodeSelection(state.doc.resolve(pos))));
    }

    return true;
  };
};

exports.selectNode = selectNode;