@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
107 lines (90 loc) • 2.81 kB
text/typescript
import {
Fragment,
Node as PMNode,
Schema,
} from '../../prosemirror';
import { Serializer } from '../serializer';
const HARDBREAK_NODE_TYPE = 'hardBreak';
const IGNORE_NODE_TYPES = [
'bulletList',
'orderedList',
'heading',
'rule',
'panel',
'table',
];
interface Node {
content?: Node[];
text?: string;
}
const getText = (node: PMNode): string => {
return node.type.name === HARDBREAK_NODE_TYPE
? '\n'
: node.attrs.text || node.attrs.shortName || node.text;
};
const reduceTree = (fragment: Fragment): Node[] => {
let fragmentContainsInlineNodes = false;
let textChunks = '';
let childrenChunks: Node[] = [];
let prevNodeType: string;
fragment.forEach(node => {
fragmentContainsInlineNodes = fragmentContainsInlineNodes || node.isInline;
if (fragmentContainsInlineNodes) {
if (prevNodeType === HARDBREAK_NODE_TYPE && node.type.name === HARDBREAK_NODE_TYPE) {
// pass: ignore multiple hardBreaks
} else {
textChunks += getText(node);
}
} else {
if (IGNORE_NODE_TYPES.indexOf(node.type.name) !== -1) {
// pass: ignore these nodes
} else if (!node.childCount) {
childrenChunks.push({ text: getText(node) } as Node);
} else if (node.type.name === 'mediaGroup') {
// count children which are media files
// ignore card links
let childMediaFilesCount = 0;
node.content.forEach(childNode => {
if (childNode.attrs.type === 'file') {
childMediaFilesCount += 1;
}
});
if (childMediaFilesCount) {
const postfix = childMediaFilesCount > 1 ? 'Files' : 'File';
childrenChunks.push({ text: `📎 ${childMediaFilesCount} ${postfix}` } as Node);
}
} else if (node.type.name === 'blockquote') {
childrenChunks.push({
content: reduceTree(node.content),
text: '> ',
});
} else {
childrenChunks.push({ content: reduceTree(node.content) });
}
}
prevNodeType = node.type.name;
});
return fragmentContainsInlineNodes
? [{ text: textChunks } as Node]
: childrenChunks;
};
const serializeTree = (node: Node): string => {
if (node.content) {
return node.content!.map(childNode => {
return (node.text || '') + serializeTree(childNode);
}).join('\n');
}
return node.text!;
};
const serializeFragment = (fragment: Fragment): string => {
const tree: Node = { content: reduceTree(fragment) };
return serializeTree(tree);
};
export default class TextSerializer implements Serializer<string> {
serializeFragment(fragment: Fragment): string {
return serializeFragment(fragment);
}
static fromSchema(schema: Schema<any, any>): TextSerializer {
return new TextSerializer();
}
}