"use strict";

function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.enterKeyCommand = exports.deleteKeyCommand = exports.backspaceKeyCommand = void 0;
Object.defineProperty(exports, "indentList", {
  enumerable: true,
  get: function get() {
    return _indentList.indentList;
  }
});
exports.insertContentDeleteRange = void 0;
Object.defineProperty(exports, "outdentList", {
  enumerable: true,
  get: function get() {
    return _outdentList.outdentList;
  }
});
exports.rootListDepth = void 0;
exports.toggleBulletList = toggleBulletList;
exports.toggleList = toggleList;
exports.toggleOrderedList = toggleOrderedList;

var _prosemirrorModel = require("prosemirror-model");

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

var baseCommand = _interopRequireWildcard(require("prosemirror-commands"));

var _prosemirrorUtils = require("prosemirror-utils");

var _document = require("../../../../utils/document");

var _commands = require("../../../../utils/commands");

var _mark = require("../../../../utils/mark");

var _transforms = require("../transforms");

var _selection = require("../utils/selection");

var _listBackspace = require("./listBackspace");

var _joinListItemForward = require("./join-list-item-forward");

var _conversions = require("../actions/conversions");

var _wrapAndJoinLists = require("../actions/wrap-and-join-lists");

var _outdentList = require("./outdent-list");

var _indentList = require("./indent-list");

var _replaceContent = require("../utils/replace-content");

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

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; }

// export type InputMethod = INPUT_METHOD.KEYBOARD | INPUT_METHOD.TOOLBAR;

/**
 * Implementation taken and modified for our needs from PM
 * @param itemType Node
 * Splits the list items, specific implementation take from PM
 */
function splitListItem(itemType) {
  return function (state, dispatch) {
    var ref = state.selection;
    var $from = ref.$from;
    var $to = ref.$to;
    var node = ref.node;

    if (node && node.isBlock || $from.depth < 2 || !$from.sameParent($to)) {
      return false;
    }

    var grandParent = $from.node(-1);

    if (grandParent.type !== itemType) {
      return false;
    }
    /** --> The following line changed from the original PM implementation to allow list additions with multiple paragraphs */


    if (grandParent.content.content.length <= 1 && $from.parent.content.size === 0 && !(grandParent.content.size === 0)) {
      // In an empty block. If this is a nested list, the wrapping
      // list item should be split. Otherwise, bail out and let next
      // command handle lifting.
      if ($from.depth === 2 || $from.node(-3).type !== itemType || $from.index(-2) !== $from.node(-2).childCount - 1) {
        return false;
      }

      if (dispatch) {
        var wrap = _prosemirrorModel.Fragment.empty;
        var keepItem = $from.index(-1) > 0; // Build a fragment containing empty versions of the structure
        // from the outer list item to the parent node of the cursor

        for (var d = $from.depth - (keepItem ? 1 : 2); d >= $from.depth - 3; d -= 1) {
          wrap = _prosemirrorModel.Fragment.from($from.node(d).copy(wrap));
        } // Add a second list item with an empty default start node


        wrap = wrap.append(_prosemirrorModel.Fragment.from(itemType.createAndFill()));
        var tr$1 = state.tr.replace($from.before(keepItem ? undefined : -1), $from.after(-3), new _prosemirrorModel.Slice(wrap, keepItem ? 3 : 2, 2));
        tr$1.setSelection(state.selection.constructor.near(tr$1.doc.resolve($from.pos + (keepItem ? 3 : 2))));
        dispatch(tr$1.scrollIntoView());
      }

      return true;
    }

    var nextType = $to.pos === $from.end() ? grandParent.contentMatchAt(0).defaultType : undefined;
    var tr = state.tr["delete"]($from.pos, $to.pos);
    var types = nextType && [undefined, {
      type: nextType
    }];

    if (dispatch) {
      dispatch(tr.split($from.pos, 2, types).scrollIntoView());
    }

    return true;
  };
}

