"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
Object.defineProperty(exports, "atTheBeginningOfDoc", {
  enumerable: true,
  get: function get() {
    return _atTheBeginningOfDoc.atTheBeginningOfDoc;
  }
});
Object.defineProperty(exports, "atTheEndOfDoc", {
  enumerable: true,
  get: function get() {
    return _atTheEndOfDoc.atTheEndOfDoc;
  }
});
exports.createNewParagraphBelow = exports.createNewParagraphAbove = void 0;
exports.createParagraphNear = createParagraphNear;
exports.deleteEmptyParagraphAndMoveBlockUp = void 0;
Object.defineProperty(exports, "filter", {
  enumerable: true,
  get: function get() {
    return _filter.filter;
  }
});
Object.defineProperty(exports, "filterCommand", {
  enumerable: true,
  get: function get() {
    return _filter.filter;
  }
});
Object.defineProperty(exports, "insertContentDeleteRange", {
  enumerable: true,
  get: function get() {
    return _insertContentDeleteRange.insertContentDeleteRange;
  }
});
Object.defineProperty(exports, "insertNewLine", {
  enumerable: true,
  get: function get() {
    return _insertNewLine.insertNewLine;
  }
});
exports.walkPrevNode = exports.walkNextNode = exports.isEmptySelectionAtStart = exports.isEmptySelectionAtEnd = exports.insertNewLineWithAnalytics = void 0;
var _state = require("@atlaskit/editor-prosemirror/state");
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
var _analytics = require("../analytics");
var _editorAnalytics = require("../editor-analytics");
var _selection = require("../selection");
var _atTheBeginningOfDoc = require("./atTheBeginningOfDoc");
var _atTheEndOfDoc = require("./atTheEndOfDoc");
var _filter = require("./filter");
var _insertNewLine = require("./insertNewLine");
var _isEmptyParagraph = require("./isEmptyParagraph");
var _isMediaNode = require("./isMediaNode");
var _insertContentDeleteRange = require("./insertContentDeleteRange");
/**
 * Walk forwards from a position until we encounter the (inside) start of
 * the next node, or reach the end of the document.
 *
 * @param $startPos Position to start walking from.
 */
var walkNextNode = exports.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
  };
};

