// utils/tiptapMapper.js export function tiptapToBlocks(tiptapJSON) { const blocks = []; function processNode(node, parentId = null) { if (!node) return null; const blockId = generateId(); switch (node.type) { case "doc": if (node.content) { node.content.forEach((child) => processNode(child, null)); } return null; case "paragraph": const paragraphBlock = { id: blockId, type: "paragraph", content: extractTextContent(node), parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(paragraphBlock); // پردازش فرزندان if (node.content) { node.content.forEach((child) => { if (child.type !== "text") { const childBlock = processNode(child, blockId); if (childBlock) { paragraphBlock.children.push(childBlock.id); } } }); } return paragraphBlock; case "heading": const headingBlock = { id: blockId, type: "heading", level: node.attrs?.level || 1, content: extractTextContent(node), parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(headingBlock); // پردازش فرمت‌های درون عنوان if (node.content) { node.content.forEach((child) => { if (child.type !== "text") { const childBlock = processNode(child, blockId); if (childBlock) { headingBlock.children.push(childBlock.id); } } }); } return headingBlock; case "bulletList": case "orderedList": const isOrdered = node.type === "orderedList"; const listBlock = { id: blockId, type: isOrdered ? "numbered_list" : "bulleted_list", content: "", parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(listBlock); // پردازش آیتم‌های لیست if (node.content) { node.content.forEach((listItem, index) => { if (listItem.type === "listItem") { const itemContent = extractTextContent(listItem); const itemBlock = { id: generateId(), type: "list_item", content: itemContent, parentId: blockId, number: isOrdered ? index + 1 : null, createdAt: new Date().toISOString(), children: [], }; blocks.push(itemBlock); listBlock.children.push(itemBlock.id); // پردازش محتوای درون آیتم لیست if (listItem.content) { listItem.content.forEach((child) => { if (child.type !== "paragraph" && child.type !== "text") { const childBlock = processNode(child, itemBlock.id); if (childBlock) { itemBlock.children.push(childBlock.id); } } }); } } }); } return listBlock; case "codeBlock": const codeBlock = { id: blockId, type: "code", language: node.attrs?.language || "javascript", content: extractTextContent(node), parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(codeBlock); return codeBlock; case "blockquote": const quoteBlock = { id: blockId, type: "quote", content: extractTextContent(node), parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(quoteBlock); return quoteBlock; case "text": // متن ساده را به عنوان یک بلوک متنی برمی‌گردانیم const textBlock = { id: blockId, type: "text", content: node.text || "", marks: node.marks || [], parentId: parentId, createdAt: new Date().toISOString(), children: [], }; // فقط اگر درون یک بلوک دیگر نباشد، آن را به عنوان بلوک مستقل اضافه می‌کنیم if (!parentId) { blocks.push(textBlock); } return textBlock; case "hardBreak": const breakBlock = { id: blockId, type: "break", content: "\n", parentId: parentId, createdAt: new Date().toISOString(), children: [], }; if (!parentId) { blocks.push(breakBlock); } return breakBlock; default: // برای انواع ناشناخته if (node.content) { const unknownBlock = { id: blockId, type: "unknown", content: extractTextContent(node), originalType: node.type, parentId: parentId, createdAt: new Date().toISOString(), children: [], }; blocks.push(unknownBlock); // بازگشتی پردازش فرزندان node.content.forEach((child) => { if (child.type !== "text") { const childBlock = processNode(child, blockId); if (childBlock) { unknownBlock.children.push(childBlock.id); } } }); return unknownBlock; } return null; } } function extractTextContent(node) { if (!node.content) return node.text || ""; let text = ""; node.content.forEach((child) => { if (child.type === "text") { text += child.text; } else if (child.content || child.text) { text += extractTextContent(child); } }); return text; } function generateId() { return ( "block_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9) ); } // شروع پردازش if (tiptapJSON && tiptapJSON.content) { tiptapJSON.content.forEach((child) => processNode(child, null)); } return blocks; } // تابع معکوس برای تست (اختیاری) export function blocksToTiptap(blocks) { const content = []; const blockMap = new Map(); // ایجاد نقشه برای دسترسی سریع blocks.forEach((block) => { blockMap.set(block.id, block); }); // تابع بازگشتی برای ایجاد گره‌ها function createNode(block) { switch (block.type) { case "paragraph": return { type: "paragraph", content: [ { type: "text", text: block.content || "", }, ], }; case "heading": return { type: "heading", attrs: { level: block.level || 1 }, content: [ { type: "text", text: block.content || "", }, ], }; case "bulleted_list": case "numbered_list": const listItems = []; if (block.children && block.children.length > 0) { block.children.forEach((childId) => { const childBlock = blockMap.get(childId); if (childBlock && childBlock.type === "list_item") { listItems.push({ type: "listItem", content: [ { type: "paragraph", content: [ { type: "text", text: childBlock.content || "", }, ], }, ], }); } }); } return { type: block.type === "numbered_list" ? "orderedList" : "bulletList", content: listItems, }; case "code": return { type: "codeBlock", attrs: { language: block.language || "javascript" }, content: [ { type: "text", text: block.content || "", }, ], }; case "quote": return { type: "blockquote", content: [ { type: "paragraph", content: [ { type: "text", text: block.content || "", }, ], }, ], }; default: return { type: "paragraph", content: [ { type: "text", text: block.content || "", }, ], }; } } // فقط بلوک‌هایی که والد ندارند (بلوک‌های سطح بالا) const topLevelBlocks = blocks.filter((block) => !block.parentId); topLevelBlocks.forEach((block) => { const node = createNode(block); if (node) { content.push(node); } }); return { type: "doc", content: content, }; }