Files
docmost/apps/server/src/common/helpers/prosemirror/utils.ts
Philip Okugbe de7982fe30 feat: copy page to different space (#1118)
* Add copy page to space endpoint
* copy storage function
* copy function
* feat: copy attachments too
* Copy page - WIP
* fix type
* sync
* cleanup
2025-04-30 14:43:16 +01:00

130 lines
3.1 KiB
TypeScript

import { Node } from '@tiptap/pm/model';
import {
jsonToNode,
tiptapExtensions,
} from '../../../collaboration/collaboration.util';
import { validate as isValidUUID } from 'uuid';
import { Transform } from '@tiptap/pm/transform';
import { TiptapTransformer } from '@hocuspocus/transformer';
import * as Y from 'yjs';
export interface MentionNode {
id: string;
label: string;
entityType: 'user' | 'page';
entityId: string;
creatorId: string;
}
export function extractMentions(prosemirrorJson: any) {
const mentionList: MentionNode[] = [];
const doc = jsonToNode(prosemirrorJson);
doc.descendants((node: Node) => {
if (node.type.name === 'mention') {
if (
node.attrs.id &&
!mentionList.some((mention) => mention.id === node.attrs.id)
) {
mentionList.push({
id: node.attrs.id,
label: node.attrs.label,
entityType: node.attrs.entityType,
entityId: node.attrs.entityId,
creatorId: node.attrs.creatorId,
});
}
}
});
return mentionList;
}
export function extractUserMentions(mentionList: MentionNode[]): MentionNode[] {
const userList = [];
for (const mention of mentionList) {
if (mention.entityType === 'user') {
userList.push(mention);
}
}
return userList as MentionNode[];
}
export function extractPageMentions(mentionList: MentionNode[]): MentionNode[] {
const pageMentionList = [];
for (const mention of mentionList) {
if (
mention.entityType === 'page' &&
!pageMentionList.some(
(pageMention) => pageMention.entityId === mention.entityId,
)
) {
pageMentionList.push(mention);
}
}
return pageMentionList as MentionNode[];
}
export function getProsemirrorContent(content: any) {
return (
content ?? {
type: 'doc',
content: [{ type: 'paragraph', attrs: { textAlign: 'left' } }],
}
);
}
export function isAttachmentNode(nodeType: string) {
const attachmentNodeTypes = [
'attachment',
'image',
'video',
'excalidraw',
'drawio',
];
return attachmentNodeTypes.includes(nodeType);
}
export function getAttachmentIds(prosemirrorJson: any) {
const doc = jsonToNode(prosemirrorJson);
const attachmentIds = [];
doc?.descendants((node: Node) => {
if (isAttachmentNode(node.type.name)) {
if (node.attrs.attachmentId && isValidUUID(node.attrs.attachmentId)) {
if (!attachmentIds.includes(node.attrs.attachmentId)) {
attachmentIds.push(node.attrs.attachmentId);
}
}
}
});
return attachmentIds;
}
export function removeMarkTypeFromDoc(doc: Node, markName: string): Node {
const { schema } = doc.type;
const markType = schema.marks[markName];
if (!markType) {
return doc;
}
const tr = new Transform(doc).removeMark(0, doc.content.size, markType);
return tr.doc;
}
export function createYdocFromJson(prosemirrorJson: any): Buffer | null {
if (prosemirrorJson) {
const ydoc = TiptapTransformer.toYdoc(
prosemirrorJson,
'default',
tiptapExtensions,
);
Y.encodeStateAsUpdate(ydoc);
return Buffer.from(Y.encodeStateAsUpdate(ydoc));
}
return null;
}