"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.stateKey = exports.plugin = exports["default"] = exports.canLinkBeCreatedInRange = exports.LinkAction = exports.InsertStatus = void 0;

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

var _helpers = require("../../../../utils/helpers");

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

var LinkAction;
exports.LinkAction = LinkAction;

(function (LinkAction) {
  LinkAction["SHOW_INSERT_TOOLBAR"] = "SHOW_INSERT_TOOLBAR";
  LinkAction["HIDE_TOOLBAR"] = "HIDE_TOOLBAR";
  LinkAction["SELECTION_CHANGE"] = "SELECTION_CHANGE";
  LinkAction["INSERT_LINK_TOOLBAR"] = "INSERT";
  LinkAction["EDIT_INSERTED_TOOLBAR"] = "EDIT_INSERTED_TOOLBAR";
})(LinkAction || (exports.LinkAction = LinkAction = {}));

var InsertStatus;
exports.InsertStatus = InsertStatus;

(function (InsertStatus) {
  InsertStatus["EDIT_LINK_TOOLBAR"] = "EDIT";
  InsertStatus["INSERT_LINK_TOOLBAR"] = "INSERT";
  InsertStatus["EDIT_INSERTED_TOOLBAR"] = "EDIT_INSERTED";
})(InsertStatus || (exports.InsertStatus = InsertStatus = {}));

var canLinkBeCreatedInRange = function canLinkBeCreatedInRange(from, to) {
  return function (state) {
    if (!state.doc.rangeHasMark(from, to, state.schema.marks.link)) {
      var $from = state.doc.resolve(from);
      var $to = state.doc.resolve(to);
      var link = state.schema.marks.link;

      if ($from.parent === $to.parent && $from.parent.isTextblock) {
        if ($from.parent.type.allowsMarkType(link)) {
          var allowed = true;
          state.doc.nodesBetween(from, to, function (node) {
            allowed = allowed && !node.marks.some(function (m) {
              return m.type.excludes(link);
            });
            return allowed;
          });
          return allowed;
        }
      }
    }

    return false;
  };
};

exports.canLinkBeCreatedInRange = canLinkBeCreatedInRange;

var isSelectionInsideLink = function isSelectionInsideLink(state) {
  return !!state.doc.type.schema.marks.link.isInSet(state.selection.$from.marks());
};

var isSelectionAroundLink = function isSelectionAroundLink(state) {
  var _state$selection = state.selection,
      $from = _state$selection.$from,
      $to = _state$selection.$to;
  var node = $from.nodeAfter;
  return !!node && $from.textOffset === 0 && $to.pos - $from.pos === node.nodeSize && !!state.doc.type.schema.marks.link.isInSet(node.marks);
};

var mapTransactionToState = function mapTransactionToState(state, tr) {
  if (!state) {
    return undefined;
  } else if (state.type === InsertStatus.EDIT_LINK_TOOLBAR || state.type === InsertStatus.EDIT_INSERTED_TOOLBAR) {
    var _tr$mapping$mapResult = tr.mapping.mapResult(state.pos, 1),
        pos = _tr$mapping$mapResult.pos,
        deleted = _tr$mapping$mapResult.deleted;

    var node = tr.doc.nodeAt(pos); // If the position was not deleted & it is still a link

    if (!deleted && !!node.type.schema.marks.link.isInSet(node.marks)) {
      if (node === state.node && pos === state.pos) {
        return state;
      }

      return _objectSpread(_objectSpread({}, state), {}, {
        pos: pos,
        node: node
      });
    } // If the position has been deleted, then require a navigation to show the toolbar again


    return;
  } else if (state.type === InsertStatus.INSERT_LINK_TOOLBAR) {
    return _objectSpread(_objectSpread({}, state), {}, {
      from: tr.mapping.map(state.from),
      to: tr.mapping.map(state.to)
    });
  }

  return;
};

