@atlaskit/editor-plugin-code-block
Version:
Code block plugin for @atlaskit/editor-core
80 lines (75 loc) • 3.64 kB
JavaScript
import { GapCursorSelection } from '@atlaskit/editor-common/selection';
import { mapSlice, timestampToString } from '@atlaskit/editor-common/utils';
import { Fragment } from '@atlaskit/editor-prosemirror/model';
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
export function transformToCodeBlockAction(state, start,
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
attrs) {
var startOfCodeBlockText = state.selection.$from;
var endPosition = state.selection.empty && !(state.selection instanceof GapCursorSelection) ? startOfCodeBlockText.end() : state.selection.$to.pos;
var startLinePosition = startOfCodeBlockText.start();
//when cmd+A is used to select the content. start position should be 0.
var parentStartPosition = startOfCodeBlockText.depth === 0 ? 0 : startOfCodeBlockText.before();
var contentSlice = state.doc.slice(startOfCodeBlockText.pos, endPosition);
var codeBlockSlice = mapSlice(contentSlice, function (node, parent, index) {
if (node.type === state.schema.nodes.hardBreak) {
return state.schema.text('\n');
}
if (node.isText) {
return node.mark([]);
}
if (node.isInline) {
// Convert dates
if (node.attrs.timestamp) {
return state.schema.text(timestampToString(node.attrs.timestamp, null));
}
// Convert links
if (node.attrs.url) {
return state.schema.text(node.attrs.url);
}
return node.attrs.text ? state.schema.text(node.attrs.text) : null;
}
// if the current node is the last child of the Slice exit early to prevent
// adding additional line breaks
if (contentSlice.content.childCount - 1 === index) {
return node.content;
}
//useful to decide whether to append line breaks when the content has list items.
var isParentLastChild = parent && contentSlice.content.childCount - 1 === index;
// add line breaks at the end of each paragraph to mimic layout of selected content
// do not add line breaks when the 'paragraph' parent is last child.
if (node.content.childCount && node.type === state.schema.nodes.paragraph && !isParentLastChild) {
return node.content.append(Fragment.from(state.schema.text('\n\n')));
}
return node.content.childCount ? node.content : null;
});
var tr = state.tr;
// Replace current block node
var startMapped = startLinePosition === start ? parentStartPosition : start;
var codeBlock = state.schema.nodes.codeBlock;
var codeBlockNode = codeBlock.createChecked(attrs, codeBlockSlice.content);
tr.replaceWith(startMapped, Math.min(endPosition, tr.doc.content.size), codeBlockNode);
// Reposition cursor when inserting into layouts or table headers
var mapped = tr.doc.resolve(tr.mapping.map(startMapped) + 1);
var selection = TextSelection.findFrom(mapped, state.selection instanceof GapCursorSelection ? -1 : 1, true);
if (selection) {
return tr.setSelection(selection);
}
return tr.setSelection(TextSelection.create(tr.doc, Math.min(start + startOfCodeBlockText.node().nodeSize - 1, tr.doc.content.size)));
}
export function isConvertableToCodeBlock(state) {
// Before a document is loaded, there is no selection.
if (!state.selection) {
return false;
}
var $from = state.selection.$from;
var node = $from.parent;
if (!node.isTextblock || node.type === state.schema.nodes.codeBlock) {
return false;
}
var parentDepth = $from.depth - 1;
var parentNode = $from.node(parentDepth);
var index = $from.index(parentDepth);
return parentNode.canReplaceWith(index, index + 1, state.schema.nodes.codeBlock);
}