wip fix layout live change

This commit is contained in:
Rizky 2023-11-24 06:30:55 +07:00
parent 7eada6fde4
commit a296b35eff
8 changed files with 126 additions and 59 deletions

View File

@ -1,5 +1,4 @@
import { IScopeComp } from "../../../../web/src/nova/ed/logic/ed-global";
import { MItem } from "../../../../web/src/utils/types/item";
import { DComp } from "../../../../web/src/utils/types/root";
import { SAction } from "../actions";
import { loadComponent } from "../editor/load-component";

View File

@ -21,15 +21,14 @@ export const site_load: SAction["site"]["load"] = async function (
activity.site.room(site.id).join({ ws: this.ws });
let layout = undefined;
const _layout = await db.page.findFirst({
const layout = await db.page.findFirst({
where: {
id_site: id,
is_deleted: false,
is_default_layout: true,
},
select: { id: true },
});
if (_layout) layout = _layout.content_tree as IRoot;
return {
id: site.id,
@ -38,7 +37,7 @@ export const site_load: SAction["site"]["load"] = async function (
domain: site.domain,
js: site.js || "",
js_compiled: site.js_compiled || "",
layout,
layout: { id: layout?.id || "" },
};
}
}

View File

@ -5,7 +5,7 @@ import { SAction } from "../../../../../srv/ws/sync/actions";
import { parseJs } from "../../../../../srv/ws/sync/editor/parser/parse-js";
import { clientStartSync } from "../../../utils/sync/ws-client";
import { IItem, MItem } from "../../../utils/types/item";
import { DComp, DPage, IRoot } from "../../../utils/types/root";
import { DComp, DPage } from "../../../utils/types/root";
import { ISection } from "../../../utils/types/section";
import { IText, MText } from "../../../utils/types/text";
@ -16,7 +16,7 @@ export const EmptySite = {
config: { api_url: "" },
js: "",
js_compiled: "",
layout: undefined as undefined | IRoot,
layout: { snapshot: null as null | Uint8Array, id: "" },
};
export type ESite = typeof EmptySite;
@ -114,8 +114,14 @@ export const EDGlobal = {
page: {
cur: EmptyPage,
doc: null as null | DPage,
doc_on_update: async (bin: Uint8Array, origin: any) => {},
list: {} as Record<string, { page: EPage; doc: DPage }>,
list: {} as Record<
string,
{
page: EPage;
doc: DPage;
on_update?: (bin: Uint8Array, origin: any) => Promise<void>;
}
>,
building: false,
meta: {} as Record<string, EdMeta>,
entry: [] as string[],

View File

@ -3,6 +3,7 @@ import { IItem } from "../../../utils/types/item";
import { DComp } from "../../../utils/types/root";
import { PG } from "./ed-global";
import { treeRebuild } from "./tree/build";
import { loadSite } from "./ed-site";
export const edRoute = async (p: PG) => {
if (p.status === "ready" || p.status === "init") {
@ -15,7 +16,7 @@ export const edRoute = async (p: PG) => {
return;
}
p.site = site;
await loadSite(p, site);
}
if (
@ -23,22 +24,23 @@ export const edRoute = async (p: PG) => {
!p.page.cur.snapshot ||
!p.page.list[p.page.cur.id]
) {
if (p.page.list[params.page_id] && p.page.doc) {
p.page.doc.off("update", p.page.doc_on_update);
const page = p.page.list[params.page_id];
if (page && p.page.doc && page.on_update) {
p.page.doc.off("update", page.on_update);
const cur = p.page.list[params.page_id];
p.page.cur = cur.page;
p.page.doc = cur.doc;
}
await reloadPage(p);
await reloadPage(p, params.page_id);
}
}
};
export const reloadPage = async (p: PG) => {
export const reloadPage = async (p: PG, page_id: string) => {
p.status = "loading";
const remotePage = await p.sync.page.load(params.page_id);
const remotePage = await p.sync.page.load(page_id);
if (!remotePage) {
p.status = "page-not-found";
@ -66,7 +68,17 @@ export const reloadPage = async (p: PG) => {
const doc = new Y.Doc();
Y.applyUpdate(doc, decompress(remotePage.snapshot));
p.page.doc_on_update = async (bin: Uint8Array, origin: any) => {
let page = p.page.list[remotePage.id];
if (!page) {
p.page.list[remotePage.id] = {} as any;
page = p.page.list[remotePage.id];
}
if (page.on_update && page.doc) {
page.doc.off("update", page.on_update);
}
page.on_update = async (bin: Uint8Array, origin: any) => {
if (origin === "sv_remote" || origin === "local") return;
const res = await p.sync.yjs.sv_local(
@ -93,14 +105,12 @@ export const reloadPage = async (p: PG) => {
}
};
doc.on("update", p.page.doc_on_update);
doc.on("update", page.on_update);
p.page.doc = doc as any;
if (p.page.doc) {
p.page.list[remotePage.id] = {
page: p.page.cur,
doc: p.page.doc,
};
page.page = p.page.cur;
page.doc = p.page.doc;
}
if (p.page.doc) {

View File

@ -0,0 +1,19 @@
import { ESite, PG } from "./ed-global";
import { reloadPage } from "./ed-route";
export const loadSite = async (p: PG, site: ESite) => {
const old_layout_id = p.site.layout.id;
const layout_changed = p.site.layout.id !== site.layout.id;
p.site = site;
if (layout_changed) {
const old_layout = p.page.list[old_layout_id];
if (old_layout && old_layout.on_update) {
old_layout.doc.off("update", old_layout.on_update);
}
if (site.layout.id) {
await reloadPage(p, site.layout.id);
}
}
};

View File

@ -8,6 +8,7 @@ import { EmptySite, PG } from "./ed-global";
import { treeRebuild } from "./tree/build";
import { evalCJS } from "../../view/logic/load-code";
import { reloadPage } from "./ed-route";
import { loadSite } from "./ed-site";
const decoder = new TextDecoder();
@ -28,9 +29,9 @@ export const edInitSync = (p: PG) => {
p.site = deepClone(EmptySite);
p.site.id = "--loading--";
p.ui.popup.code.init = false;
p.sync.site.load(params.site_id).then((site) => {
p.sync.site.load(params.site_id).then(async (site) => {
if (site) {
p.site = site;
await loadSite(p, site);
p.render();
} else {
alert("Site not found. redirecting...");
@ -124,7 +125,7 @@ export const edInitSync = (p: PG) => {
},
async editor_start(e) {
if (p.ui.syncing) {
await reloadPage(p);
await reloadPage(p, params.page_id);
if (p.page.doc) {
p.page.doc.transact(() => {
p.page.doc?.getMap("map").set("ts", Date.now());

View File

@ -20,7 +20,9 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
const loaded = new Set<string>();
await Promise.all(
sections.map((e) => {
return syncWalkLoad(p, e, loaded);
return syncWalkLoad(p, e, loaded, (id) => {
return loadComponent(p, id);
});
})
);
}
@ -32,36 +34,61 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
let root_id = "root";
if (p.site.layout) {
const loaded = new Set<string>();
await Promise.all(
p.site.layout.childs.map((e) =>
walkLoad(p.comp, e, loaded, (id) => loadComponent(p, id))
)
);
p.site.layout.childs.map((e) => {
p.page.entry.push(e.id);
walkMap(
{ meta: p.page.meta, comps: p.comp.map },
{
isLayout: true,
item: e,
parent_item: { id: "root" },
portal,
each(meta) {
if (meta.item.name === "content") {
root_id = meta.item.id;
}
},
}
);
});
const ldoc = p.page.list[p.site.layout.id];
if (ldoc) {
const lroot = ldoc.doc.getMap("map").get("root");
if (lroot) {
const sections = lroot.get("childs");
if (sections) {
const loaded = new Set<string>();
await Promise.all(
sections.map((e) => {
return syncWalkLoad(p, e, loaded, (id) => {
return loadComponent(p, id);
});
})
);
// if root_id is root, it means content is not found.
// if content is not found, do not use layout.
if (root_id === "root") {
p.page.entry = [];
p.page.tree = [];
p.page.meta = {};
sections.map((e) => {
if (root_id === "root") {
p.page.entry.push(e.get("id"));
}
syncWalkMap(p, {
isLayout: false,
mitem: e,
parent_item: { id: root_id },
tree_root_id: root_id,
portal,
each(meta) {
if (meta.item.name === "content") {
root_id = meta.item.id;
}
},
});
});
for (const [k, portal_out] of Object.entries(portal.out)) {
const name = k.replace(/⮕/gi, "").trim();
const portal_in = portal.in[`${name}`];
if (portal_in) {
for (const key of Object.keys(portal_in)) {
delete (portal_in as any)[key];
}
for (const [k, v] of Object.entries(portal_out)) {
(portal_in as any)[k] = v;
}
}
}
}
// if root_id is root, it means content is not found.
// if content is not found, do not use layout.
if (root_id === "root") {
p.page.entry = [];
p.page.tree = [];
p.page.meta = {};
}
}
}
}

View File

@ -16,7 +16,8 @@ import {
export const syncWalkLoad = async (
p: PG,
mitem: MItem,
loaded: Set<string>
loaded: Set<string>,
loadComponent: (id: string) => Promise<boolean>
) => {
const mcomp = mitem.get("component");
if (mcomp) {
@ -26,14 +27,14 @@ export const syncWalkLoad = async (
const isFirstLoaded = !loaded.has(id);
loaded.add(id);
if (!p.comp.list[id]) {
await loadComponent(p, comp.id);
await loadComponent(comp.id);
}
const pcomp = p.comp.list[id];
if (pcomp) {
const pitem = pcomp.doc.getMap("map").get("root");
if (pitem && isFirstLoaded) {
await syncWalkLoad(p, pitem, loaded);
await syncWalkLoad(p, pitem, loaded, loadComponent);
}
}
}
@ -44,7 +45,7 @@ export const syncWalkLoad = async (
if (mprop) {
const mcontent = ensurePropContent(mprop, propName);
if (mcontent) {
await syncWalkLoad(p, mcontent, loaded);
await syncWalkLoad(p, mcontent, loaded, loadComponent);
}
}
}
@ -52,7 +53,7 @@ export const syncWalkLoad = async (
}
for (const e of mitem.get("childs")?.map((e) => e) || []) {
await syncWalkLoad(p, e, loaded);
await syncWalkLoad(p, e, loaded, loadComponent);
}
};
@ -69,6 +70,7 @@ export const syncWalkMap = (
parent_mcomp?: EdMeta["parent_mcomp"];
skip_add_tree?: boolean;
tree_root_id: string;
each?: (meta: EdMeta) => void;
}
) => {
const { mitem, parent_item, parent_mcomp } = arg;
@ -153,6 +155,8 @@ export const syncWalkMap = (
if (item.name.startsWith("⮕")) {
arg.portal.out[item.name] = meta;
}
if (arg.each) arg.each(meta);
p.page.meta[item.id] = meta;
if (!skip_tree) {
@ -231,6 +235,8 @@ export const syncWalkMap = (
if (item.name.startsWith("⮕")) {
arg.portal.out[item.name] = meta;
}
if (arg.each) arg.each(meta);
p.page.meta[item.id] = meta;
if (!skip_tree) {