var deletePreviousEmptyListItem = function deletePreviousEmptyListItem(state, dispatch) {
  var $from = state.selection.$from;
  var listItem = state.schema.nodes.listItem;
  var $cut = (0, _commands.findCutBefore)($from);

  if (!$cut || !$cut.nodeBefore || !($cut.nodeBefore.type === listItem)) {
    return false;
  }

  var previousListItemEmpty = $cut.nodeBefore.childCount === 1 && $cut.nodeBefore.firstChild.nodeSize <= 2;

  if (previousListItemEmpty) {
    var tr = state.tr;

    if (dispatch) {
      dispatch(tr["delete"]($cut.pos - $cut.nodeBefore.nodeSize, $from.pos).scrollIntoView());
    }

    return true;
  }

  return false;
};

var enterKeyCommand = function enterKeyCommand(state, dispatch) {
  var selection = state.selection;

  if (selection.empty) {
    var $from = selection.$from;
    var _state$schema$nodes = state.schema.nodes,
        listItem = _state$schema$nodes.listItem,
        codeBlock = _state$schema$nodes.codeBlock;
    var node = $from.node($from.depth);
    var wrapper = $from.node($from.depth - 1);

    if (wrapper && wrapper.type === listItem) {
      /** Check if the wrapper has any visible content */
      var wrapperHasContent = (0, _document.hasVisibleContent)(wrapper);

      if ((0, _document.isNodeEmpty)(node) && !wrapperHasContent) {
        return (0, _outdentList.outdentList)()(state, dispatch);
      }

      if (!(0, _prosemirrorUtils.hasParentNodeOfType)(codeBlock)(selection)) {
        return splitListItem(listItem)(state, dispatch);
      }
    }
  }

  return false;
};

exports.enterKeyCommand = enterKeyCommand;

var joinToPreviousListItem = function joinToPreviousListItem(state, dispatch) {
  var $from = state.selection.$from;
  var _state$schema$nodes2 = state.schema.nodes,
      paragraph = _state$schema$nodes2.paragraph,
      codeBlock = _state$schema$nodes2.codeBlock,
      bulletList = _state$schema$nodes2.bulletList,
      orderedList = _state$schema$nodes2.orderedList; // const isGapCursorShown = state.selection instanceof GapCursorSelection;

  var $cutPos =
  /* isGapCursorShown ? state.doc.resolve($from.pos + 1) : */
  $from;
  var $cut = (0, _commands.findCutBefore)($cutPos);

  if (!$cut) {
    return false;
  } // see if the containing node is a list


  if ($cut.nodeBefore && [bulletList, orderedList].indexOf($cut.nodeBefore.type) > -1) {
    // and the node after this is a paragraph or a codeBlock
    if ($cut.nodeAfter && ($cut.nodeAfter.type === paragraph || $cut.nodeAfter.type === codeBlock)) {
      // find the nearest paragraph that precedes this node
      var $lastNode = $cut.doc.resolve($cut.pos - 1);

      while ($lastNode.parent.type !== paragraph) {
        $lastNode = state.doc.resolve($lastNode.pos - 1);
      }

      var tr = state.tr; // if (isGapCursorShown) {
      //   const nodeBeforePos = findPositionOfNodeBefore(tr.selection);
      //   if (typeof nodeBeforePos !== 'number') {
      //     return false;
      //   }
      //   // append the codeblock to the list node
      //   const list = $cut.nodeBefore.copy(
      //     $cut.nodeBefore.content.append(
      //       Fragment.from(listItem.createChecked({}, $cut.nodeAfter)),
      //     ),
      //   );
      //   tr.replaceWith(
      //     nodeBeforePos,
      //     $from.pos + $cut.nodeAfter.nodeSize,
      //     list,
      //   );
      // } else {

      var step = (0, _replaceContent.moveTargetIntoList)({
        insertPosition: $lastNode.pos,
        $target: $cut
      }); // ED-13966: check if the step will cause an ProseMirror error
      // if there's an error don't apply the step as it will might lead into a data loss.
      // It doesn't play well with media being a leaf node.

      var stepResult = state.tr.maybeStep(step);

      if (stepResult.failed) {
        return false;
      }

      tr = state.tr.step(step); // }
      // find out if there's now another list following and join them
      // as in, [list, p, list] => [list with p, list], and we want [joined list]

      var $postCut = tr.doc.resolve(tr.mapping.map($cut.pos + $cut.nodeAfter.nodeSize));

      if ($postCut.nodeBefore && $postCut.nodeAfter && $postCut.nodeBefore.type === $postCut.nodeAfter.type && [bulletList, orderedList].indexOf($postCut.nodeBefore.type) > -1) {
        tr = tr.join($postCut.pos);
      }

      if (dispatch) {
        dispatch(tr.scrollIntoView());
      }

      return true;
    }
  }

  return false;
};

