"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.selectCellByGrid = exports.pasteContentIntoTable = exports.jumpOutTableInEditor = exports.isSelectingMultipleTables = exports.isInTable = exports.isDisabled = exports.insertTable = exports.getTableFocusingInfos = exports.getTableEntry = exports.getSelectedTableCells = exports.getSelectGrid = exports.getContextMenuPosition = void 0;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
var _slate = require("slate");
var _slateReact = require("slate-react");
var _isUrl = _interopRequireDefault(require("is-url"));
var _model = require("./model");
var _elementTypes = require("../../constants/element-types");
var _core = require("../../core");
var _getEventTransfer = _interopRequireDefault(require("../../../containers/custom/get-event-transfer"));
var _deserializeHtml = require("../../../utils/deserialize-html");
var _common = require("../../../utils/common");
var _helper = require("../link/helper");
var _helper2 = require("../image/helper");
const isDisabled = (editor, readonly) => {
  const {
    selection
  } = editor;
  if (readonly || !selection) return true;
  const disableTypes = [_elementTypes.TABLE, _elementTypes.TABLE_ROW, _elementTypes.TABLE_CELL, _elementTypes.FORMULA, _elementTypes.CODE_BLOCK, _elementTypes.COLUMN, _elementTypes.BLOCKQUOTE, _elementTypes.UNORDERED_LIST, _elementTypes.ORDERED_LIST, _elementTypes.LIST_ITEM];
  const [nodeEntry] = _slate.Editor.nodes(editor, {
    match: n => disableTypes.includes(n.type),
    mode: 'highest'
  });
  if (nodeEntry) return true;
  return false;
};
exports.isDisabled = isDisabled;
const isInTable = editor => {
  const {
    selection
  } = editor;
  if (!selection) return false;
  const [nodeEntry] = getTableEntry(editor);
  if (!nodeEntry) return false;
  return true;
};
exports.isInTable = isInTable;
const insertTable = (editor, rowNum, columnNum) => {
  const table = (0, _model.generateTable)({
    rowNum,
    columnNum
  });
  const {
    selection
  } = editor;
  _slate.Editor.insertNode(editor, table, {
    select: false
  });
  if (_slate.Range.isCollapsed(selection)) {
    const [paragraphNodeEntry] = _slate.Editor.nodes(editor, {
      at: selection.anchor.path,
      match: n => n.type === _elementTypes.PARAGRAPH && _slate.Node.string(n).length === 0
    });
    if (paragraphNodeEntry) {
      const paragraphPath = paragraphNodeEntry[1];
      if (paragraphPath.length === 1 && paragraphPath[0] !== 0) {
        _slate.Transforms.removeNodes(editor, {
          at: paragraphPath
        });
      }
    }
  }

  // Auto focus at the first cell in table
  const [nodeEntry] = _slate.Editor.nodes(editor, {
    match: node => node.id === table.id,
    mode: 'highest'
  });
  const focusPoint = _slate.Editor.start(editor, nodeEntry[1]);
  (0, _core.focusEditor)(editor, focusPoint);
};
exports.insertTable = insertTable;
const getTableFocusingInfos = editor => {
  if (!isInTable(editor)) return null;
  const nodeEntries = _slate.Editor.nodes(editor, {
    match: n => [_elementTypes.TABLE, _elementTypes.TABLE_ROW, _elementTypes.TABLE_CELL].includes(n.type)
  });
  const nodeEntryList = Array.from(nodeEntries);
  const [tableEntry, rowEntry, cellEntry] = nodeEntryList;
  const columnIndex = cellEntry[1].at(-1);
  const rowIndex = cellEntry[1].at(-2);
  return {
    cellEntry,
    tableEntry,
    rowEntry,
    columnIndex,
    rowIndex
  };
};
exports.getTableFocusingInfos = getTableFocusingInfos;
const selectCellByGrid = (editor, rowIndex, colIndex) => {
  const {
    tableEntry: [, tablePath]
  } = getTableFocusingInfos(editor);
  const selectRange = _slate.Editor.range(editor, tablePath.concat(rowIndex, colIndex));
  (0, _core.focusEditor)(editor, selectRange);
};
exports.selectCellByGrid = selectCellByGrid;
const getSelectedTableCells = editor => {
  const [tableEntry] = getTableEntry(editor);
  if (!tableEntry) return null;
  const [tableNode] = tableEntry;
  const tableRows = tableNode.children;
  const selectGrid = getSelectGrid(editor);
  if (!selectGrid) return null;
  const {
    startRowIndex,
    endRowIndex,
    startColIndex,
    endColIndex
  } = selectGrid;
  const selectedTableRows = [];
  for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {
    const currentRow = tableRows[rowIndex];
    let selectedTableCells = [];
    for (let colIndex = startColIndex; colIndex <= endColIndex; colIndex++) {
      const currentCell = currentRow.children[colIndex];
      selectedTableCells.push(currentCell);
    }
    selectedTableRows.push((0, _model.generateTableRow)({
      childrenOrText: selectedTableCells
    }));
    selectedTableCells = [];
  }
  return [(0, _model.generateTable)({
    childrenOrText: selectedTableRows
  })];
};
exports.getSelectedTableCells = getSelectedTableCells;
const getSelectGrid = editor => {
  const [tableEntry] = getTableEntry(editor);
  if (!tableEntry) return null;
  const selectedTableCells = document.querySelectorAll('.selected-cell');
  if (selectedTableCells.length === 0) return null;
  const node = _slateReact.ReactEditor.toSlateNode(editor, selectedTableCells[0]);
  const nodePath = _slateReact.ReactEditor.findPath(editor, node);
  if (!_slate.Path.isAncestor(tableEntry[1], nodePath)) return null;
  const selectGrid = Array.from(selectedTableCells).reduce((grid, cell) => {
    const {
      startRowIndex,
      endRowIndex,
      startColIndex,
      endColIndex
    } = grid;
    const {
      cellIndex: colIndex
    } = cell;
    const {
      rowIndex
    } = cell.parentNode;
    if (endRowIndex === -1 || rowIndex > endRowIndex) grid.endRowIndex = rowIndex;
    if (startRowIndex === -1 || rowIndex < startRowIndex) grid.startRowIndex = rowIndex;
    if (endColIndex === -1 || colIndex > endColIndex) grid.endColIndex = colIndex;
    if (startColIndex === -1 || colIndex < startColIndex) grid.startColIndex = colIndex;
    return (0, _objectSpread2.default)({}, grid);
  }, {
    startRowIndex: -1,
    endRowIndex: -1,
    startColIndex: -1,
    endColIndex: -1
  });
  return selectGrid;
};
exports.getSelectGrid = getSelectGrid;
const pasteContentIntoTable = (editor, content) => {
  const data = content;
  let {
    fragment,
    text,
    type,
    html
  } = (0, _getEventTransfer.default)(data);
  const newText = text.replace(/\r\n|\n/g, ' ');
  if (!fragment && type === 'text') {
    if ((0, _isUrl.default)(text) && !(0, _common.isImage)(text)) {
      const link = (0, _helper.generateLinkNode)(text, text);
      _slate.Editor.insertFragment(editor, [link], {
        select: true
      });
      return;
    } else if ((0, _isUrl.default)(text) && (0, _common.isImage)(text)) {
      (0, _helper2.insertImage)(editor, text);
      return;
    }
    _slate.Transforms.insertText(editor, newText);
    return;
  }
  if (type === 'html') {
    fragment = (0, _deserializeHtml.htmlDeserializer)(html);
  }
  if (fragment.length === 1) {
    if (fragment[0].type === _elementTypes.TABLE) {
      const clipboardTable = fragment[0];
      const {
        tableEntry: [tableNode, tablePath],
        rowEntry: [rowNode],
        rowIndex,
        columnIndex
      } = getTableFocusingInfos(editor);
      const tableWidth = rowNode.children.length;
      const tableHeight = tableNode.children.length;
      clipboardTable.children.some((clipRow, clipRowIndex) => {
        const currentInsertPath = tablePath.concat(rowIndex + clipRowIndex + rowIndex);
        // Out of table
        if (rowIndex + clipRowIndex >= tableHeight + 1) return true;
        clipRow.children.some((clipCol, clipColIndex) => {
          // Out of table
          if (columnIndex + clipColIndex >= tableWidth + 1) return true;
          const currentCellPath = currentInsertPath.concat(columnIndex + clipColIndex);
          const currentCellChildPath = currentCellPath.concat(0);
          _slate.Transforms.removeNodes(editor, {
            at: currentCellChildPath
          });
          if (clipCol.children.type !== _elementTypes.PARAGRAPH) {
            const text = _slate.Node.string(clipCol);
            const newChild = (0, _core.generateElement)(_elementTypes.PARAGRAPH, {
              childrenOrText: text
            });
            _slate.Transforms.insertNodes(editor, newChild, {
              at: currentCellChildPath
            });
          } else {
            _slate.Transforms.insertNodes(editor, clipCol.children, {
              at: currentCellChildPath
            });
          }
          return false;
        });
        return false;
      });
    } else if (fragment[0].type === _elementTypes.PARAGRAPH) {
      (0, _slate.insertFragment)(editor, fragment);
    } else {
      _slate.Transforms.insertText(editor, text.replace(/\r\n|\n/g, ' '));
    }
  }
};
exports.pasteContentIntoTable = pasteContentIntoTable;
const jumpOutTableInEditor = editor => {
  const [tableEntry] = getTableEntry(editor);
  if (!tableEntry) return;
  const [, tablePath] = tableEntry;
  const tableParentPath = _slate.Path.parent(tablePath);
  const insertPath = tableParentPath.concat(tablePath.at(-1) + 1);
  _slate.Transforms.insertNodes(editor, (0, _core.generateElement)(_elementTypes.PARAGRAPH), {
    at: insertPath
  });
  _slate.Transforms.select(editor, {
    path: insertPath.concat(0),
    offset: 0
  });
};
exports.jumpOutTableInEditor = jumpOutTableInEditor;
const getTableEntry = editor => {
  return _slate.Editor.nodes(editor, {
    match: n => n.type === _elementTypes.TABLE,
    mode: 'highest'
  });
};
exports.getTableEntry = getTableEntry;
const isSelectingMultipleTables = editor => {
  let selectedTableCount = 0;
  const selectedElems = (0, _core.getSelectedElems)(editor);
  const isSelectedMultiple = selectedElems.some(elem => {
    if (elem.type === _elementTypes.TABLE) selectedTableCount++;
    if (selectedTableCount > 1) return true;
    return false;
  });
  return isSelectedMultiple;
};
exports.isSelectingMultipleTables = isSelectingMultipleTables;
const getContextMenuPosition = (event, tableRef) => {
  const menuHeight = 240;
  const menuWidth = 350;
  const {
    clientHeight,
    clientWidth
  } = document.body; // page
  const {
    x,
    y
  } = tableRef.current.getBoundingClientRect(); // table
  const {
    clientY,
    clientX
  } = event; // cursor

  const isBeyondBottom = clientY + menuHeight > clientHeight;
  const isBeyondRight = clientX + menuWidth > clientWidth;
  const defaultTop = clientY - y;
  const defaultLeft = clientX - x;
  let top = 0;
  let left = 0;
  if (isBeyondBottom) {
    const hiddenHeight = menuHeight - (clientHeight - clientY);
    top = defaultTop - hiddenHeight;
  }
  if (isBeyondRight) {
    const hiddenWidth = menuWidth - (clientWidth - clientX);
    left = defaultLeft - hiddenWidth;
  }
  if (!isBeyondBottom && !isBeyondRight) {
    return {
      top: defaultTop,
      left: defaultLeft
    };
  }
  if (isBeyondBottom && isBeyondRight) {
    return {
      top,
      left
    };
  }
  if (isBeyondBottom) {
    return {
      top,
      left: defaultLeft
    };
  }
  return {
    top: defaultTop,
    left
  };
};
exports.getContextMenuPosition = getContextMenuPosition;