"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _slate = require("slate");
var _isHotkey = _interopRequireDefault(require("is-hotkey"));
var _helper = require("./helper");
var _constants = require("../../constants");
var _setEventTransfer = _interopRequireDefault(require("../../../containers/custom/set-event-transfer"));
var _elementTypes = require("../../constants/element-types");
var _tableOperations = require("./table-operations");
var _getEventTransfer = _interopRequireDefault(require("../../../containers/custom/get-event-transfer"));
var _eventBus = _interopRequireDefault(require("../../../utils/event-bus"));
var _eventTypes = require("../../../constants/event-types");
var _core = require("../../core");
/**
 * @param {Editor} editor
 */
const withTable = editor => {
  const {
    insertBreak,
    deleteBackward,
    onHotKeyDown,
    insertText,
    deleteForward,
    onCopy,
    insertData,
    insertFragment,
    normalizeNode
  } = editor;
  const newEditor = editor;
  newEditor.insertBreak = () => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!editor.selection || !isTableActive) return insertBreak && insertBreak();
    (0, _tableOperations.insertRow)(newEditor);
    const [nodeEntry] = _slate.Editor.nodes(newEditor, {
      match: n => _slate.Element.isElement(n) && n.type === _elementTypes.TABLE_ROW
    });
    const path = _slate.Path.next(nodeEntry[1]);
    const firstCellPath = path.concat(0);
    _slate.Transforms.select(newEditor, firstCellPath);
    return;
  };
  newEditor.insertText = text => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!isTableActive) return insertText && insertText(text);
    const {
      selection
    } = newEditor;
    // set element by markdown shortcut;
    if (text === ' ' && selection && _slate.Range.isCollapsed(selection)) {
      insertText(text);
      return;
    }
    return insertText(text);
  };
  newEditor.insertData = data => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!isTableActive) return insertData && insertData(data);
    const {
      type
    } = (0, _getEventTransfer.default)(data);
    if (type === 'file') {
      return insertData(data);
    }
    return (0, _helper.pasteContentIntoTable)(newEditor, data);
  };
  newEditor.insertFragment = fragment => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!isTableActive) return insertFragment && insertFragment(fragment);
    if (!Array.isArray(fragment)) return;
    const firstChild = fragment[0];
    if (fragment.length === 1 && firstChild.type === _elementTypes.TABLE) {
      const {
        tableEntry,
        rowEntry
      } = (0, _helper.getTableFocusingInfos)(editor);
      let selectedInfo = (0, _helper.getSelectGrid)(editor);
      if (!selectedInfo) {
        const tableCellEntry = (0, _core.getSelectedNodeEntryByType)(editor, _elementTypes.TABLE_CELL);
        if (!tableCellEntry) return;
        const [, path] = tableCellEntry;
        const startColIndex = path.pop();
        const startRowIndex = path.pop();
        selectedInfo = {
          startRowIndex,
          startColIndex
        };
      }
      const {
        startRowIndex,
        startColIndex
      } = selectedInfo;
      const [tableNode, tablePath] = tableEntry;
      const [rowNode] = rowEntry;
      const tableWidth = rowNode.children.length;
      const tableHeight = tableNode.children.length;
      firstChild.children.forEach((clipRow, clipRowIndex) => {
        // Out of table
        if (startRowIndex + clipRowIndex >= tableHeight) return true;

        // rowPath = [...tablePath, rowIndex + clipRowIndex];
        const currentRowPath = [...tablePath, startRowIndex + clipRowIndex];
        clipRow.children.forEach((clipCol, clipColIndex) => {
          // Out of table
          if (startColIndex + clipColIndex >= tableWidth) return true;

          // cellPath = [...rowPath, columnIndex + clipColIndex];
          const currentCellPath = [...currentRowPath, startColIndex + clipColIndex];
          const currentCellChildPath = currentCellPath.concat(0);
          _slate.Transforms.removeNodes(editor, {
            at: currentCellChildPath
          });
          const otherBlockTypes = [..._constants.HEADERS, _elementTypes.CHECK_LIST_ITEM, _elementTypes.PARAGRAPH];
          const newChildren = clipCol.children.map(item => {
            if (otherBlockTypes.includes(item.type)) return item.children;
            return item;
          }).flat();
          _slate.Transforms.insertNodes(editor, newChildren, {
            at: currentCellChildPath
          });
          return false;
        });
        return false;
      });
      return;
    }
    const notSupportTypes = [_elementTypes.TABLE, _elementTypes.BLOCKQUOTE, _elementTypes.UNORDERED_LIST, _elementTypes.ORDERED_LIST, _elementTypes.CODE_BLOCK];
    const isDataValid = fragment.some(item => notSupportTypes.includes(item.type));
    if (isDataValid) {
      const strContent = fragment.reduce((ret, item) => {
        return ret + _slate.Node.string(item);
      }, '');
      _slate.Editor.insertText(newEditor, strContent);
      return;
    }
    const otherBlockTypes = [..._constants.HEADERS, _elementTypes.CHECK_LIST_ITEM, _elementTypes.PARAGRAPH];
    const newChildren = fragment.map(item => {
      if (otherBlockTypes.includes(item.type)) return item.children;
      return item;
    }).flat();
    insertFragment(newChildren);
  };
  newEditor.deleteBackward = unit => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!isTableActive) return deleteBackward(unit);
    const {
      selection
    } = newEditor;
    // If select range,prevent to delete
    if (!_slate.Range.isRange(selection)) return;
    const [tableCellEntry] = _slate.Editor.nodes(editor, {
      match: node => node.type === _elementTypes.TABLE_CELL,
      mode: 'lowest'
    });
    // If delete empty cell,prevent to delete
    const isStartOfCellText = _slate.Editor.isStart(newEditor, selection.anchor, tableCellEntry[1]);
    if (isStartOfCellText) return;
    return deleteBackward && deleteBackward(unit);
  };
  newEditor.deleteForward = unit => {
    const isTableActive = (0, _helper.isInTable)(newEditor);
    if (!isTableActive) return deleteForward(unit);
    const {
      selection
    } = newEditor;
    // If select range,prevent to delete
    if (!_slate.Range.isRange(selection)) return;
    const [tableCellEntry] = _slate.Editor.nodes(editor, {
      match: node => node.type === _elementTypes.TABLE_CELL,
      mode: 'lowest'
    });
    // If delete empty cell,prevent to delete
    const isEndOfCellText = _slate.Editor.isEnd(newEditor, selection.anchor, tableCellEntry[1]);
    if (isEndOfCellText) return;
    return deleteForward(unit);
  };
  newEditor.onHotKeyDown = event => {
    if (!(0, _helper.isInTable)(newEditor)) return onHotKeyDown && onHotKeyDown(event);
    if ((0, _isHotkey.default)('tab', event)) {
      if (newEditor.hasMovedSelection) event.stopPropagation();
      event.preventDefault();
      const {
        tableEntry: [tableNode],
        rowEntry: [rowNode],
        columnIndex,
        rowIndex
      } = (0, _helper.getTableFocusingInfos)(newEditor);
      let nextColumnIndex;
      let nextRowIndex;
      // If focus not at end of columns
      if (columnIndex < rowNode.children.length - 1) {
        nextColumnIndex = columnIndex + 1;
        nextRowIndex = rowIndex;
      } else {
        // If focus not at end of rows,add new row
        const shouldAddNewRow = rowIndex === tableNode.children.length - 1;
        nextColumnIndex = 0;
        nextRowIndex = rowIndex + 1;
        shouldAddNewRow && (0, _tableOperations.insertRow)(newEditor, _constants.INSERT_POSITION.AFTER);
      }
      (0, _helper.selectCellByGrid)(newEditor, nextRowIndex, nextColumnIndex);
      return true;
    }
    if ((0, _isHotkey.default)('shift+tab', event)) {
      if (newEditor.hasMovedSelection) event.stopPropagation();
      event.preventDefault();
      const {
        rowEntry: [rowNode],
        columnIndex,
        rowIndex
      } = (0, _helper.getTableFocusingInfos)(newEditor);
      let previousColumnIndex;
      let previousRowIndex;
      // If focus not at start of columns
      if (columnIndex > 0) {
        previousRowIndex = rowIndex;
        previousColumnIndex = columnIndex - 1;
      } else {
        // If focus not at start of rows
        if (rowIndex > 0) {
          previousRowIndex = rowIndex - 1;
          previousColumnIndex = rowNode.children.length - 1;
        } else {
          previousRowIndex = 0;
          previousColumnIndex = 0;
        }
      }
      (0, _helper.selectCellByGrid)(newEditor, previousRowIndex, previousColumnIndex);
      return true;
    }
    if ((0, _isHotkey.default)('mod+enter', event) || (0, _isHotkey.default)('shift+enter', event)) {
      event.preventDefault();
      (0, _helper.jumpOutTableInEditor)(newEditor);
      return true;
    }
    if ((0, _isHotkey.default)('mod+a', event)) {
      event.preventDefault();
      const {
        tableEntry: [tableNode],
        rowEntry: [rowNode]
      } = (0, _helper.getTableFocusingInfos)(newEditor);
      const rowCount = tableNode.children.length;
      const colCount = rowNode.children.length;
      (0, _helper.selectCellByGrid)(newEditor, rowCount - 1, colCount - 1);
      const eventBus = _eventBus.default.getInstance();
      eventBus.dispatch(_eventTypes.INTERNAL_EVENTS.ON_SELECT_ALL_CELL, tableNode.id);
      return true;
    }
    if ((0, _isHotkey.default)('delete', event) || (0, _isHotkey.default)('backspace', event)) {
      const selectedInfo = (0, _helper.getSelectGrid)(newEditor);
      if (!selectedInfo) return onHotKeyDown && onHotKeyDown(event);
      const {
        startRowIndex,
        endRowIndex,
        startColIndex,
        endColIndex
      } = selectedInfo;
      if (startRowIndex === -1 || endRowIndex === -1 || startColIndex === -1 || endColIndex === -1) return;
      const [tableEntry] = (0, _helper.getTableEntry)(newEditor);
      const [, tablePath] = tableEntry;
      for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {
        for (let colIndex = startColIndex; colIndex <= endColIndex; colIndex++) {
          _slate.Transforms.insertText(newEditor, '', {
            at: tablePath.concat(rowIndex, colIndex)
          });
        }
      }
      return true;
    }
    return onHotKeyDown && onHotKeyDown(event);
  };
  newEditor.onCopy = event => {
    if (!(0, _helper.isInTable)(newEditor)) {
      return onCopy && onCopy(event);
    }
    event.preventDefault();
    event.stopPropagation();
    // selected multiple cells
    const tableNode = (0, _helper.getSelectedTableCells)(newEditor);
    if (tableNode) {
      (0, _setEventTransfer.default)(event, 'fragment', tableNode);
      return true;
    }
    // selected only one cell
    const tableCell = (0, _core.getSelectedNodeByType)(newEditor, _elementTypes.TABLE_CELL);
    if (tableCell) {
      const selection = window.getSelection();
      const selectedText = selection.toString();
      const range = selection.getRangeAt(0);
      const selectedContent = range.cloneContents();
      const div = document.createElement('div');
      // Unwrap image wrapper
      selectedContent.childNodes.forEach(node => {
        if (node.classList && node.classList.contains('sf-image-wrapper')) {
          const img = node.querySelector('img');
          div.appendChild(img.cloneNode(true));
          return;
        }
        div.appendChild(node.cloneNode(true));
      });
      (0, _setEventTransfer.default)(event, 'text', selectedText);
      (0, _setEventTransfer.default)(event, 'html', div.innerHTML.toString());
      return true;
    }
    return false;
  };
  newEditor.normalizeNode = _ref => {
    let [node, path] = _ref;
    if (node.type === _elementTypes.TABLE) {
      const isLast = (0, _core.isLastNode)(newEditor, node);
      if (isLast) {
        const paragraph = (0, _core.generateEmptyElement)(_elementTypes.PARAGRAPH);
        _slate.Transforms.insertNodes(newEditor, paragraph, {
          at: [path[0] + 1]
        });
      }
      const isFirst = (0, _core.isFirstNode)(newEditor, node);
      if (isFirst) {
        const paragraph = (0, _core.generateEmptyElement)(_elementTypes.PARAGRAPH);
        _slate.Transforms.insertNodes(newEditor, paragraph, {
          at: [path[0]]
        });
      }
    }
    if (node.type === _elementTypes.TABLE_ROW) {
      const parentEntry = _slate.Editor.parent(editor, path);
      if ((parentEntry === null || parentEntry === void 0 ? void 0 : parentEntry[0].type) !== _elementTypes.TABLE) {
        (0, _slate.unwrapNodes)(editor, {
          at: path
        });
        return;
      }
    }
    if (node.type === _elementTypes.TABLE_CELL) {
      const parentEntry = _slate.Editor.parent(editor, path);
      if ((parentEntry === null || parentEntry === void 0 ? void 0 : parentEntry[0].type) !== _elementTypes.TABLE_ROW) {
        (0, _slate.unwrapNodes)(editor, {
          at: path
        });
        return;
      }
    }
    return normalizeNode([node, path]);
  };
  return newEditor;
};
var _default = exports.default = withTable;