diff --git a/app/srv/ws/sync/actions/comp_load.ts b/app/srv/ws/sync/actions/comp_load.ts index 9339e90f..37c87985 100644 --- a/app/srv/ws/sync/actions/comp_load.ts +++ b/app/srv/ws/sync/actions/comp_load.ts @@ -40,5 +40,3 @@ export const comp_load: SAction["comp"]["load"] = async function ( } return result; }; - -const scanMeta = async (id: string, doc: DComp, sync: SyncConnection) => {}; diff --git a/app/srv/ws/sync/editor/load-component.ts b/app/srv/ws/sync/editor/load-component.ts index 0e25e356..ee2c5201 100644 --- a/app/srv/ws/sync/editor/load-component.ts +++ b/app/srv/ws/sync/editor/load-component.ts @@ -1,3 +1,5 @@ +import { IItem } from "../../../../web/src/utils/types/item"; +import { DComp } from "../../../../web/src/utils/types/root"; import { conns } from "../entity/conn"; import { docs } from "../entity/docs"; import { snapshot } from "../entity/snapshot"; @@ -9,7 +11,6 @@ import { SyncConnection, SyncType } from "../type"; export const loadComponent = async (comp_id: string, sync?: SyncConnection) => { let snap = snapshot.get("comp", comp_id); let ydoc = docs.comp[comp_id]; - const conf = sync?.conf; const createUndoManager = async (root: Y.Map) => { const um = new Y.UndoManager(root, { @@ -22,6 +23,21 @@ export const loadComponent = async (comp_id: string, sync?: SyncConnection) => { const attachOnUpdate = async (doc: Y.Doc, um: Y.UndoManager) => { snapshot.set("comp", comp_id, "id_doc", um.doc.clientID); + const mitem = (doc as DComp).getMap("map").get("root"); + if (mitem) { + const item = mitem.toJSON() as IItem; + if (!item.component) { + const component = new Y.Map(); + syncronize(component, { id: comp_id, props: {} }); + mitem.set("component", component as any); + } else if (item.component.id !== comp_id) { + const mcomp = mitem.get("component"); + if (mcomp && mcomp.get("id") !== comp_id) { + mcomp.set("id", comp_id); + } + } + } + doc.on("update", async (update: Uint8Array, origin: any) => { const bin = Y.encodeStateAsUpdate(doc); snapshot.set("comp", comp_id, "bin", bin); diff --git a/app/web/src/nova/ed/logic/ed-global.ts b/app/web/src/nova/ed/logic/ed-global.ts index 3c214f1a..8928e799 100644 --- a/app/web/src/nova/ed/logic/ed-global.ts +++ b/app/web/src/nova/ed/logic/ed-global.ts @@ -153,6 +153,7 @@ export const EDGlobal = { entry: [] as string[], tree: [] as NodeModel[], render: () => {}, + prevent_rebuild: false, }, comp: { doc: null as null | DComp, diff --git a/app/web/src/nova/ed/logic/tree/build.tsx b/app/web/src/nova/ed/logic/tree/build.tsx index a92e95b1..a4d0f42e 100644 --- a/app/web/src/nova/ed/logic/tree/build.tsx +++ b/app/web/src/nova/ed/logic/tree/build.tsx @@ -4,6 +4,8 @@ import { IMeta, PG, active } from "../ed-global"; import { pushTreeNode } from "./build/push-tree"; export const treeRebuild = async (p: PG, arg?: { note?: string }) => { + if (p.page.prevent_rebuild) return; + const is_layout = p.site.layout && p.site.layout.id === p.page.cur.id && diff --git a/app/web/src/nova/ed/panel/main/main-per-item.tsx b/app/web/src/nova/ed/panel/main/main-per-item.tsx index c6e767aa..87ee1979 100644 --- a/app/web/src/nova/ed/panel/main/main-per-item.tsx +++ b/app/web/src/nova/ed/panel/main/main-per-item.tsx @@ -4,6 +4,9 @@ import { IMeta, PG, active } from "../../logic/ed-global"; import { treeRebuild } from "../../logic/tree/build"; type MPIVParam = Parameters>; + +const text_edit = { timeout: null as any }; + export const mainPerItemVisit = ( p: PG, meta: MPIVParam[0], @@ -12,45 +15,55 @@ export const mainPerItemVisit = ( if ((meta.item as IContent).type === "text" && !meta.item.adv?.jsBuilt) { parts.props.spellCheck = false; parts.props.contentEditable = true; - parts.props.dangerouslySetInnerHTML = { - __html: meta.item.html || " ", - }; parts.props.onFocus = (e) => { - if (![meta.item.originalId, meta.item.id].includes(active.item_id)) { + p.page.prevent_rebuild = true; + p.render(); + const is_active = ![meta.item.originalId, meta.item.id].includes( + active.item_id + ); + if (is_active) { e.currentTarget.blur(); } }; - parts.props.onBlur = (e) => { - e.stopPropagation(); - const val = e.currentTarget.innerHTML; - if (active.comp_id && meta.parent?.comp_id === active.comp_id) { - const comp = p.comp.list[active.comp_id]; - const m = comp.meta[meta.item.originalId || meta.item.id]; - if (m && m.mitem) { - m.item.html = val; - m.mitem.set("html", val); - } - return; - } + p.page.prevent_rebuild = false; + p.render(); + }; - let mitem = meta.mitem; - if (mitem) { - meta.item.html = val; - mitem.set("html", val); - } + parts.props.onInput = (e) => { + e.stopPropagation(); + e.preventDefault(); + const val = e.currentTarget.innerHTML; + clearTimeout(text_edit.timeout); + text_edit.timeout = setTimeout(() => { + if (active.comp_id && meta.parent?.comp_id === active.comp_id) { + const comp = p.comp.list[active.comp_id]; + const m = comp.meta[meta.item.originalId || meta.item.id]; + if (m && m.mitem) { + m.item.html = val; + m.mitem.set("html", val); + } + return; + } + + let mitem = meta.mitem; + if (mitem) { + meta.item.html = val; + mitem.set("html", val); + } + }, 500); }; } - let isActive: boolean = active.item_id === meta.item.id; + let is_active: boolean = active.item_id === meta.item.id; if (active.comp_id) { - isActive = active.item_id === meta.item.originalId; + is_active = active.item_id === meta.item.originalId; } parts.props.className = cx( parts.props.className, - isActive && "el-active", - isActive && + is_active && "el-active", + is_active && css` &::after { content: " "; @@ -123,14 +136,3 @@ const getOuterMeta = (p: { meta: Record }, meta: IMeta) => { if (cur) return cur; }; -function setEndOfContenteditable(div: any) { - let range: any, sel: any; - if (document.createRange) { - //Firefox, Chrome, Opera, Safari, IE 9+ - range = document.createRange(); - range.selectNodeContents(div); - sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } -} diff --git a/app/web/src/nova/ed/panel/tree/node/render.tsx b/app/web/src/nova/ed/panel/tree/node/render.tsx index dc997844..5619b4b4 100644 --- a/app/web/src/nova/ed/panel/tree/node/render.tsx +++ b/app/web/src/nova/ed/panel/tree/node/render.tsx @@ -95,7 +95,11 @@ export const nodeRender: NodeRender = (node, prm) => { p.page.render(); if ((item as IContent).type === "text") { setTimeout(() => { - (document.querySelector(".el-active") as any)?.focus(); + if (document.activeElement?.tagName === "INPUT") { + return; + } + const el_active = document.querySelector(".el-active") as any; + if (el_active) el_active.focus(); }, 100); } }}