diff --git a/app/srv/ws/sync/actions/comp_load.ts b/app/srv/ws/sync/actions/comp_load.ts index 7a7c2574..b34dfd4d 100644 --- a/app/srv/ws/sync/actions/comp_load.ts +++ b/app/srv/ws/sync/actions/comp_load.ts @@ -1,7 +1,6 @@ import { EComp } from "../../../../web/src/nova/ed/logic/ed-global"; import { genMeta } from "../../../../web/src/nova/vi/meta/meta"; import { IItem } from "../../../../web/src/utils/types/item"; -import { DComp } from "../../../../web/src/utils/types/root"; import { SAction } from "../actions"; import { loadComponent, userSyncComponent } from "../editor/load-component"; import { parseJs } from "../editor/parser/parse-js"; diff --git a/app/srv/ws/sync/actions/page_load.ts b/app/srv/ws/sync/actions/page_load.ts index 51c57454..bdfce535 100644 --- a/app/srv/ws/sync/actions/page_load.ts +++ b/app/srv/ws/sync/actions/page_load.ts @@ -2,7 +2,7 @@ import { EPage } from "../../../../web/src/nova/ed/logic/ed-global"; import { initLoadComp } from "../../../../web/src/nova/vi/meta/comp/init-comp-load"; import { genMeta } from "../../../../web/src/nova/vi/meta/meta"; import { simplifyMeta } from "../../../../web/src/nova/vi/meta/simplify"; -import { GenMetaP } from "../../../../web/src/nova/vi/utils/types"; +import { GenMetaP, IMeta } from "../../../../web/src/nova/vi/utils/types"; import { IItem } from "../../../../web/src/utils/types/item"; import { DPage } from "../../../../web/src/utils/types/root"; import { SAction } from "../actions"; @@ -213,7 +213,23 @@ const scanMeta = async (doc: DPage, sync: SyncConnection) => { if (docs.comp[id]) { const mitem = docs.comp[id].doc.getMap("map").get("root"); - mcomps[id] = { comp: mitem?.toJSON() as IItem }; + const comp = mitem?.toJSON() as IItem; + const smeta: Record = {}; + genMeta( + { + comps: {}, + meta: smeta, + on: { + visit(meta) { + if (typeof meta.item.adv?.js === "string") { + meta.scope.def = parseJs(meta); + } + }, + }, + }, + { item: comp, ignore_first_component: true } + ); + mcomps[id] = { comp, smeta: simplifyMeta(smeta) }; } } } @@ -244,22 +260,7 @@ const scanMeta = async (doc: DPage, sync: SyncConnection) => { const comps: EPage["comps"] = {}; for (const [id, snap] of Object.entries(msnap)) { - const meta = {}; - genMeta( - { - comps: {}, - meta, - on: { - visit(meta) { - if (typeof meta.item.adv?.js === "string") { - meta.scope.def = parseJs(meta); - } - }, - }, - }, - { item: mcomps[id].comp } - ); - + const meta = mcomps[id].smeta; comps[id] = { id, meta, snapshot: await gzipAsync(snap.bin) }; } diff --git a/app/web/src/nova/ed/logic/comp/load.tsx b/app/web/src/nova/ed/logic/comp/load.tsx index 692a7094..47002541 100644 --- a/app/web/src/nova/ed/logic/comp/load.tsx +++ b/app/web/src/nova/ed/logic/comp/load.tsx @@ -7,6 +7,8 @@ import { IMeta, PG } from "../ed-global"; import { treeRebuild } from "../tree/build"; import { pushTreeNode } from "../tree/build/push-tree"; import { initLoadComp } from "../../../vi/meta/comp/init-comp-load"; +import { ISimpleMeta } from "../../../vi/utils/types"; +import { simplifyMeta } from "../../../vi/meta/simplify"; export const loadcomp = { timeout: 0 as any, @@ -28,7 +30,7 @@ export const loadComponent = async (p: PG, id_comp: string, sync?: boolean) => { for (const [id_comp, comp] of result) { if (comp && comp.snapshot) { - await loadCompSnapshot(p, id_comp, comp.snapshot); + await loadCompSnapshot(p, id_comp, comp.snapshot, comp.meta); } } loadcomp.pending.clear(); @@ -40,7 +42,8 @@ export const loadComponent = async (p: PG, id_comp: string, sync?: boolean) => { export const loadCompSnapshot = async ( p: PG, comp_id: string, - snapshot: Uint8Array + snapshot: Uint8Array, + smeta: Record ) => { if (p.comp.list[comp_id] && p.comp.list[comp_id].doc) { return; @@ -53,15 +56,16 @@ export const loadCompSnapshot = async ( doc.off("update", p.comp.list[comp_id].on_update); } - const updated = await updateComponentMeta(p, doc, comp_id); + const updated = await updateComponentMeta(p, doc, comp_id, smeta); if (updated) { const { meta, tree } = updated; if (p.comp.list[comp_id]) { + p.comp.list[comp_id].comp.meta = smeta; p.comp.list[comp_id].meta = meta; p.comp.list[comp_id].tree = tree; } else { p.comp.list[comp_id] = { - comp: { id: comp_id, snapshot }, + comp: { id: comp_id, snapshot, meta: smeta }, doc, meta, tree, @@ -91,7 +95,8 @@ export const loadCompSnapshot = async ( const updated = await updateComponentMeta( p, p.comp.list[comp_id].doc, - comp_id + comp_id, + smeta ); if (updated) { p.comp.list[comp_id].meta = updated.meta; @@ -112,7 +117,8 @@ export const loadCompSnapshot = async ( export const updateComponentMeta = async ( p: PG, doc: DComp, - comp_id: string + comp_id: string, + smeta: Record ) => { const mitem = doc.getMap("map").get("root"); if (!mitem) return; @@ -120,24 +126,24 @@ export const updateComponentMeta = async ( const meta: Record = {}; const tree: NodeModel[] = []; const item = mitem.toJSON() as IItem; - p.comp.loaded[comp_id] = { - comp: item, - }; + p.comp.loaded[comp_id] = { comp: item, smeta }; await initLoadComp( { comps: p.comp.loaded, meta, set_meta: false, + smeta, }, item, async (comp_ids: string[]) => { - const comps = await p.sync.comp.load(comp_ids, true); + const ids = comp_ids.filter((id) => !p.comp.loaded[id]); + const comps = await p.sync.comp.load(ids, true); let result = Object.entries(comps); for (const [id_comp, comp] of result) { if (comp && comp.snapshot) { - await loadCompSnapshot(p, id_comp, comp.snapshot); + await loadCompSnapshot(p, id_comp, comp.snapshot, comp.meta); } } } @@ -182,5 +188,7 @@ export const updateComponentMeta = async ( { item, ignore_first_component: true } ); + p.comp.loaded[comp_id] = { comp: item, smeta: simplifyMeta(meta) }; + return { meta, tree }; }; diff --git a/app/web/src/nova/ed/logic/ed-route.ts b/app/web/src/nova/ed/logic/ed-route.ts index 742e1f0b..3160a6f5 100644 --- a/app/web/src/nova/ed/logic/ed-route.ts +++ b/app/web/src/nova/ed/logic/ed-route.ts @@ -3,7 +3,7 @@ import { PG } from "./ed-global"; import { loadSite } from "./ed-site"; import { treeRebuild } from "./tree/build"; import { loadCompSnapshot } from "./comp/load"; - +import { produce } from "immer"; export const edRoute = async (p: PG) => { if (p.status === "ready" || p.status === "init") { if (!p.site.domain && !p.site.name) { @@ -50,7 +50,7 @@ export const reloadPage = async (p: PG, page_id: string, note: string) => { if (remotePage.comps) { for (const [id_comp, c] of Object.entries(remotePage.comps)) { if (c && c.snapshot) { - await loadCompSnapshot(p, id_comp, c.snapshot); + await loadCompSnapshot(p, id_comp, c.snapshot, c.meta); } } } diff --git a/app/web/src/nova/ed/logic/ed-sync.tsx b/app/web/src/nova/ed/logic/ed-sync.tsx index bcc99d4f..a9093c73 100644 --- a/app/web/src/nova/ed/logic/ed-sync.tsx +++ b/app/web/src/nova/ed/logic/ed-sync.tsx @@ -179,7 +179,12 @@ export const edInitSync = (p: PG) => { if (data.type === "page") { await treeRebuild(p, { note: "sv_remote" }); } else { - const updated = await updateComponentMeta(p, doc, data.id); + const updated = await updateComponentMeta( + p, + doc, + data.id, + p.comp.list[data.id].comp.meta + ); if (updated) { p.comp.list[data.id].meta = updated.meta; p.comp.list[data.id].tree = updated.tree; diff --git a/app/web/src/nova/ed/logic/tree/build.tsx b/app/web/src/nova/ed/logic/tree/build.tsx index d0bf939a..2cc9aeb0 100644 --- a/app/web/src/nova/ed/logic/tree/build.tsx +++ b/app/web/src/nova/ed/logic/tree/build.tsx @@ -16,9 +16,11 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => { if (icomp) { p.comp.loaded[k] = { comp: icomp, + smeta: v.comp.meta, }; } } + if (v.comp.meta) p.comp.loaded[k].smeta = v.comp.meta; } const mroot = p.page.doc?.getMap("map").get("root"); diff --git a/app/web/src/nova/ed/panel/tree/node/on-drop.tsx b/app/web/src/nova/ed/panel/tree/node/on-drop.tsx index 940e21d6..87a1e6c2 100644 --- a/app/web/src/nova/ed/panel/tree/node/on-drop.tsx +++ b/app/web/src/nova/ed/panel/tree/node/on-drop.tsx @@ -31,6 +31,10 @@ export const nodeOnDrop: ( let from = fromMeta.mitem; if (to) { + if (to.get("component")?.get("id")) { + return null; + } + to.doc?.transact(() => { if (to && from && typeof relativeIndex === "number") { const toChilds = to.get("childs"); @@ -91,34 +95,12 @@ export const canDrop = (p: PG, arg: DropOptions) => { return false; } else if (from === "item") { if (to === "section" || to === "item") { - if ( - dropTarget.data.item.type === "item" && - dropTarget.data.item.component?.id - ) { - if (p.comp) { - if (active.comp_id === dropTarget.data.item.component?.id) { - return true; - } - } - return false; - } return true; } else { return false; } } else if (from === "text") { - if (to === "item") { - if ( - dropTarget.data.item.type === "item" && - dropTarget.data.item.component?.id - ) { - if (p.comp) { - if (active.comp_id === dropTarget.data.item.component.id) { - return true; - } - } - return false; - } + if (to === "item" || to === "section") { return true; } } diff --git a/app/web/src/nova/vi/meta/comp.tsx b/app/web/src/nova/vi/meta/comp.tsx index ef21eba5..f43d8bf7 100644 --- a/app/web/src/nova/vi/meta/comp.tsx +++ b/app/web/src/nova/vi/meta/comp.tsx @@ -1,4 +1,5 @@ -import { GenMetaArg, GenMetaP, IMeta } from "../utils/types"; +import { deepClone } from "web-utils"; +import { GenMetaArg, GenMetaP, IMeta, ISimpleMeta } from "../utils/types"; import { instantiate, walkChild } from "./comp/instantiate"; import { walkProp } from "./comp/walk-prop"; import { genMeta } from "./meta"; @@ -17,31 +18,24 @@ export const genComp = (p: GenMetaP, arg: GenMetaArg) => { } if (pcomp) { - let smeta_instances: IMeta["instances"] = undefined; - if (p.smeta && p.smeta[item.id]) { - const smeta = p.smeta[item.id]; - if (smeta && smeta.comp) { - smeta_instances = smeta.comp.instances; - } - } - let instance = {}; let instances: IMeta["instances"] = undefined; - if (!smeta_instances) { - const parent_instance = getParentInstance(p, arg, item.id); - instance = parent_instance || {}; - instances = !parent_instance ? { [item.id]: instance } : undefined; - } else { - instance = smeta_instances[item.id]; - instances = smeta_instances; - } + const parent_instance = getParentInstance(p, arg, item.id); + instance = parent_instance || {}; + instances = !parent_instance ? { [item.id]: instance } : undefined; instantiate({ item, comp: pcomp.comp, ids: instance, }); + + let smeta = p.comps[item.component.id].smeta; + if (smeta) { + smeta = applySMeta(smeta, instance); + } + const meta: IMeta = { item: simplifyItemChild(item), parent: { @@ -53,8 +47,10 @@ export const genComp = (p: GenMetaP, arg: GenMetaArg) => { scope: {}, }; - if (p.smeta?.[item.id]) { - meta.scope.def = p.smeta[item.id].scope; + if (!meta.parent?.comp_id) { + if (p.smeta?.[item.id]) { + meta.scope.def = p.smeta[item.id].scope; + } } if (item.id) { @@ -75,20 +71,23 @@ export const genComp = (p: GenMetaP, arg: GenMetaArg) => { ) { walkChild(prop.content, instance); - genMeta(p, { - item: prop.content, - is_root: false, - jsx_prop: { - is_root: true, - comp_id, - name, - }, - parent: { - item: meta.item, - instance_id: item.id, - comp: pcomp.comp, - }, - }); + genMeta( + { ...p, smeta }, + { + item: prop.content, + is_root: false, + jsx_prop: { + is_root: true, + comp_id, + name, + }, + parent: { + item: meta.item, + instance_id: item.id, + comp: pcomp.comp, + }, + } + ); } }, }); @@ -108,15 +107,18 @@ export const genComp = (p: GenMetaP, arg: GenMetaArg) => { for (const child of Object.values(item.childs)) { if (child.name.startsWith("jsx:")) continue; - genMeta(p, { - item: child, - is_root: false, - parent: { - item, - instance_id: item.id, - comp: pcomp.comp, - }, - }); + genMeta( + { ...p, smeta }, + { + item: child, + is_root: false, + parent: { + item, + instance_id: item.id, + comp: pcomp.comp, + }, + } + ); } } } @@ -134,3 +136,25 @@ const getParentInstance = (p: GenMetaP, arg: GenMetaArg, id: string) => { } } }; + +const applySMeta = ( + smeta: Record, + ids: Record +) => { + const nmeta: typeof smeta = {}; + + for (const [k, v] of Object.entries(smeta)) { + const id = ids[k]; + if (id) { + nmeta[id] = deepClone(v); + nmeta[id].id = id; + const parent = nmeta[id].parent; + if (parent) { + if (parent.instance_id) parent.instance_id = ids[parent.instance_id]; + if (parent.id) parent.id = ids[id]; + } + } + } + + return nmeta; +}; diff --git a/app/web/src/nova/vi/meta/meta.ts b/app/web/src/nova/vi/meta/meta.ts index a68a9d40..30239e67 100644 --- a/app/web/src/nova/vi/meta/meta.ts +++ b/app/web/src/nova/vi/meta/meta.ts @@ -46,7 +46,7 @@ export const genMeta = (p: GenMetaP, arg: GenMetaArg) => { if (p.set_meta !== false) { p.meta[meta.item.id] = meta; } - } + } if (item.childs) { for (const [_, v] of Object.entries(item.childs)) { diff --git a/app/web/src/nova/vi/utils/types.ts b/app/web/src/nova/vi/utils/types.ts index 8b313298..a6a7a9ce 100644 --- a/app/web/src/nova/vi/utils/types.ts +++ b/app/web/src/nova/vi/utils/types.ts @@ -7,7 +7,7 @@ import { createViPassProp } from "../render/script/passprop"; export type GenMetaP = { meta: Record; - comps: Record; + comps: Record }>; on?: { visit_component?: (id: string) => void; visit?: (meta: IMeta) => void;