import { EPage } from "../../../../web/src/nova/ed/logic/ed-global"; import { assignMitem } from "../../../../web/src/nova/ed/logic/tree/assign-mitem"; 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, 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"; import { loadComponent, userSyncComponent } from "../editor/load-component"; import { parseJs } from "../editor/parser/parse-js"; import { activity } from "../entity/activity"; import { conns } from "../entity/conn"; import { docs } from "../entity/docs"; import { CompSnapshot, snapshot } from "../entity/snapshot"; import { user } from "../entity/user"; import { gzipAsync } from "../entity/zlib"; import { sendWS } from "../sync-handler"; import { SyncConnection, SyncType } from "../type"; export const page_load: SAction["page"]["load"] = async function ( this: SyncConnection, id: string ) { let snap = snapshot.get("page", id); let ydoc = docs.page[id]; const conf = this.conf; if (!conf) return undefined; conf.page_id = id; const createUndoManager = async (root: Y.Map) => { const um = new Y.UndoManager(root, { ignoreRemoteMapChanges: true, }); return um; }; const attachOnUpdate = async (doc: Y.Doc, um: Y.UndoManager) => { snapshot.set("page", id, "id_doc", um.doc.clientID); doc.on("update", async (update: Uint8Array, origin: any) => { const bin = Y.encodeStateAsUpdate(doc); snapshot.set("page", id, "bin", bin); const sv_local = await gzipAsync(update); user.active.findAll({ page_id: id }).map((e) => { if (origin !== um) { if (e.client_id === origin) return; } const ws = conns.get(e.client_id)?.ws; if (ws) sendWS(ws, { type: SyncType.Event, event: "remote_svlocal", data: { type: "page", sv_local, id }, }); }); }); }; const defaultActive = { select: "" as "" | "comp" | "item" | "section" | "text", }; const setActivityPage = async (id_site: string, id_page: string) => { await activity.site.set(id_site, this.ws, async (data) => { data.page_id = id_page; return data; }); }; user.active.delAll({ client_id: this.client_id }); if (!snap && !ydoc) { const page = await db.page.findFirst({ where: { id } }); if (page) { await setActivityPage(page.id_site, page.id); const doc = new Y.Doc(); let root = doc.getMap("map"); syncronize(root, { id, root: page.content_tree }); const um = await createUndoManager(root); docs.page[id] = { doc: doc as any, id, um, }; const bin = Y.encodeStateAsUpdate(doc); await attachOnUpdate(doc, um); snapshot.update({ bin, id, type: "page", name: page.name, ts: Date.now(), url: page.url, id_doc: doc.clientID, id_site: page.id_site, }); user.active.add({ ...defaultActive, client_id: this.client_id, user_id: this.user_id, site_id: page.id_site, page_id: page.id, }); const meta = await scanMeta(docs.page[id].doc, this); return { id: id, url: page.url, name: page.name, snapshot: await gzipAsync(bin), ...meta, }; } } else if (snap && !ydoc) { const doc = new Y.Doc(); snapshot.set("page", id, "id_doc", doc.clientID); await setActivityPage(snap.id_site, id); Y.applyUpdate(doc, snap.bin); let root = doc.getMap("map"); const um = await createUndoManager(root); await attachOnUpdate(doc, um); docs.page[id] = { doc: doc as any, id, um, }; user.active.add({ ...defaultActive, client_id: this.client_id, user_id: this.user_id, site_id: snap.id_site, page_id: snap.id, }); const meta = await scanMeta(docs.page[id].doc, this); return { id: id, url: snap.url, name: snap.name, snapshot: await gzipAsync(snap.bin), ...meta, }; } else if (snap && ydoc) { await setActivityPage(snap.id_site, id); user.active.add({ ...defaultActive, client_id: this.client_id, user_id: this.user_id, site_id: snap.id_site, page_id: snap.id, }); const meta = await scanMeta(ydoc.doc, this); return { id: snap.id, url: snap.url, name: snap.name, snapshot: await gzipAsync(snap.bin), ...meta, }; } }; const scanMeta = async (doc: DPage, sync: SyncConnection) => { const meta: GenMetaP["meta"] = {}; const mcomps: GenMetaP["comps"] = {}; const msnap: Record = {}; const loading = {} as Record>; const mchilds = doc.getMap("map").get("root")?.get("childs"); const entry: string[] = []; if (mchilds) { const childs = mchilds.map((m) => m); for (const mchild of childs) { await initLoadComp( { comps: mcomps, meta }, mchild.toJSON(), async (comp_ids) => { for (const id of comp_ids) { if (!docs.comp[id]) { if (typeof loading[id] === "undefined") { loading[id] = new Promise(async (resolve) => { await loadComponent(id, sync); resolve(); }); } await loading[id]; } else { userSyncComponent(sync, id); } const snap = snapshot.get("comp", id); if (snap) { msnap[id] = snap; } if (docs.comp[id]) { const mitem = docs.comp[id].doc.getMap("map").get("root"); 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.adv?.js); } }, }, }, { item: comp, ignore_first_component: true } ); mcomps[id] = { comp, smeta: simplifyMeta(smeta) }; } } } ); } const transact = { instances_check: {} as Record, }; for (const mitem of childs) { const item = mitem.toJSON() as IItem; entry.push(item.id); genMeta( { comps: mcomps, meta, on: { visit_component(item) { if (!item.component?.instances) { transact.instances_check[item.id] = true; } }, visit(m) { if (!m.parent?.comp_id) { if (typeof m.item.adv?.js === "string") { m.scope.def = parseJs(m.item.adv?.js); } } if (m.item.component?.id) { if (transact.instances_check[m.item.id]) { transact.instances_check[m.item.id] = m; } } }, }, }, { item } ); } } const comps: EPage["comps"] = {}; for (const [id, snap] of Object.entries(msnap)) { const meta = mcomps[id].smeta; comps[id] = { id, meta, snapshot: await gzipAsync(snap.bin) }; } return { meta: simplifyMeta(meta), comps, entry }; };