|
@@ -0,0 +1,117 @@
|
|
|
+import { renderBlock } from "@/components/vEditor/renderJSON";
|
|
|
+import { toJSONBlock } from "@/components/vEditor/toJSON";
|
|
|
+// render ----------------------------------->
|
|
|
+/**
|
|
|
+ * 将富文本 JSON 渲染到指定的元素中
|
|
|
+ *
|
|
|
+ * @param {RichTextJSON} body
|
|
|
+ * @param {HTMLDivElement} container
|
|
|
+ */
|
|
|
+export function renderRichText(body, container) {
|
|
|
+ let sections = body?.sections || [];
|
|
|
+ let nodes = [];
|
|
|
+ sections.forEach((section) => {
|
|
|
+ nodes.push(renderSection(section));
|
|
|
+ });
|
|
|
+ if (container != undefined) {
|
|
|
+ container.innerHTML = "";
|
|
|
+ nodes.forEach((node) => {
|
|
|
+ container.appendChild(node);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {RichTextSectionJSON} section
|
|
|
+ * @returns {HTMLDivElement} 返回根据 section 渲染好的 HTMLDivElement
|
|
|
+ */
|
|
|
+function renderSection(section) {
|
|
|
+ let blocks = section.blocks || [];
|
|
|
+ let inline = blocks.length > 1;
|
|
|
+ let node = document.createElement("div");
|
|
|
+ if (section.attributes) {
|
|
|
+ Object.keys(section.attributes).forEach((key) => {
|
|
|
+ node.setAttribute(key, section.attributes[key]);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // node.style = "display: flex;";
|
|
|
+ blocks.forEach((block) => {
|
|
|
+ node.appendChild(renderBlock(block, inline));
|
|
|
+ });
|
|
|
+ return node;
|
|
|
+}
|
|
|
+
|
|
|
+// toJson ----------------------------------->
|
|
|
+/**
|
|
|
+ * 将编辑器的 HTMLDivElement 转为我们需要的 JSON.stringify(RichTextJSON)
|
|
|
+ *
|
|
|
+ * @param {HTMLDivElement} editor
|
|
|
+ *
|
|
|
+ * @returns {String} JSON.stringify(RichTextJSON)
|
|
|
+ */
|
|
|
+export function richTextToJSON(editor) {
|
|
|
+ let newSections = [];
|
|
|
+ const nodesSectionsCollector = toNodeSections(editor);
|
|
|
+ nodesSectionsCollector.forEach((section) => {
|
|
|
+ let newSection = { blocks: [], attributes: section.attributes };
|
|
|
+ section.blockElements.forEach((elem) => {
|
|
|
+ const newBlock = toJSONBlock(elem);
|
|
|
+ if (newBlock) newSection.blocks.push(newBlock);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!newSection.blocks.length) {
|
|
|
+ // 空行特殊处理
|
|
|
+ newSection.blocks = [{ type: "text", value: "", param: null }];
|
|
|
+ }
|
|
|
+ newSections.push(newSection);
|
|
|
+ });
|
|
|
+ // console.log(newSections);
|
|
|
+
|
|
|
+ /** @type {RichTextJSON} */
|
|
|
+ const result = { sections: newSections };
|
|
|
+ return result;
|
|
|
+ // return JSON.stringify(result, null);
|
|
|
+}
|
|
|
+
|
|
|
+function toNodeSections(node) {
|
|
|
+ let sections = [];
|
|
|
+ let curSection = { attributes: {}, blockElements: [] };
|
|
|
+
|
|
|
+ const checkIsDiv = (elem) => {
|
|
|
+ return elem.nodeType == Node.ELEMENT_NODE && elem.nodeName === "DIV";
|
|
|
+ };
|
|
|
+
|
|
|
+ const parseNode = (node) => {
|
|
|
+ node.childNodes.forEach((elem) => {
|
|
|
+ if (checkIsDiv(elem)) {
|
|
|
+ if (curSection.blockElements.length) {
|
|
|
+ sections.push(curSection);
|
|
|
+ }
|
|
|
+ curSection = { attributes: {}, blockElements: [] };
|
|
|
+ if (elem.attributes) {
|
|
|
+ let attributes = {};
|
|
|
+ for (let i = 0; i < elem.attributes.length; i++) {
|
|
|
+ const attr = elem.attributes[i];
|
|
|
+ attributes[attr.nodeName] = attr.nodeValue;
|
|
|
+ }
|
|
|
+ curSection.attributes = attributes;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (elem.childNodes && elem.childNodes.length) {
|
|
|
+ parseNode(elem);
|
|
|
+ } else {
|
|
|
+ curSection.blockElements.push(elem);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ parseNode(node);
|
|
|
+
|
|
|
+ if (curSection.blockElements.length) {
|
|
|
+ sections.push(curSection);
|
|
|
+ }
|
|
|
+
|
|
|
+ // console.log(sections);
|
|
|
+ return sections;
|
|
|
+}
|