var toState = function toState(state, action, editorState) {
  // Show insert or edit toolbar
  if (!state) {
    switch (action) {
      case LinkAction.SHOW_INSERT_TOOLBAR:
        {
          var _editorState$selectio = editorState.selection,
              from = _editorState$selectio.from,
              to = _editorState$selectio.to;

          if (canLinkBeCreatedInRange(from, to)(editorState)) {
            return {
              type: InsertStatus.INSERT_LINK_TOOLBAR,
              from: from,
              to: to
            };
          }

          return undefined;
        }

      case LinkAction.SELECTION_CHANGE:
        // If the user has moved their cursor, see if they're in a link
        var link = getActiveLinkMark(editorState);

        if (link) {
          return _objectSpread(_objectSpread({}, link), {}, {
            type: InsertStatus.EDIT_LINK_TOOLBAR
          });
        }

        return undefined;

      default:
        return undefined;
    }
  } // Update toolbar state if selection changes, or if toolbar is hidden


  if (state.type === InsertStatus.EDIT_LINK_TOOLBAR) {
    switch (action) {
      case LinkAction.EDIT_INSERTED_TOOLBAR:
        {
          var _link2 = getActiveLinkMark(editorState);

          if (_link2) {
            if (_link2.pos === state.pos && _link2.node === state.node) {
              return _objectSpread(_objectSpread({}, state), {}, {
                type: InsertStatus.EDIT_INSERTED_TOOLBAR
              });
            }

            return _objectSpread(_objectSpread({}, _link2), {}, {
              type: InsertStatus.EDIT_INSERTED_TOOLBAR
            });
          }

          return undefined;
        }

      case LinkAction.SELECTION_CHANGE:
        var _link = getActiveLinkMark(editorState);

        if (_link) {
          if (_link.pos === state.pos && _link.node === state.node) {
            // Make sure we return the same object, if it's the same link
            return state;
          }

          return _objectSpread(_objectSpread({}, _link), {}, {
            type: InsertStatus.EDIT_LINK_TOOLBAR
          });
        }

        return undefined;

      case LinkAction.HIDE_TOOLBAR:
        return undefined;

      default:
        return state;
    }
  } // Remove toolbar if user changes selection or toolbar is hidden


  if (state.type === InsertStatus.INSERT_LINK_TOOLBAR) {
    switch (action) {
      case LinkAction.SELECTION_CHANGE:
      case LinkAction.HIDE_TOOLBAR:
        return undefined;

      default:
        return state;
    }
  }

  return;
};

var getActiveLinkMark = function getActiveLinkMark(state) {
  var $from = state.selection.$from;

  if (isSelectionInsideLink(state) || isSelectionAroundLink(state)) {
    var pos = $from.pos - $from.textOffset;
    var node = state.doc.nodeAt(pos);
    return node && node.isText ? {
      node: node,
      pos: pos
    } : undefined;
  }

  return undefined;
};

var getActiveText = function getActiveText(selection) {
  var currentSlice = selection.content();

  if (currentSlice.size === 0) {
    return;
  }

  if (currentSlice.content.childCount === 1 && currentSlice.content.firstChild && selection instanceof _prosemirrorState.TextSelection) {
    return currentSlice.content.firstChild.textContent;
  }

  return;
};

var stateKey = new _prosemirrorState.PluginKey('hyperlinkPlugin');
exports.stateKey = stateKey;

var plugin = function plugin(dispatch) {
  return new _prosemirrorState.Plugin({
    state: {
      init: function init(_, state) {
        var canInsertLink = canLinkBeCreatedInRange(state.selection.from, state.selection.to)(state);
        return {
          activeText: getActiveText(state.selection),
          canInsertLink: canInsertLink,
          activeLinkMark: toState(undefined, LinkAction.SELECTION_CHANGE, state)
        };
      },
      apply: function apply(tr, pluginState, _oldState, newState) {
        var state = pluginState;
        var action = tr.getMeta(stateKey) && tr.getMeta(stateKey).type;

        if (tr.docChanged) {
          state = {
            activeText: state.activeText,
            canInsertLink: canLinkBeCreatedInRange(newState.selection.from, newState.selection.to)(newState),
            activeLinkMark: mapTransactionToState(state.activeLinkMark, tr)
          };
        }

        if (action) {
          state = {
            activeText: state.activeText,
            canInsertLink: state.canInsertLink,
            activeLinkMark: toState(state.activeLinkMark, action, newState)
          };
        }

        if (tr.selectionSet) {
          state = {
            activeText: getActiveText(newState.selection),
            canInsertLink: canLinkBeCreatedInRange(newState.selection.from, newState.selection.to)(newState),
            activeLinkMark: toState(state.activeLinkMark, LinkAction.SELECTION_CHANGE, newState)
          };
        }

        if (!(0, _helpers.shallowEqual)(state, pluginState)) {
          dispatch(stateKey, state);
        }

        return state;
      }
    },
    key: stateKey
  });
};

exports.plugin = plugin;
var _default = plugin;
exports["default"] = _default;