var backspaceKeyCommand = function backspaceKeyCommand(state, dispatch) {
  return baseCommand.chainCommands(_listBackspace.listBackspace, // if we're at the start of a list item, we need to either backspace
  // directly to an empty list item above, or outdent this node
  (0, _commands.filter)([_commands.isEmptySelectionAtStart, // list items might have multiple paragraphs; only do this at the first one
  _commands.isFirstChildOfParent, _selection.isInsideListItem], baseCommand.chainCommands(deletePreviousEmptyListItem, (0, _outdentList.outdentList)())), // if we're just inside a paragraph node (or gapcursor is shown) and backspace, then try to join
  // the text to the previous list item, if one exists
  (0, _commands.filter)([function (state) {
    return state.selection.empty;
  }, _selection.canJoinToPreviousListItem], joinToPreviousListItem))(state, dispatch);
};

exports.backspaceKeyCommand = backspaceKeyCommand;
var deleteKeyCommand = _joinListItemForward.joinListItemForward; // Get the depth of the nearest ancestor list

exports.deleteKeyCommand = deleteKeyCommand;

var rootListDepth = function rootListDepth(pos, nodes) {
  var bulletList = nodes.bulletList,
      orderedList = nodes.orderedList,
      listItem = nodes.listItem;
  var depth;

  for (var i = pos.depth - 1; i > 0; i -= 1) {
    var node = pos.node(i);

    if (node.type === bulletList || node.type === orderedList) {
      depth = i;
    }

    if (node.type !== bulletList && node.type !== orderedList && node.type !== listItem) {
      break;
    }
  }

  return depth;
};

exports.rootListDepth = rootListDepth;

function untoggleSelectedList(tr) {
  var selection = tr.selection;
  var depth = rootListDepth(selection.$to, tr.doc.type.schema.nodes);
  var newtr = (0, _transforms.liftFollowingList)(selection.$to.pos, selection.$to.end(depth), depth || 0, tr);
  newtr = (0, _transforms.liftSelectionList)(selection, tr);
  return newtr;
}

function toggleList(listType) {
  return function (state, dispatch) {
    var tr = state.tr;
    var listInsideSelection = (0, _selection.selectionContainsList)(tr);
    var listNodeType = state.schema.nodes[listType];

    if (listInsideSelection) {
      var selection = state.selection;
      var fromNode = selection.$from.node(selection.$from.depth - 2);
      var toNode = selection.$to.node(selection.$to.depth - 2);

      if ((fromNode === null || fromNode === void 0 ? void 0 : fromNode.type.name) === listType && (toNode === null || toNode === void 0 ? void 0 : toNode.type.name) === listType) {
        var _tr = state.tr;
        _tr = untoggleSelectedList(_tr);

        if (dispatch) {
          dispatch(_tr);
        }

        return true;
      }

      (0, _conversions.convertListType)({
        tr: tr,
        nextListNodeType: listNodeType
      });
    } else {
      // Need to have this before wrapInList so the wrapping is done with valid content
      // For example, if trying to convert centre or right aligned paragraphs to lists
      (0, _mark.sanitiseMarksInSelection)(tr, listNodeType);
      (0, _wrapAndJoinLists.wrapInListAndJoin)(listNodeType, tr);
    } // If document wasn't changed, return false from the command to indicate that the
    // editing action failed


    if (!tr.docChanged) {
      return false;
    }

    if (dispatch) {
      dispatch(tr);
    }

    return true;
  };
}

function toggleBulletList(view) {
  return toggleList("bulletList")(view.state, view.dispatch);
}

function toggleOrderedList(view) {
  return toggleList("orderedList")(view.state, view.dispatch);
}

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;