@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
449 lines (437 loc) • 18.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _eventDispatcher = require("@atlaskit/editor-common/event-dispatcher");
var _processRawValue = require("@atlaskit/editor-common/process-raw-value");
var _analytics2 = require("@atlaskit/editor-common/utils/analytics");
var _model = require("@atlaskit/editor-prosemirror/model");
var _state = require("@atlaskit/editor-prosemirror/state");
var _utils = require("@atlaskit/editor-prosemirror/utils");
var _action = require("../utils/action");
var _deprecationWarnings = _interopRequireDefault(require("../utils/deprecation-warnings"));
var _nodesByLocalIds = require("../utils/nodes-by-localIds");
var _tempIsEmptyDocument = require("./temp-is-empty-document");
var _tempNodesByLocalids = require("./temp-nodes-by-localids");
var _tempToJson = require("./temp-to-json");
// eslint-disable-next-line import/order
// eslint-disable-next-line import/order
// Please, do not copy or use this kind of code below
// @ts-ignore
var fakePluginKey = {
key: 'nativeCollabProviderPlugin$',
getState: function getState(state) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return state['nativeCollabProviderPlugin$'];
}
};
/**
* @deprecated {@link https://hello.atlassian.net/browse/ENGHEALTH-26729 Internal documentation for deprecation (no external access)} Editor actions is no longer supported and will be removed in a future version. Please use the core actions, or Plugin APIs directly instead
* @example If you were using editorActions.getValue() replace with:
const { editorApi, preset } = usePreset(...);
editorApi?.core.actions.requestDocument((doc) => {
// use doc as desired
})
* If you were using editorActions.getNodeByLocalId(localId) replace with:
const { editorApi, preset } = usePreset(...);
const extensionAPI = editorAPI?.extension?.actions?.api();
// Use nodeWithPos as desired
const nodeWithPos = extensionAPI.getNodeWithPosByLocalId(localId);
const node = nodeWithPos.node;
const nodePos = nodeWithPos.pos;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var EditorActions = exports.default = /*#__PURE__*/function () {
function EditorActions() {
var _this = this;
(0, _classCallCheck2.default)(this, EditorActions);
(0, _defineProperty2.default)(this, "listeners", []);
(0, _defineProperty2.default)(this, "dispatchAnalyticsEvent", function (payload) {
if (_this.eventDispatcher) {
var dispatch = (0, _eventDispatcher.createDispatch)(_this.eventDispatcher);
dispatch(_analytics2.analyticsEventKey, {
payload: payload
});
}
});
/**
* If editor is using new collab service,
* we want editor to call the collab provider to
* retrieve the final acknowledged state of the
* editor. The final acknowledged editor state
* refers to the latest state of editor with confirmed
* steps.
*/
(0, _defineProperty2.default)(this, "getResolvedEditorState", /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(reason) {
var _this$getFeatureFlags, useNativeCollabPlugin, editorValue, editorView, collabEditState;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_this$getFeatureFlags = _this.getFeatureFlags(), useNativeCollabPlugin = _this$getFeatureFlags.useNativeCollabPlugin;
if (_this.editorView) {
_context.next = 3;
break;
}
throw new Error('Called getResolvedEditorState before editorView is ready');
case 3:
if (useNativeCollabPlugin) {
_context.next = 10;
break;
}
_context.next = 6;
return _this.getValue();
case 6:
editorValue = _context.sent;
if (editorValue) {
_context.next = 9;
break;
}
throw new Error('editorValue is undefined');
case 9:
return _context.abrupt("return", {
content: editorValue,
title: null,
stepVersion: -1
});
case 10:
editorView = _this.editorView;
_context.next = 13;
return (0, _action.getEditorValueWithMedia)(editorView);
case 13:
collabEditState = fakePluginKey.getState(editorView.state);
return _context.abrupt("return", collabEditState === null || collabEditState === void 0 ? void 0 : collabEditState.getFinalAcknowledgedState(reason));
case 15:
case "end":
return _context.stop();
}
}, _callee);
}));
return function (_x) {
return _ref.apply(this, arguments);
};
}());
}
return (0, _createClass2.default)(EditorActions, [{
key: "_privateGetEditorView",
value:
//#region private
// This method needs to be public for context based helper components.
function _privateGetEditorView() {
return this.editorView;
}
}, {
key: "_privateGetEventDispatcher",
value: function _privateGetEventDispatcher() {
return this.eventDispatcher;
}
}, {
key: "getFeatureFlags",
value: function getFeatureFlags() {
return {};
}
// This method needs to be public for EditorContext component.
}, {
key: "_privateRegisterEditor",
value: function _privateRegisterEditor(editorView, eventDispatcher, contentTransformer) {
var getFeatureFlags = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {
return {};
};
this.contentTransformer = contentTransformer;
this.eventDispatcher = eventDispatcher;
this.getFeatureFlags = getFeatureFlags;
if (!this.editorView && editorView) {
this.editorView = editorView;
this.listeners.forEach(function (cb) {
return cb(editorView, eventDispatcher);
});
} else if (this.editorView !== editorView) {
throw new Error("Editor has already been registered! It's not allowed to re-register editor with the new Editor instance.");
}
if (this.contentTransformer) {
this.contentEncode = this.contentTransformer.encode.bind(this.contentTransformer);
}
}
// This method needs to be public for EditorContext component.
}, {
key: "_privateUnregisterEditor",
value: function _privateUnregisterEditor() {
this.editorView = undefined;
this.contentTransformer = undefined;
this.contentEncode = undefined;
this.eventDispatcher = undefined;
this.getFeatureFlags = function () {
return {};
};
}
}, {
key: "_privateSubscribe",
value: function _privateSubscribe(cb) {
// If editor is registered and somebody is trying to add a listener,
// just call it first.
if (this.editorView && this.eventDispatcher) {
cb(this.editorView, this.eventDispatcher);
}
this.listeners.push(cb);
}
}, {
key: "_privateUnsubscribe",
value: function _privateUnsubscribe(cb) {
this.listeners = this.listeners.filter(function (c) {
return c !== cb;
});
}
//#endregion
}, {
key: "focus",
value: function focus() {
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
scrollIntoView: true
},
scrollIntoView = _ref2.scrollIntoView;
if (!this.editorView || this.editorView.hasFocus()) {
return false;
}
this.editorView.focus();
if (scrollIntoView !== null && scrollIntoView !== void 0 ? scrollIntoView : true) {
this.editorView.dispatch(this.editorView.state.tr.scrollIntoView());
}
return true;
}
}, {
key: "blur",
value: function blur() {
if (!this.editorView || !this.editorView.hasFocus()) {
return false;
}
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
this.editorView.dom.blur();
return true;
}
}, {
key: "clear",
value: function clear() {
if (!this.editorView) {
return false;
}
var editorView = this.editorView;
var state = editorView.state;
var tr = editorView.state.tr.setSelection(_state.TextSelection.create(state.doc, 0, state.doc.nodeSize - 2)).deleteSelection();
editorView.dispatch(tr);
return true;
}
// eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
/**
* @deprecated This is deprecated and is no longer maintained.
*
* Use the `requestDocument` API from `editorAPI` (ie. `editorApi?.core?.actions.requestDocument( ... ))
* it has inbuilt throttling and is designed for use with `ComposableEditor`.
*
* Docs on its usage are available from: https://atlaskit.atlassian.com/packages/editor/editor-core
*
* WARNING: this may be called repeatedly, async with care
*/
}, {
key: "getValue",
value: function () {
var _getValue = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
var editorView, doc, json, nodeSanitized;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
editorView = this.editorView;
if (editorView) {
_context2.next = 3;
break;
}
return _context2.abrupt("return");
case 3:
_context2.next = 5;
return (0, _action.getEditorValueWithMedia)(editorView);
case 5:
doc = _context2.sent;
json = (0, _tempToJson.toJSON)(doc);
if (this.contentEncode) {
_context2.next = 9;
break;
}
return _context2.abrupt("return", json);
case 9:
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
nodeSanitized = _model.Node.fromJSON(this.editorView.state.schema, json);
_context2.prev = 10;
return _context2.abrupt("return", this.contentEncode(nodeSanitized));
case 14:
_context2.prev = 14;
_context2.t0 = _context2["catch"](10);
this.dispatchAnalyticsEvent({
action: _analytics.ACTION.DOCUMENT_PROCESSING_ERROR,
actionSubject: _analytics.ACTION_SUBJECT.EDITOR,
eventType: _analytics.EVENT_TYPE.OPERATIONAL,
attributes: {
errorMessage: "".concat(_context2.t0 instanceof Error && _context2.t0.name === 'NodeNestingTransformError' ? 'NodeNestingTransformError - Failed to encode one or more nested tables' : undefined)
}
});
throw _context2.t0;
case 18:
case "end":
return _context2.stop();
}
}, _callee2, this, [[10, 14]]);
}));
function getValue() {
return _getValue.apply(this, arguments);
}
return getValue;
}() // eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
/**
* @deprecated - please use `getNodeWithPosByLocalId` found in the core plugin actions instead
* @example
const { editorApi, preset } = usePreset(...);
const extensionAPI = editorAPI?.extension?.actions?.api();
// Use nodeWithPos as desired
const nodeWithPos = extensionAPI.getNodeWithPosByLocalId(localId);
const node = nodeWithPos.node;
const nodePos = nodeWithPos.pos;
*/
}, {
key: "getNodeByLocalId",
value: function getNodeByLocalId(id) {
var _this$editorView;
if ((_this$editorView = this.editorView) !== null && _this$editorView !== void 0 && _this$editorView.state) {
var _this$editorView2;
var nodes = (0, _tempNodesByLocalids.findNodePosByLocalIds)((_this$editorView2 = this.editorView) === null || _this$editorView2 === void 0 ? void 0 : _this$editorView2.state, [id]);
var node = nodes.length >= 1 ? nodes[0] : undefined;
return node === null || node === void 0 ? void 0 : node.node;
}
}
}, {
key: "getNodeByFragmentLocalId",
value: function getNodeByFragmentLocalId(id) {
var _this$editorView3;
if ((_this$editorView3 = this.editorView) !== null && _this$editorView3 !== void 0 && _this$editorView3.state) {
var _this$editorView4;
var nodes = (0, _nodesByLocalIds.findNodePosByFragmentLocalIds)((_this$editorView4 = this.editorView) === null || _this$editorView4 === void 0 ? void 0 : _this$editorView4.state, [id]);
return nodes.length > 0 ? nodes[0].node : undefined;
}
}
/**
* This method will return the currently selected `Node` if the selection is a `Node`.
* Otherwise, if the selection is textual or a non-selectable `Node` within another selectable `Node`, the closest selectable parent `Node` will be returned.
*/
}, {
key: "getSelectedNode",
value: function getSelectedNode() {
var _this$editorView5;
if ((_this$editorView5 = this.editorView) !== null && _this$editorView5 !== void 0 && (_this$editorView5 = _this$editorView5.state) !== null && _this$editorView5 !== void 0 && _this$editorView5.selection) {
var _findParentNode;
var selection = this.editorView.state.selection;
if (selection instanceof _state.NodeSelection) {
return selection.node;
}
return (_findParentNode = (0, _utils.findParentNode)(function (node) {
return Boolean(node.type.spec.selectable);
})(selection)) === null || _findParentNode === void 0 ? void 0 : _findParentNode.node;
}
}
}, {
key: "isDocumentEmpty",
value: function isDocumentEmpty() {
// Unlikely case when editorView has been destroyed before calling isDocumentEmpty,
// we treat this case as if document was empty.
if (!this.editorView) {
return true;
}
return (0, _tempIsEmptyDocument.isEmptyDocument)(this.editorView.state.doc);
}
// eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
/**
* @deprecated - please use `replaceDocument` found in the core plugin actions instead
* using this will reset your Editor State which could cause some things to break (like emojis)
* @example - use the `replaceDocument` from the core plugin actions instead
* ```ts
* const { editorApi, preset } = usePreset(...);
// where you need it
editorApi?.core.actions.replaceDocument(value);
return <ComposableEditor preset={preset} ... />
*/
}, {
key: "replaceDocument",
value: function replaceDocument(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rawValue) {
var shouldScrollToBottom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var shouldAddToHistory = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
(0, _deprecationWarnings.default)('EditorActions.replaceDocument', {
shouldAddToHistory: shouldAddToHistory
}, [{
property: 'shouldAddToHistory',
description: '[ED-14158] EditorActions.replaceDocument does not use the shouldAddToHistory arg',
type: 'removed'
}]);
if (!this.editorView || rawValue === undefined || rawValue === null) {
return false;
}
if (this.eventDispatcher) {
this.eventDispatcher.emit('resetEditorState', {
doc: rawValue,
shouldScrollToBottom: shouldScrollToBottom
});
}
return true;
}
}, {
key: "replaceSelection",
value: function replaceSelection(rawValue, tryToReplace, position) {
if (!this.editorView) {
return false;
}
var state = this.editorView.state;
if (!rawValue) {
var tr = state.tr.deleteSelection().scrollIntoView();
this.editorView.dispatch(tr);
return true;
}
var schema = state.schema;
var content = Array.isArray(rawValue) ? (0, _processRawValue.processRawFragmentValue)(schema, rawValue, undefined, undefined, undefined, this.dispatchAnalyticsEvent) : (0, _processRawValue.processRawValue)(schema, rawValue, undefined, undefined, undefined, this.dispatchAnalyticsEvent);
if (!content) {
return false;
}
// try to find a place in the document where to insert a node if its not allowed at the cursor position by schema
this.editorView.dispatch((0, _utils.safeInsert)(content, position, tryToReplace)(state.tr).scrollIntoView());
return true;
}
}, {
key: "appendText",
value: function appendText(text) {
if (!this.editorView || !text) {
return false;
}
var state = this.editorView.state;
var lastChild = state.doc.lastChild;
if (lastChild && lastChild.type !== state.schema.nodes.paragraph) {
return false;
}
var tr = state.tr.insertText(text).scrollIntoView();
this.editorView.dispatch(tr);
return true;
}
}], [{
key: "from",
value: function from(view, eventDispatcher, transformer) {
var editorActions = new EditorActions();
editorActions._privateRegisterEditor(view, eventDispatcher, transformer);
return editorActions;
}
}]);
}();