UNPKG

@atlaskit/editor-plugin-code-block

Version:

Code block plugin for @atlaskit/editor-core

173 lines (170 loc) 9.54 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createPlugin = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _browser = require("@atlaskit/editor-common/browser"); var _codeBlock = require("@atlaskit/editor-common/code-block"); var _messages = require("@atlaskit/editor-common/messages"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _selection = require("@atlaskit/editor-common/selection"); var _transforms = require("@atlaskit/editor-common/transforms"); var _state = require("@atlaskit/editor-prosemirror/state"); var _view = require("@atlaskit/editor-prosemirror/view"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _editorCommands = require("../editor-commands"); var _codeBlock2 = require("../nodeviews/code-block"); var _classNames = require("../ui/class-names"); var _actions = require("./actions"); var _decorators = require("./decorators"); var _pluginKey = require("./plugin-key"); var _utils = require("./utils"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var createPlugin = exports.createPlugin = function createPlugin(_ref) { var _ref$useLongPressSele = _ref.useLongPressSelection, useLongPressSelection = _ref$useLongPressSele === void 0 ? false : _ref$useLongPressSele, getIntl = _ref.getIntl, _ref$allowComposition = _ref.allowCompositionInputOverride, allowCompositionInputOverride = _ref$allowComposition === void 0 ? false : _ref$allowComposition, api = _ref.api; var handleDOMEvents = { click: function click() { var _api$core, _api$interaction; // Set hasHadInteraction to true on any click of code blocks, as clicks // on code blocks to not propagate to editor-level click handlers api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$interaction = api.interaction) === null || _api$interaction === void 0 ? void 0 : _api$interaction.commands.handleInteraction); } }; // ME-1599: Composition on mobile was causing the DOM observer to mutate the code block // incorrecly and lose content when pressing enter in the middle of a code block line. if (allowCompositionInputOverride) { handleDOMEvents.beforeinput = function (view, event) { var keyEvent = event; var eventInputType = keyEvent.inputType; var eventText = keyEvent.data; var browser = (0, _browser.getBrowserInfo)(); if (browser.ios && event.composed && // insertParagraph will be the input type when the enter key is pressed. eventInputType === 'insertParagraph' && (0, _transforms.findCodeBlock)(view.state, view.state.selection)) { event.preventDefault(); return true; } else if (browser.android && event.composed && eventInputType === 'insertCompositionText' && eventText[(eventText === null || eventText === void 0 ? void 0 : eventText.length) - 1] === '\n' && (0, _transforms.findCodeBlock)(view.state, view.state.selection)) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any var resultingText = event.target.outerText + '\n'; if (resultingText.endsWith(eventText)) { // End of paragraph setTimeout(function () { view.someProp('handleKeyDown', function (f) { return f(view, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter' })); }); }, 0); } else { // Middle of paragraph, end of line (0, _editorCommands.ignoreFollowingMutations)(view.state, view.dispatch); } return true; } if (browser.android) { (0, _editorCommands.resetShouldIgnoreFollowingMutations)(view.state, view.dispatch); } return false; }; } return new _safePlugin.SafePlugin({ state: { init: function init(_, state) { var node = (0, _transforms.findCodeBlock)(state, state.selection); var initialDecorations = // Disabled when using advanced code block advanced since it interfers with styling // Long term we will deprecate the code block plugin and move all the related logic to // the advanced plugin // @ts-expect-error Code block advanced cannot depend on code block (api === null || api === void 0 ? void 0 : api.codeBlockAdvanced) !== undefined && (0, _expValEquals.expValEquals)('platform_editor_code_block_fold_gutter', 'isEnabled', true) ? [] : (0, _decorators.generateInitialDecorations)(state); return { pos: node ? node.pos : null, contentCopied: false, isNodeSelected: false, shouldIgnoreFollowingMutations: false, decorations: _view.DecorationSet.create(state.doc, initialDecorations) }; }, apply: function apply(tr, pluginState, _oldState, newState) { var meta = tr.getMeta(_pluginKey.pluginKey); if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_IS_WRAPPED) { var node = (0, _transforms.findCodeBlock)(newState, tr.selection); return _objectSpread(_objectSpread({}, pluginState), {}, { decorations: (0, _decorators.updateDecorationSetWithWordWrappedDecorator)(pluginState.decorations, tr, node) }); } if (tr.docChanged) { var _node = (0, _transforms.findCodeBlock)(newState, tr.selection); // Updates mapping position of all existing decorations to new positions // specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does). var updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc); var codeBlockNodes = (0, _utils.getAllChangedCodeBlocksInTransaction)(tr); if (codeBlockNodes) { (0, _codeBlock.updateCodeBlockWrappedStateNodeKeys)(codeBlockNodes, _oldState); // Disabled when using advanced code block for performance reasons // @ts-expect-error Code block advanced cannot depend on code block if ((api === null || api === void 0 ? void 0 : api.codeBlockAdvanced) === undefined) { updatedDecorationSet = (0, _decorators.updateCodeBlockDecorations)(tr, codeBlockNodes, updatedDecorationSet); } } var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, { pos: _node ? _node.pos : null, isNodeSelected: tr.selection instanceof _state.NodeSelection, decorations: updatedDecorationSet }); return newPluginState; } if (tr.selectionSet) { var _node2 = (0, _transforms.findCodeBlock)(newState, tr.selection); var _newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, { pos: _node2 ? _node2.pos : null, isNodeSelected: tr.selection instanceof _state.NodeSelection }); return _newPluginState; } if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_COPIED_TO_CLIPBOARD) { return _objectSpread(_objectSpread({}, pluginState), {}, { contentCopied: meta.data }); } else if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_SHOULD_IGNORE_FOLLOWING_MUTATIONS) { return _objectSpread(_objectSpread({}, pluginState), {}, { shouldIgnoreFollowingMutations: meta.data }); } return pluginState; } }, key: _pluginKey.pluginKey, props: { decorations: function decorations(state) { return _pluginKey.pluginKey.getState(state).decorations || _view.DecorationSet.empty; }, nodeViews: { codeBlock: function codeBlock(node, view, getPos) { var _getIntl = getIntl(), formatMessage = _getIntl.formatMessage; var formattedAriaLabel = formatMessage(_messages.blockTypeMessages.codeblock); return (0, _codeBlock2.codeBlockNodeView)(node, view, getPos, formattedAriaLabel, api); } }, handleClickOn: (0, _selection.createSelectionClickHandler)(['codeBlock'], function (target) { return !!(target.classList.contains(_classNames.codeBlockClassNames.lineNumberWidget) || target.classList.contains(_classNames.codeBlockClassNames.gutter)); }, { useLongPressSelection: useLongPressSelection }), handleDOMEvents: handleDOMEvents } }); };