/**
 * 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 = exports.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
  };
};
var insertNewLineWithAnalytics = exports.insertNewLineWithAnalytics = function insertNewLineWithAnalytics(editorAnalyticsAPI) {
  return (0, _editorAnalytics.withAnalytics)(editorAnalyticsAPI, {
    action: _analytics.ACTION.INSERTED,
    actionSubject: _analytics.ACTION_SUBJECT.TEXT,
    actionSubjectId: _analytics.ACTION_SUBJECT_ID.LINE_BREAK,
    eventType: _analytics.EVENT_TYPE.TRACK
  })((0, _insertNewLine.insertNewLine)());
};
var createNewParagraphAbove = exports.createNewParagraphAbove = function createNewParagraphAbove(state, dispatch) {
  var append = false;
  if (!canMoveUp(state) && canCreateParagraphNear(state)) {
    createParagraphNear(append)(state, dispatch);
    return true;
  }
  return false;
};
var createNewParagraphBelow = exports.createNewParagraphBelow = function createNewParagraphBelow(state, dispatch) {
  var append = true;
  if (!canMoveDown(state) && canCreateParagraphNear(state)) {
    createParagraphNear(append)(state, dispatch);
    return true;
  }
  return false;
};
function canCreateParagraphNear(state) {
  var $from = state.selection.$from;
  var node = $from.node($from.depth);
  var insideCodeBlock = !!node && node.type === state.schema.nodes.codeBlock;
  var isNodeSelection = state.selection instanceof _state.NodeSelection;
  return $from.depth > 1 || isNodeSelection || insideCodeBlock;
}
function createParagraphNear() {
  var append = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  return function (state, dispatch) {
    var paragraph = state.schema.nodes.paragraph;
    if (!paragraph) {
      return false;
    }
    var insertPos;
    if (state.selection instanceof _state.TextSelection) {
      if (topLevelNodeIsEmptyTextBlock(state)) {
        return false;
      }
      insertPos = getInsertPosFromTextBlock(state, append);
    } else {
      insertPos = getInsertPosFromNonTextBlock(state, append);
    }
    var tr = state.tr.insert(insertPos, paragraph.createAndFill());
    tr.setSelection(_state.TextSelection.create(tr.doc, insertPos + 1));
    if (dispatch) {
      dispatch(tr);
    }
    return true;
  };
}
function getInsertPosFromTextBlock(state, append) {
  var _state$selection = state.selection,
    $from = _state$selection.$from,
    $to = _state$selection.$to;
  var pos;
  if (!append) {
    pos = $from.start(0);
  } else {
    pos = $to.end(0);
  }
  return pos;
}
function getInsertPosFromNonTextBlock(state, append) {
  var _state$selection2 = state.selection,
    $from = _state$selection2.$from,
    $to = _state$selection2.$to;
  var nodeAtSelection = state.selection instanceof _state.NodeSelection && state.doc.nodeAt(state.selection.$anchor.pos);
  var isMediaSelection = nodeAtSelection && nodeAtSelection.type.name === 'mediaGroup';
  var pos;
  if (!append) {
    // The start position is different with text block because it starts from 0
    pos = $from.start($from.depth);
    // The depth is different with text block because it starts from 0
    pos = $from.depth > 0 && !isMediaSelection ? pos - 1 : pos;
  } else {
    pos = $to.end($to.depth);
    pos = $to.depth > 0 && !isMediaSelection ? pos + 1 : pos;
  }
  return pos;
}
function topLevelNodeIsEmptyTextBlock(state) {
  var topLevelNode = state.selection.$from.node(1);
  return topLevelNode.isTextblock && topLevelNode.type !== state.schema.nodes.codeBlock && topLevelNode.nodeSize === 2;
}
function canMoveUp(state) {
  var selection = state.selection;
  /**
   * If there's a media element on the selection it will use a gap cursor to move
   */
  if (selection instanceof _state.NodeSelection && (0, _isMediaNode.isMediaNode)(selection.node)) {
    return true;
  }
  if (selection instanceof _state.TextSelection && !(0, _experiments.editorExperiment)('platform_editor_block_menu', true)) {
    if (!selection.empty) {
      return true;
    }
  }
  return !(0, _atTheBeginningOfDoc.atTheBeginningOfDoc)(state);
}
function canMoveDown(state) {
  var selection = state.selection;

  /**
   * If there's a media element on the selection it will use a gap cursor to move
   */
  if (selection instanceof _state.NodeSelection && (0, _isMediaNode.isMediaNode)(selection.node)) {
    return true;
  }
  if (selection instanceof _state.TextSelection && !(0, _experiments.editorExperiment)('platform_editor_block_menu', true)) {
    if (!selection.empty) {
      return true;
    }
  }
  return !(0, _atTheEndOfDoc.atTheEndOfDoc)(state);
}

/**
 * If the selection is empty, is inside a paragraph node and `canNextNodeMoveUp` is true then delete current paragraph
 * and move the node below it up. The selection will be retained, to be placed in the moved node.
 *
 * @param canNextNodeMoveUp check if node directly after the selection is able to be brought up to selection
 * @returns PM Command
 */
var deleteEmptyParagraphAndMoveBlockUp = exports.deleteEmptyParagraphAndMoveBlockUp = function deleteEmptyParagraphAndMoveBlockUp(canNextNodeMoveUp) {
  return function (state, dispatch, view) {
    var _state$selection3 = state.selection,
      _state$selection3$$fr = _state$selection3.$from,
      pos = _state$selection3$$fr.pos,
      parent = _state$selection3$$fr.parent,
      $head = _state$selection3.$head,
      empty = _state$selection3.empty,
      tr = state.tr,
      doc = state.doc;
    var _walkNextNode = walkNextNode($head),
      $pos = _walkNextNode.$pos;
    var nextPMNode = doc.nodeAt($pos.pos - 1);
    if (empty && nextPMNode && canNextNodeMoveUp(nextPMNode) && (0, _isEmptyParagraph.isEmptyParagraph)(parent) && view !== null && view !== void 0 && view.endOfTextblock('right')) {
      tr.deleteRange(pos - 1, pos + 1);
      if (dispatch) {
        dispatch(tr);
      }
      return true;
    }
    return false;
  };
};

/**
 * Check if the selection is empty and at the start of a task or list item
 * @param state Editor state
 * @returns true if selection is empty and at the start of a task or list item
 */
var isEmptySelectionAtStart = exports.isEmptySelectionAtStart = function isEmptySelectionAtStart(state) {
  var blockTaskItem = state.schema.nodes.blockTaskItem;
  var _state$selection4 = state.selection,
    empty = _state$selection4.empty,
    $from = _state$selection4.$from;

  // If blockTaskItem is in the schema,
  // we need to check if the selection is inside a blockTaskItem
  if (blockTaskItem && empty) {
    // If the parent is in a textblock,
    // check if it's nested inside a blockTaskItem
    if ($from.parent.isTextblock) {
      var $posAtStartOfTextBlock = state.doc.resolve($from.start($from.depth - 1));
      var parentOfTextBlock = $posAtStartOfTextBlock.parent;

      // If the parent of the textblock is a blockTaskItem,
      // we need to if the textblock is the first node in the blockTaskItem
      if (parentOfTextBlock.type === blockTaskItem) {
        var firstChildOfBlockTaskItem = parentOfTextBlock.firstChild;
        if (firstChildOfBlockTaskItem === $from.parent) {
          // If the textblock is the first node in the blockTaskItem,
          // check if the selection is at the start of the textblock
          var firstTextPosInTextBlock = $from.start($from.depth);
          return $from.pos === firstTextPosInTextBlock;
        } else {
          return false;
        }
      }
    }
    // Else, check if the parent is a blockTaskItem
    else if ($from.parent.type === blockTaskItem) {
      // Check if the selection is at the start of the blockTaskItem
      var blockTaskItemDepth = $from.depth;
      var firstPosInBlockTaskItem = $from.start(blockTaskItemDepth);

      // Is the selection at the first possible position inside the blockTaskItem
      return $from.pos === firstPosInBlockTaskItem;
    }
  }
  return empty && ($from.parentOffset === 0 || state.selection instanceof _selection.GapCursorSelection);
};
var isEmptySelectionAtEnd = exports.isEmptySelectionAtEnd = function isEmptySelectionAtEnd(state) {
  var blockTaskItem = state.schema.nodes.blockTaskItem;
  var _state$selection5 = state.selection,
    empty = _state$selection5.empty,
    $from = _state$selection5.$from;

  // If blockTaskItem is in the schema,
  // we need to check if the selection is inside a blockTaskItem
  if (blockTaskItem && empty) {
    // If the parent is in a textblock,
    // check if it's nested inside a blockTaskItem
    if ($from.parent.isTextblock) {
      var $posAtEndOfTextBlock = state.doc.resolve($from.end($from.depth - 1));
      var parentOfTextBlock = $posAtEndOfTextBlock.parent;

      // If the parent of the textblock is a blockTaskItem,
      // we need to know if the textblock is the last node in the blockTaskItem
      if (parentOfTextBlock.type === blockTaskItem) {
        var lastChildOfBlockTaskItem = parentOfTextBlock.lastChild;
        if (lastChildOfBlockTaskItem === $from.parent) {
          // If the textblock is the last node in the blockTaskItem,
          // check if the selection is at the end of the textblock
          var lastTextPosInTextBlock = $from.end($from.depth);
          return $from.pos === lastTextPosInTextBlock;
        } else {
          return false;
        }
      }
    }
    // Else, check if the parent is a blockTaskItem
    else if ($from.parent.type === blockTaskItem) {
      // Check if the selection is at the end of the blockTaskItem
      var lastPosInBlockTaskItem = $from.end();
      return $from.pos === lastPosInBlockTaskItem;
    }
  }
  return empty && ($from.end() === $from.pos || state.selection instanceof _selection.GapCursorSelection);
};

// eslint-disable-next-line @atlaskit/editor/no-re-export

// eslint-disable-next-line @atlaskit/editor/no-re-export

// eslint-disable-next-line @atlaskit/editor/no-re-export

// eslint-disable-next-line @atlaskit/editor/no-re-export

// eslint-disable-next-line @atlaskit/editor/no-re-export

// eslint-disable-next-line @atlaskit/editor/no-re-export