wip remove view
This commit is contained in:
parent
8bdc357d7f
commit
8179e3f74c
|
|
@ -8,9 +8,9 @@ import { IItem } from "../../../utils/types/item";
|
||||||
import { DComp, DPage } from "../../../utils/types/root";
|
import { DComp, DPage } from "../../../utils/types/root";
|
||||||
import {
|
import {
|
||||||
GenMetaP,
|
GenMetaP,
|
||||||
IMeta as LogicMeta,
|
|
||||||
ISimpleMeta,
|
ISimpleMeta,
|
||||||
} from "../../view/logic/meta/types";
|
IMeta as LogicMeta,
|
||||||
|
} from "../../vi/utils/types";
|
||||||
|
|
||||||
export type IMeta = LogicMeta;
|
export type IMeta = LogicMeta;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { parseJs } from "../../../../../../srv/ws/sync/editor/parser/parse-js";
|
import { parseJs } from "../../../../../srv/ws/sync/editor/parser/parse-js";
|
||||||
import { IContent } from "../../../../utils/types/general";
|
import { IContent } from "../../../utils/types/general";
|
||||||
import { IItem, MItem } from "../../../../utils/types/item";
|
import { IItem, MItem } from "../../../utils/types/item";
|
||||||
import { createViLocal } from "../../../vi/render/script/local";
|
import { createViLocal } from "../render/script/local";
|
||||||
import { createViPassProp } from "../../../vi/render/script/passprop";
|
import { createViPassProp } from "../render/script/passprop";
|
||||||
|
|
||||||
export type GenMetaP = {
|
export type GenMetaP = {
|
||||||
meta: Record<string, IMeta>;
|
meta: Record<string, IMeta>;
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { ReactElement, ReactNode } from "react";
|
|
||||||
import { IMeta, IScope } from "../../ed/logic/ed-global";
|
|
||||||
|
|
||||||
export const ViewGlobal = {
|
|
||||||
mode: "" as "desktop" | "mobile",
|
|
||||||
status: "init" as "init" | "load-code" | "loading-code" | "ready" | "rebuild",
|
|
||||||
current: { site_id: "", page_id: "" },
|
|
||||||
layout: { show: false },
|
|
||||||
meta: {} as Record<string, IMeta>,
|
|
||||||
scope: null as null | IScope,
|
|
||||||
entry: [] as string[],
|
|
||||||
body_cache: null as null | ReactElement,
|
|
||||||
component: {
|
|
||||||
load: async (id_comp: string) => {},
|
|
||||||
},
|
|
||||||
script: {
|
|
||||||
api_url: "",
|
|
||||||
db: null as any,
|
|
||||||
api: null as any,
|
|
||||||
},
|
|
||||||
view: {
|
|
||||||
hidden: undefined as undefined | ((meta: IMeta) => boolean),
|
|
||||||
active: undefined as
|
|
||||||
| undefined
|
|
||||||
| {
|
|
||||||
get: (meta: IMeta) => boolean;
|
|
||||||
set: (meta: IMeta) => void;
|
|
||||||
text?: (arg: { meta: IMeta }) => ReactNode;
|
|
||||||
},
|
|
||||||
hover: undefined as
|
|
||||||
| undefined
|
|
||||||
| { get: (meta: IMeta) => boolean; set: (meta: IMeta) => void },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export type VG = typeof ViewGlobal & { render: () => void };
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { VG } from "./global";
|
|
||||||
import { VLoad } from "./types";
|
|
||||||
|
|
||||||
export const w = window as unknown as {
|
|
||||||
isMobile: boolean;
|
|
||||||
isDesktop: boolean;
|
|
||||||
isEditor: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const vInit = (
|
|
||||||
v: VG,
|
|
||||||
arg: {
|
|
||||||
load: VLoad;
|
|
||||||
site_id: string;
|
|
||||||
page_id: string;
|
|
||||||
mode: "mobile" | "desktop";
|
|
||||||
isEditor: boolean;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
const { load, site_id, page_id, mode, isEditor } = arg;
|
|
||||||
|
|
||||||
w.isDesktop = mode !== "mobile";
|
|
||||||
w.isMobile = mode === "mobile";
|
|
||||||
w.isEditor = isEditor;
|
|
||||||
|
|
||||||
v.status = "load-code";
|
|
||||||
v.current.site_id = site_id;
|
|
||||||
v.current.page_id = page_id;
|
|
||||||
|
|
||||||
if (load.mode === "tree_meta") {
|
|
||||||
v.meta = load.meta;
|
|
||||||
v.entry = load.entry;
|
|
||||||
v.scope = load.scope || null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
import { VG } from "./global";
|
|
||||||
|
|
||||||
export const codeLoaded = new Set<string>();
|
|
||||||
const codeMap = {
|
|
||||||
page: {} as Record<string, string[]>,
|
|
||||||
compGroup: {} as Record<string, string[]>,
|
|
||||||
comp: {} as Record<string, string>,
|
|
||||||
};
|
|
||||||
export const newLoadCode = async (v: VG, forceLoad?: boolean) => {
|
|
||||||
if (forceLoad) {
|
|
||||||
codeLoaded.clear();
|
|
||||||
v.status = "load-code";
|
|
||||||
v.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.status === "load-code") {
|
|
||||||
v.status = "loading-code";
|
|
||||||
|
|
||||||
const { site_id, page_id } = v.current;
|
|
||||||
const w = window as any;
|
|
||||||
|
|
||||||
if (!codeLoaded.has(site_id)) {
|
|
||||||
codeLoaded.add(site_id);
|
|
||||||
const module = await importCJS(`/nova-load/site/${site_id}/index.js`);
|
|
||||||
for (const [k, v] of Object.entries(module)) {
|
|
||||||
w[k] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
const code = await db.code.findMany({
|
|
||||||
where: { id_site: site_id, name: { notIn: ["site", "SSR"] } },
|
|
||||||
select: { code_assign: true },
|
|
||||||
});
|
|
||||||
codeMap.compGroup = {};
|
|
||||||
codeMap.page = {};
|
|
||||||
for (const c of code) {
|
|
||||||
c.code_assign.forEach((e) => {
|
|
||||||
if (e.id_page) {
|
|
||||||
if (!codeMap.page[e.id_page]) codeMap.page[e.id_page] = [];
|
|
||||||
codeMap.page[e.id_page].push(e.id_code);
|
|
||||||
}
|
|
||||||
if (e.id_component_group) {
|
|
||||||
if (!codeMap.compGroup[e.id_component_group])
|
|
||||||
codeMap.compGroup[e.id_component_group] = [];
|
|
||||||
codeMap.page[e.id_component_group].push(e.id_code);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
codeMap.comp = {};
|
|
||||||
const comps = await db.component.findMany({
|
|
||||||
where: { id_component_group: { in: Object.keys(codeMap.compGroup) } },
|
|
||||||
select: { id: true, id_component_group: true },
|
|
||||||
});
|
|
||||||
for (const c of comps) {
|
|
||||||
if (c.id && c.id_component_group) {
|
|
||||||
codeMap.comp[c.id] = c.id_component_group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const promises = [];
|
|
||||||
if (codeMap.page[page_id]) {
|
|
||||||
for (const id of codeMap.page[page_id]) {
|
|
||||||
promises.push(
|
|
||||||
new Promise<void>(async (resolve) => {
|
|
||||||
if (!codeLoaded.has(id)) {
|
|
||||||
codeLoaded.add(id);
|
|
||||||
const module = await importCJS(`/nova-load/code/${id}/index.js`);
|
|
||||||
for (const [k, v] of Object.entries(module)) {
|
|
||||||
w[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
v.status = "rebuild";
|
|
||||||
v.render();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const loadCompCode = async (comp_id: string) => {
|
|
||||||
const cgroup_id = codeMap.comp[comp_id];
|
|
||||||
if (codeMap.compGroup[cgroup_id]) {
|
|
||||||
const promises = [];
|
|
||||||
const w = window as any;
|
|
||||||
for (const id of codeMap.compGroup[cgroup_id]) {
|
|
||||||
promises.push(
|
|
||||||
new Promise<void>(async (resolve) => {
|
|
||||||
if (!codeLoaded.has(id)) {
|
|
||||||
codeLoaded.add(id);
|
|
||||||
const module = await importCJS(`/nova-load/code/${id}/index.js`);
|
|
||||||
for (const [k, v] of Object.entries(module)) {
|
|
||||||
w[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const importCJS = async (url: string) => {
|
|
||||||
const res = await fetch(url);
|
|
||||||
const src = await res.text();
|
|
||||||
return evalCJS(src);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const evalCJS = (src: string) => {
|
|
||||||
if (src) {
|
|
||||||
const module = { exports: { __esModule: true as true | undefined } };
|
|
||||||
eval(`try {
|
|
||||||
${src}
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e);
|
|
||||||
}`);
|
|
||||||
const result = { ...module.exports };
|
|
||||||
if (result.__esModule) {
|
|
||||||
delete result.__esModule;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
import importModule from "../../../render/editor/tools/dynamic-import";
|
|
||||||
import { devLoader } from "../../../render/live/dev-loader";
|
|
||||||
import { createAPI, createDB, initApi } from "../../../utils/script/init-api";
|
|
||||||
import { VG } from "./global";
|
|
||||||
|
|
||||||
export const oldLoadCode = async (v: VG) => {
|
|
||||||
const site = await db.site.findFirst({
|
|
||||||
where: { id: v.current.site_id },
|
|
||||||
include: { component_site: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
const loader = devLoader;
|
|
||||||
const p = {} as any;
|
|
||||||
if (site) {
|
|
||||||
const w = window as any;
|
|
||||||
if (!w.exports) w.exports = {};
|
|
||||||
|
|
||||||
if (site.component_site) {
|
|
||||||
for (const cg of site.component_site) {
|
|
||||||
await importModule(loader.npm(p, "site", cg.id_component_group));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await initApi(site.config);
|
|
||||||
await importModule(loader.npm(p, "site", site.id));
|
|
||||||
if (site.js_compiled) {
|
|
||||||
const config = site.config as any;
|
|
||||||
const exec = (fn: string, scopes: any) => {
|
|
||||||
if (config.api_url && !scopes["api"]) {
|
|
||||||
scopes["api"] = createAPI(config.api_url);
|
|
||||||
scopes["db"] = createDB(config.api_url);
|
|
||||||
}
|
|
||||||
scopes.params = w.params;
|
|
||||||
scopes.module = {};
|
|
||||||
const f = new Function(...Object.keys(scopes), fn);
|
|
||||||
const res = f(...Object.values(scopes));
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
const scope = {
|
|
||||||
types: {},
|
|
||||||
exports: w.exports,
|
|
||||||
load: importModule,
|
|
||||||
render: p.render,
|
|
||||||
module: {
|
|
||||||
exports: {} as any,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await exec(site.js_compiled, scope);
|
|
||||||
if (scope.module.exports) {
|
|
||||||
for (const [k, v] of Object.entries(scope.module.exports)) {
|
|
||||||
w.exports[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v.status = "rebuild";
|
|
||||||
v.render();
|
|
||||||
};
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
import { instantiate, walkChild } from "./comp/instantiate";
|
|
||||||
import { walkProp } from "./comp/walk-prop";
|
|
||||||
import { genMeta } from "./meta";
|
|
||||||
import { simplifyItemChild } from "./simplify";
|
|
||||||
import { GenMetaArg, GenMetaP, IMeta } from "./types";
|
|
||||||
|
|
||||||
export const genComp = (p: GenMetaP, arg: GenMetaArg) => {
|
|
||||||
const { item } = arg;
|
|
||||||
if (item.type === "item" && item.component?.id && arg.parent?.item.id) {
|
|
||||||
let pcomp = p.comps[item.component.id];
|
|
||||||
if (p.on?.visit_component) {
|
|
||||||
p.on.visit_component(item.component.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pcomp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
instantiate({
|
|
||||||
item,
|
|
||||||
comp: pcomp.comp,
|
|
||||||
ids: instance,
|
|
||||||
});
|
|
||||||
|
|
||||||
const meta: IMeta = {
|
|
||||||
item: simplifyItemChild(item),
|
|
||||||
parent: {
|
|
||||||
id: arg.parent.item.id,
|
|
||||||
comp_id: arg.parent?.comp?.component?.id,
|
|
||||||
instance_id: arg.parent?.instance_id,
|
|
||||||
},
|
|
||||||
instances,
|
|
||||||
scope: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (p.smeta?.[item.id]) {
|
|
||||||
meta.scope.def = p.smeta[item.id].scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.id) {
|
|
||||||
if (p.set_meta !== false) {
|
|
||||||
p.meta[item.id] = meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walkProp({
|
|
||||||
item,
|
|
||||||
pcomp,
|
|
||||||
each(name, prop) {
|
|
||||||
const comp_id = item.component?.id;
|
|
||||||
if (
|
|
||||||
prop.meta?.type === "content-element" &&
|
|
||||||
prop.content &&
|
|
||||||
comp_id
|
|
||||||
) {
|
|
||||||
walkChild(prop.content, instance);
|
|
||||||
|
|
||||||
genMeta(p, {
|
|
||||||
item: prop.content,
|
|
||||||
is_root: false,
|
|
||||||
jsx_prop: {
|
|
||||||
is_root: true,
|
|
||||||
comp_id,
|
|
||||||
name,
|
|
||||||
},
|
|
||||||
parent: {
|
|
||||||
item,
|
|
||||||
instance_id: item.id,
|
|
||||||
comp: pcomp.comp,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (p.on) {
|
|
||||||
if (p.on.item_exists && p.meta[item.id]) {
|
|
||||||
p.on.item_exists({ old: p.meta[item.id], new: meta });
|
|
||||||
} else if (p.on.item_new && !p.meta[item.id]) {
|
|
||||||
p.on.item_new({ new: meta });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.on?.visit) {
|
|
||||||
p.on.visit(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getParentInstance = (p: GenMetaP, arg: GenMetaArg, id: string) => {
|
|
||||||
if (arg.parent?.instance_id && p.meta[arg.parent?.instance_id]) {
|
|
||||||
const parent_instance = p.meta[arg.parent?.instance_id];
|
|
||||||
if (parent_instance.instances) {
|
|
||||||
if (!parent_instance.instances[id]) {
|
|
||||||
parent_instance.instances[id] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent_instance.instances[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import { IItem } from "../../../../../utils/types/item";
|
|
||||||
import { genMeta } from "../meta";
|
|
||||||
import { GenMetaP } from "../types";
|
|
||||||
|
|
||||||
export const initLoadComp = async (
|
|
||||||
p: GenMetaP,
|
|
||||||
item: IItem,
|
|
||||||
load: (comp_ids: string[]) => Promise<void>
|
|
||||||
) => {
|
|
||||||
const comp_ids: string[] = [];
|
|
||||||
genMeta(
|
|
||||||
{
|
|
||||||
...p,
|
|
||||||
on: {
|
|
||||||
visit_component: async (id) => {
|
|
||||||
if (!p.comps[id]) {
|
|
||||||
comp_ids.push(id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
set_meta: false,
|
|
||||||
},
|
|
||||||
{ item }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (comp_ids.length > 0) {
|
|
||||||
await load(comp_ids);
|
|
||||||
await initLoadComp(p, item, load);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
import { deepClone } from "web-utils";
|
|
||||||
import { IItem } from "../../../../../utils/types/item";
|
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
|
||||||
import { FNComponent } from "../../../../../utils/types/meta-fn";
|
|
||||||
|
|
||||||
export const instantiate = (arg: {
|
|
||||||
item: IItem;
|
|
||||||
comp: IItem;
|
|
||||||
ids: Record<string, string>;
|
|
||||||
}) => {
|
|
||||||
const { item, comp, ids } = arg;
|
|
||||||
const newitem = deepClone(comp);
|
|
||||||
|
|
||||||
walkChild(newitem, ids);
|
|
||||||
|
|
||||||
if (item.id) {
|
|
||||||
newitem.id = item.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newitem.component && item.component && newitem.component.props) {
|
|
||||||
for (const k of Object.keys(newitem.component.props)) {
|
|
||||||
if (item.component.props[k]) {
|
|
||||||
newitem.component.props[k] = item.component.props[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key of Object.keys(item)) {
|
|
||||||
delete (item as any)[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(newitem)) {
|
|
||||||
(item as any)[k] = v;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const walkChild = (
|
|
||||||
item: IItem,
|
|
||||||
ids: Exclude<FNComponent["ref_ids"], undefined>
|
|
||||||
) => {
|
|
||||||
if (!ids[item.id]) {
|
|
||||||
ids[item.id] = createId();
|
|
||||||
}
|
|
||||||
|
|
||||||
item.id = ids[item.id];
|
|
||||||
|
|
||||||
if (item.childs) {
|
|
||||||
for (const child of item.childs) {
|
|
||||||
walkChild(child as IItem, ids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { IItem } from "../../../../../utils/types/item";
|
|
||||||
import { FNCompDef } from "../../../../../utils/types/meta-fn";
|
|
||||||
|
|
||||||
export const walkProp = (arg: {
|
|
||||||
item: IItem;
|
|
||||||
pcomp: { comp: IItem };
|
|
||||||
each: (name: string, prop: FNCompDef) => void;
|
|
||||||
}) => {
|
|
||||||
for (const [k, v] of Object.entries(arg.pcomp.comp.component?.props || {})) {
|
|
||||||
const props = arg.item.component?.props;
|
|
||||||
let prop = props?.[k];
|
|
||||||
if (props) {
|
|
||||||
if (!props[k]) {
|
|
||||||
props[k] = v;
|
|
||||||
prop = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop) {
|
|
||||||
arg.each(k, prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
import { IItem } from "../../../../utils/types/item";
|
|
||||||
import { genComp } from "./comp";
|
|
||||||
import { simplifyItemChild } from "./simplify";
|
|
||||||
import { GenMetaArg, GenMetaP, IMeta } from "./types";
|
|
||||||
|
|
||||||
export const genMeta = (p: GenMetaP, arg: GenMetaArg) => {
|
|
||||||
const item = arg.item as IItem;
|
|
||||||
|
|
||||||
if (item.type === "item" && item.component?.id) {
|
|
||||||
genComp(p, arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let scope: IMeta["scope"] = {};
|
|
||||||
if (p.smeta) {
|
|
||||||
if (p.smeta[item.id] && p.smeta[item.id].scope) {
|
|
||||||
scope.def = p.smeta[item.id].scope;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta: IMeta = {
|
|
||||||
item: simplifyItemChild(item),
|
|
||||||
jsx_prop: arg.jsx_prop,
|
|
||||||
parent: {
|
|
||||||
id: arg.parent?.item.id || "root",
|
|
||||||
instance_id: arg.parent?.instance_id,
|
|
||||||
comp_id: arg.parent?.comp?.component?.id,
|
|
||||||
},
|
|
||||||
scope,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (p.on?.visit) {
|
|
||||||
p.on.visit(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.on) {
|
|
||||||
if (p.on.item_exists && p.meta[item.id]) {
|
|
||||||
p.on.item_exists({ old: p.meta[item.id], new: meta });
|
|
||||||
} else if (p.on.item_new && !p.meta[item.id]) {
|
|
||||||
p.on.item_new({ new: meta });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item.id) {
|
|
||||||
if (p.set_meta !== false) {
|
|
||||||
p.meta[item.id] = meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.childs) {
|
|
||||||
for (const [_, v] of Object.entries(item.childs)) {
|
|
||||||
genMeta(p, {
|
|
||||||
item: v,
|
|
||||||
is_root: false,
|
|
||||||
parent: {
|
|
||||||
item,
|
|
||||||
instance_id: arg.parent?.instance_id,
|
|
||||||
comp: arg.parent?.comp,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
import { IItem } from "../../../../utils/types/item";
|
|
||||||
import { IMeta, ISimpleMeta } from "./types";
|
|
||||||
|
|
||||||
export const simplifyItemChild = (item: IItem) => {
|
|
||||||
const newitem = {} as any;
|
|
||||||
for (const [k, v] of Object.entries(item)) {
|
|
||||||
if (k === "childs") {
|
|
||||||
newitem.childs = [];
|
|
||||||
if (v && Array.isArray(v)) {
|
|
||||||
for (const child of v) {
|
|
||||||
newitem.childs.push({ id: child.id });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newitem[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newitem as IItem;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const simplifyMeta = (allmeta: Record<string, IMeta>) => {
|
|
||||||
const smeta = {} as Record<string, ISimpleMeta>;
|
|
||||||
|
|
||||||
for (const [k, meta] of Object.entries(allmeta)) {
|
|
||||||
smeta[k] = {
|
|
||||||
id: meta.item.id,
|
|
||||||
parent: meta.parent
|
|
||||||
? {
|
|
||||||
id: meta.parent.id,
|
|
||||||
comp_id: meta.parent.comp_id,
|
|
||||||
instance_id: meta.parent.instance_id,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
comp:
|
|
||||||
meta.item.component && meta.instances
|
|
||||||
? {
|
|
||||||
id: meta.item.component.id,
|
|
||||||
instances: meta.instances,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
scope: meta.scope.def,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return smeta;
|
|
||||||
};
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import { VG } from "./global";
|
|
||||||
|
|
||||||
export const preload = async (p: VG, pathname: string) => {
|
|
||||||
//TODO
|
|
||||||
};
|
|
||||||
|
|
||||||
export const extractNavigate = (str: string) => {
|
|
||||||
return [
|
|
||||||
...findBetween(str, `navigate(`, `)`),
|
|
||||||
...findBetween(str, `href = `, `;`),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const findBetween = (text: string, opener: string, closer: string) => {
|
|
||||||
let i = 0;
|
|
||||||
let last = 0;
|
|
||||||
const founds: string[] = [];
|
|
||||||
while (true) {
|
|
||||||
const startIndex = text.indexOf(opener, i);
|
|
||||||
last = i;
|
|
||||||
if (startIndex >= 0) {
|
|
||||||
const char = text[startIndex + opener.length];
|
|
||||||
if (char === '"' || char === "'" || char === "`") {
|
|
||||||
const end = text.indexOf(
|
|
||||||
`${char}${closer}`,
|
|
||||||
startIndex + opener.length + 1
|
|
||||||
);
|
|
||||||
const found = text.substring(startIndex + opener.length + 1, end);
|
|
||||||
i = end + 2 + closer.length;
|
|
||||||
founds.push(found);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last === i) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return founds;
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { IMeta, IScope, PG } from "../../ed/logic/ed-global";
|
|
||||||
|
|
||||||
export type VLoad =
|
|
||||||
| { mode: "page"; page_id: string }
|
|
||||||
| { mode: "pathname"; pathname: string }
|
|
||||||
| {
|
|
||||||
mode: "tree_meta";
|
|
||||||
entry: string[];
|
|
||||||
scope?: IScope;
|
|
||||||
meta: Record<string, IMeta>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type VLoadComponent = {
|
|
||||||
load: (id_comp: string) => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { useGlobal } from "web-utils";
|
|
||||||
import { ViewGlobal } from "../logic/global";
|
|
||||||
import { ViewMeta } from "./meta/meta";
|
|
||||||
|
|
||||||
export const VEntry = () => {
|
|
||||||
const v = useGlobal(ViewGlobal, "VIEW");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{v.entry.map((section_id) => {
|
|
||||||
return <ViewMeta id={section_id} key={section_id} />;
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { FC, Fragment, ReactNode } from "react";
|
|
||||||
import { useGlobal, useLocal } from "web-utils";
|
|
||||||
import { IMeta } from "../../../ed/logic/ed-global";
|
|
||||||
import { ViewGlobal } from "../../logic/global";
|
|
||||||
import { ViewMeta } from "./meta";
|
|
||||||
|
|
||||||
export const ViewMetaChildren: FC<{
|
|
||||||
meta: IMeta;
|
|
||||||
className?: string;
|
|
||||||
}> = ({ meta, className }) => {
|
|
||||||
const v = useGlobal(ViewGlobal, "VIEW");
|
|
||||||
const children: Record<string, ReactNode> = {};
|
|
||||||
const item = meta.item;
|
|
||||||
if (item.type !== "text") {
|
|
||||||
for (const child of item.childs) {
|
|
||||||
if (child.id) {
|
|
||||||
children[child.id] = <ViewMeta id={child.id} key={child.id} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (item.id) {
|
|
||||||
if (v.view.active?.text && v.view.active?.get(meta)) {
|
|
||||||
const ActiveText = v.view.active.text;
|
|
||||||
children[item.id] = (
|
|
||||||
<Fragment key={item.id}>
|
|
||||||
<ActiveText meta={meta} />
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
children[item.id] = (
|
|
||||||
<span
|
|
||||||
key={item.id}
|
|
||||||
dangerouslySetInnerHTML={{ __html: item.html || " " }}
|
|
||||||
></span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>{Object.values(children)}</>;
|
|
||||||
};
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import { FC, useState } from "react";
|
|
||||||
import { useGlobal } from "web-utils";
|
|
||||||
import { ViewGlobal } from "../../logic/global";
|
|
||||||
import { ViewMetaRender } from "./render";
|
|
||||||
import { ViewBoundedScript } from "./script";
|
|
||||||
import { compPropVal } from "./script/comp-propval";
|
|
||||||
|
|
||||||
export const ViewMeta: FC<{ id: string; scopeIndex?: Record<string, any> }> = ({
|
|
||||||
id,
|
|
||||||
scopeIndex,
|
|
||||||
}) => {
|
|
||||||
const v = useGlobal(ViewGlobal, "VIEW");
|
|
||||||
const [, _render] = useState({});
|
|
||||||
|
|
||||||
const meta = v.meta[id];
|
|
||||||
|
|
||||||
if (!meta) return null;
|
|
||||||
meta.render = () => _render({});
|
|
||||||
|
|
||||||
const item = meta.item;
|
|
||||||
|
|
||||||
if (item.type === "item" && item.component?.id) {
|
|
||||||
compPropVal(v, meta, scopeIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.hidden && v.view.hidden) {
|
|
||||||
if (v.view.hidden(meta)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.adv) {
|
|
||||||
if (item.adv.js && item.adv.jsBuilt && typeof item.adv.js === "string") {
|
|
||||||
return (
|
|
||||||
<ViewBoundedScript
|
|
||||||
js={item.adv.js}
|
|
||||||
v={v}
|
|
||||||
item={item}
|
|
||||||
scopeIndex={scopeIndex}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <ViewMetaRender meta={meta} v={v} />;
|
|
||||||
};
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import { FC } from "react";
|
|
||||||
import { produceCSS } from "../../../../utils/css/gen";
|
|
||||||
import { IMeta } from "../../../ed/logic/ed-global";
|
|
||||||
import { VG } from "../../logic/global";
|
|
||||||
import { ViewMetaChildren } from "./children";
|
|
||||||
|
|
||||||
export const ViewMetaRender: FC<{
|
|
||||||
meta: IMeta;
|
|
||||||
v: VG;
|
|
||||||
props?: any;
|
|
||||||
className?: string;
|
|
||||||
}> = ({ meta, v, props, className }) => {
|
|
||||||
let _className = className;
|
|
||||||
const item = meta.item;
|
|
||||||
|
|
||||||
if (meta.is_layout && !v.layout.show) {
|
|
||||||
return <ViewMetaChildren key={item.id} meta={meta} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!className) {
|
|
||||||
_className = produceCSS(item, {
|
|
||||||
mode: v.mode,
|
|
||||||
hover: v.view.hover ? v.view.hover.get(meta) : undefined,
|
|
||||||
active: v.view.active ? v.view.active.get(meta) : undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={_className}
|
|
||||||
{...props}
|
|
||||||
onPointerOver={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
v.view.hover?.set(meta);
|
|
||||||
}}
|
|
||||||
onPointerDown={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
v.view.active?.set(meta);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ViewMetaChildren meta={meta} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
import hash_sum from "hash-sum";
|
|
||||||
import { FC, ReactNode, isValidElement, useEffect } from "react";
|
|
||||||
import { useLocal } from "web-utils";
|
|
||||||
import { produceCSS } from "../../../../utils/css/gen";
|
|
||||||
import { createAPI, createDB } from "../../../../utils/script/init-api";
|
|
||||||
import { IItem } from "../../../../utils/types/item";
|
|
||||||
import { ISection } from "../../../../utils/types/section";
|
|
||||||
import { IText } from "../../../../utils/types/text";
|
|
||||||
import { VG } from "../../logic/global";
|
|
||||||
import { extractNavigate, preload } from "../../logic/router";
|
|
||||||
import { ViewMetaChildren } from "./children";
|
|
||||||
import { createLocal } from "./script/create-local";
|
|
||||||
import { createPassProp } from "./script/create-pass-prop";
|
|
||||||
import { ErrorBox } from "./script/error-box";
|
|
||||||
import { mergeScopeUpwards } from "./script/merge-upward";
|
|
||||||
|
|
||||||
const renderLimitConfig = {
|
|
||||||
maxCount: 30,
|
|
||||||
maxTime: 10,
|
|
||||||
};
|
|
||||||
const renderLimit = {} as Record<
|
|
||||||
string,
|
|
||||||
Record<string, { ts: number; count: number; cache: ReactNode }>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const ViewBoundedScript: FC<{
|
|
||||||
v: VG;
|
|
||||||
item: IItem | IText | ISection;
|
|
||||||
scopeIndex?: Record<string, any>;
|
|
||||||
js: string;
|
|
||||||
}> = ({ item, v, scopeIndex, js }) => {
|
|
||||||
const local = useLocal({ js: "" });
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (local.js !== js) {
|
|
||||||
local.js = js;
|
|
||||||
local.render();
|
|
||||||
}
|
|
||||||
}, [js]);
|
|
||||||
|
|
||||||
if (local.js !== js) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ErrorBox silent={true}>
|
|
||||||
<ViewMetaScript v={v} item={item} scopeIndex={scopeIndex} />
|
|
||||||
</ErrorBox>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ViewMetaScript: FC<{
|
|
||||||
v: VG;
|
|
||||||
item: IItem | IText | ISection;
|
|
||||||
scopeIndex?: Record<string, any>;
|
|
||||||
}> = ({ item, v, scopeIndex }) => {
|
|
||||||
const js = item.adv?.jsBuilt;
|
|
||||||
const meta = v.meta[item.id];
|
|
||||||
const w = window as any;
|
|
||||||
const className = produceCSS(item, {
|
|
||||||
mode: v.mode,
|
|
||||||
hover: v.view.hover ? v.view.hover.get(meta) : undefined,
|
|
||||||
active: v.view.active ? v.view.active.get(meta) : undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!renderLimit[v.current.page_id]) {
|
|
||||||
renderLimit[v.current.page_id] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!renderLimit[v.current.page_id][item.id]) {
|
|
||||||
renderLimit[v.current.page_id][item.id] = {
|
|
||||||
ts: Date.now(),
|
|
||||||
count: 1,
|
|
||||||
cache: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
Math.abs(renderLimit[v.current.page_id][item.id].ts - Date.now()) <
|
|
||||||
renderLimitConfig.maxTime
|
|
||||||
) {
|
|
||||||
renderLimit[v.current.page_id][item.id].count++;
|
|
||||||
|
|
||||||
if (
|
|
||||||
renderLimit[v.current.page_id][item.id].count > renderLimitConfig.maxCount
|
|
||||||
) {
|
|
||||||
let js = "";
|
|
||||||
if (typeof item.adv?.js === "string") {
|
|
||||||
js = item.adv.js;
|
|
||||||
}
|
|
||||||
console.warn(
|
|
||||||
`Maximum render limit (${renderLimitConfig.maxCount} render in ${
|
|
||||||
renderLimitConfig.maxTime
|
|
||||||
}ms) reached in item [${item.name}]:\n${
|
|
||||||
js.length > 30 ? js.substring(0, 30) + "..." : js
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
return renderLimit[v.current.page_id][item.id].cache;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
renderLimit[v.current.page_id][item.id].ts = Date.now();
|
|
||||||
renderLimit[v.current.page_id][item.id].count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = <ViewMetaChildren key={item.id} meta={meta} />;
|
|
||||||
let args = {};
|
|
||||||
|
|
||||||
if (js && meta) {
|
|
||||||
if (!meta.memoize) {
|
|
||||||
meta.memoize = {};
|
|
||||||
}
|
|
||||||
const memoizeKey = hash_sum(scopeIndex) || "default";
|
|
||||||
if (!meta.memoize[memoizeKey]) {
|
|
||||||
meta.memoize[memoizeKey] = {
|
|
||||||
Local: createLocal(v, item.id, scopeIndex),
|
|
||||||
PassProp: createPassProp(v, item.id, scopeIndex),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const _js = item.adv?.js;
|
|
||||||
if (typeof _js === "string") {
|
|
||||||
const navs = extractNavigate(_js || "");
|
|
||||||
if (navs.length > 0) {
|
|
||||||
navs.map((nav) => preload(v, nav));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.script.api_url) {
|
|
||||||
if (!v.script.db) v.script.db = createDB(v.script.api_url);
|
|
||||||
if (!v.script.api) v.script.api = createAPI(v.script.api_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalScope = mergeScopeUpwards(v, item.id, scopeIndex);
|
|
||||||
for (const [k, v] of Object.entries(finalScope)) {
|
|
||||||
if (v && typeof v === "object") {
|
|
||||||
const t: {
|
|
||||||
_jsx: true;
|
|
||||||
Comp: FC<{ parent_id: string; scopeIndex?: Record<string, any> }>;
|
|
||||||
} = v as any;
|
|
||||||
if (t._jsx && t.Comp) {
|
|
||||||
finalScope[k] = (
|
|
||||||
<>
|
|
||||||
<t.Comp parent_id={meta.item.id} scopeIndex={scopeIndex} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const output = { jsx: null as any };
|
|
||||||
|
|
||||||
args = {
|
|
||||||
...w.exports,
|
|
||||||
...finalScope,
|
|
||||||
...meta.memoize[memoizeKey],
|
|
||||||
db: v.script.db,
|
|
||||||
api: v.script.api,
|
|
||||||
children,
|
|
||||||
props: {
|
|
||||||
className,
|
|
||||||
onPointerOver: (e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
v.view.hover?.set(meta);
|
|
||||||
},
|
|
||||||
onPointerDown: (e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
v.view.active?.set(meta);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
useEffect: useEffect,
|
|
||||||
render: (jsx: ReactNode) => {
|
|
||||||
if (isValidElement(jsx)) {
|
|
||||||
// output.jsx = (
|
|
||||||
// <>
|
|
||||||
// <div className={"absolute bg-white px-1 z-10 text-[9px] text-gray-500 -mt-1"}>{item.id}</div>
|
|
||||||
// {jsx}
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
output.jsx = jsx;
|
|
||||||
renderLimit[v.current.page_id][item.id].cache = output.jsx;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// execute
|
|
||||||
const fn = new Function(...Object.keys(args), js);
|
|
||||||
const res = fn(...Object.values(args));
|
|
||||||
if (res instanceof Promise) {
|
|
||||||
res.catch((e: any) => {
|
|
||||||
console.warn(e);
|
|
||||||
console.warn(
|
|
||||||
(
|
|
||||||
`ERROR in ${item.type} [${item.name}]:\n ` +
|
|
||||||
((item.adv?.js || "") as any)
|
|
||||||
).trim()
|
|
||||||
);
|
|
||||||
console.warn(`Available var:`, args, `\n\n`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return output.jsx;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
import { createAPI, createDB } from "../../../../../utils/script/init-api";
|
|
||||||
import { IItem } from "../../../../../utils/types/item";
|
|
||||||
import { FNCompDef } from "../../../../../utils/types/meta-fn";
|
|
||||||
import { IMeta } from "../../../../ed/logic/ed-global";
|
|
||||||
import { VG } from "../../../logic/global";
|
|
||||||
import { extractNavigate, preload } from "../../../logic/router";
|
|
||||||
import { ViewMeta } from "../meta";
|
|
||||||
import { mergeScopeUpwards } from "./merge-upward";
|
|
||||||
|
|
||||||
const jsxProps = {} as Record<string, any>;
|
|
||||||
export const compPropVal = (
|
|
||||||
v: VG,
|
|
||||||
meta: IMeta,
|
|
||||||
scopeIndex?: Record<string, any>
|
|
||||||
) => {
|
|
||||||
let props = {} as Record<string, FNCompDef>;
|
|
||||||
let cprops = [] as [string, FNCompDef][];
|
|
||||||
const item = meta.item;
|
|
||||||
if (item.type === "item" && item.component?.id) {
|
|
||||||
const icomp = item.component;
|
|
||||||
if (icomp) {
|
|
||||||
props = icomp.props;
|
|
||||||
cprops = Object.entries({ ...icomp.props });
|
|
||||||
|
|
||||||
if (!v.script.db) v.script.db = createDB(v.script.api_url);
|
|
||||||
if (!v.script.api) v.script.api = createAPI(v.script.api_url);
|
|
||||||
|
|
||||||
const w = window as any;
|
|
||||||
const finalScope = mergeScopeUpwards(v, item.id, scopeIndex);
|
|
||||||
const args = {
|
|
||||||
...w.exports,
|
|
||||||
...finalScope,
|
|
||||||
db: v.script.db,
|
|
||||||
api: v.script.api,
|
|
||||||
};
|
|
||||||
|
|
||||||
const result: any = {};
|
|
||||||
for (const [name, _prop] of cprops) {
|
|
||||||
const prop = props[name] || _prop;
|
|
||||||
|
|
||||||
let value: any = null;
|
|
||||||
|
|
||||||
if (prop.valueBuilt) {
|
|
||||||
const fn = new Function(
|
|
||||||
...Object.keys(args),
|
|
||||||
`return ${prop.valueBuilt}`
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
value = fn(...Object.values(args)) || null;
|
|
||||||
|
|
||||||
const navs = extractNavigate(prop.valueBuilt || "");
|
|
||||||
if (navs.length > 0) {
|
|
||||||
navs.map((nav) => preload(v, nav));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
const cname = meta.item.name;
|
|
||||||
console.warn(e);
|
|
||||||
console.warn(
|
|
||||||
`ERROR in Component [${cname}], in prop [${name}]:\n ` +
|
|
||||||
prop.value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prop.meta?.type === "content-element") {
|
|
||||||
if (!(typeof value === "object" && !!value && value._jsx)) {
|
|
||||||
const id = `${meta.item.id}-${name}`;
|
|
||||||
if (!jsxProps[id]) {
|
|
||||||
jsxProps[id] = {
|
|
||||||
_jsx: true,
|
|
||||||
Comp: ({
|
|
||||||
parent_id,
|
|
||||||
scopeIndex,
|
|
||||||
}: {
|
|
||||||
parent_id: string;
|
|
||||||
scopeIndex?: Record<string, any>;
|
|
||||||
}) => {
|
|
||||||
if (prop.content) {
|
|
||||||
const meta = v.meta[prop.content.id] as IMeta;
|
|
||||||
let parent = v.meta[parent_id];
|
|
||||||
|
|
||||||
if (meta && parent) {
|
|
||||||
meta.parent_item.id = parent_id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ViewMeta
|
|
||||||
id={prop.content.id}
|
|
||||||
scopeIndex={scopeIndex}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
value = jsxProps[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta.propval = result;
|
|
||||||
|
|
||||||
const propvis: any = {};
|
|
||||||
for (const [name, _prop] of cprops) {
|
|
||||||
const prop = props[name] || _prop;
|
|
||||||
if (prop.visible) {
|
|
||||||
const finalArgs = { ...args, ...result };
|
|
||||||
try {
|
|
||||||
const fn = new Function(
|
|
||||||
...Object.keys(finalArgs),
|
|
||||||
`return ${_prop.visible}`
|
|
||||||
);
|
|
||||||
propvis[name] = fn(...Object.values(finalArgs));
|
|
||||||
} catch (e) {
|
|
||||||
const cname = meta.item.name;
|
|
||||||
console.warn(e);
|
|
||||||
console.warn(
|
|
||||||
`ERROR in Component [${cname}], in prop [${name}]:\n ` +
|
|
||||||
prop.visible
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
meta.propvis = propvis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
import { ReactNode, useEffect, useState } from "react";
|
|
||||||
import { deepClone } from "web-utils";
|
|
||||||
import { IMeta } from "../../../../ed/logic/ed-global";
|
|
||||||
import { VG } from "../../../logic/global";
|
|
||||||
import { modifyChildScopeIndex } from "./mod-scope-index";
|
|
||||||
|
|
||||||
const cachedLocal = {} as Record<string, Record<string, any>>;
|
|
||||||
const cachedPath = {} as Record<string, Record<string, any>>;
|
|
||||||
const cachedLayout = {} as Record<string, true>;
|
|
||||||
export const createLocal = (
|
|
||||||
v: VG,
|
|
||||||
id: string,
|
|
||||||
existingScopeIndex?: Record<string, any>
|
|
||||||
) => {
|
|
||||||
return ({
|
|
||||||
name,
|
|
||||||
idx: local_id,
|
|
||||||
value,
|
|
||||||
effect,
|
|
||||||
children,
|
|
||||||
hook,
|
|
||||||
deps,
|
|
||||||
cache,
|
|
||||||
}: {
|
|
||||||
name: string;
|
|
||||||
value: any;
|
|
||||||
idx?: string;
|
|
||||||
effect?: (value: any) => void | Promise<void>;
|
|
||||||
children: ReactNode;
|
|
||||||
hook?: (value: any) => void;
|
|
||||||
deps?: any[];
|
|
||||||
cache?: boolean;
|
|
||||||
}) => {
|
|
||||||
const meta = v.meta[id] as IMeta;
|
|
||||||
const [_, set] = useState({});
|
|
||||||
|
|
||||||
let scope = null as any;
|
|
||||||
if (!local_id) {
|
|
||||||
if (!meta.scope) {
|
|
||||||
meta.scope = {};
|
|
||||||
}
|
|
||||||
scope = meta.scope;
|
|
||||||
} else {
|
|
||||||
if (!meta.indexed_scope) {
|
|
||||||
meta.indexed_scope = {};
|
|
||||||
}
|
|
||||||
if (!meta.indexed_scope[local_id]) meta.indexed_scope[local_id] = {};
|
|
||||||
scope = meta.indexed_scope[local_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
const render = () => {
|
|
||||||
if (!local_id) {
|
|
||||||
if (meta.render) meta.render();
|
|
||||||
else v.render();
|
|
||||||
} else {
|
|
||||||
set({});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const genScope = () => {
|
|
||||||
try {
|
|
||||||
const nval = deepClone(value);
|
|
||||||
|
|
||||||
if (!scope[name]) {
|
|
||||||
scope[name] = {
|
|
||||||
...nval,
|
|
||||||
render,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
for (const [k, v] of Object.entries(nval)) {
|
|
||||||
scope[name][k] = v;
|
|
||||||
}
|
|
||||||
scope[name].render = render;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let page_id = v.current.page_id || "";
|
|
||||||
const itemid = meta.item.id + (local_id ? `_${local_id}` : "");
|
|
||||||
|
|
||||||
if (meta.is_layout) {
|
|
||||||
page_id = "layout";
|
|
||||||
if (cachedLayout[meta.item.id]) {
|
|
||||||
scope[name] = cachedLocal[page_id][itemid];
|
|
||||||
scope[name].render = render;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
page_id !== "layout" ||
|
|
||||||
(page_id === "layout" && !cachedLayout[meta.item.id])
|
|
||||||
) {
|
|
||||||
if (!cachedLocal[page_id]) {
|
|
||||||
cachedLocal[page_id] = {};
|
|
||||||
}
|
|
||||||
if (!cachedPath[page_id]) {
|
|
||||||
cachedPath[page_id] = {};
|
|
||||||
}
|
|
||||||
if (cachedLocal[page_id][itemid]) {
|
|
||||||
if (cache === false) {
|
|
||||||
if (cachedPath[page_id][itemid] !== location.href) {
|
|
||||||
cachedPath[page_id][itemid] = location.href;
|
|
||||||
genScope();
|
|
||||||
cachedLocal[page_id][itemid] = scope[name];
|
|
||||||
} else {
|
|
||||||
scope[name] = cachedLocal[page_id][itemid];
|
|
||||||
scope[name].render = render;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scope[name] = cachedLocal[page_id][itemid];
|
|
||||||
scope[name].render = render;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
genScope();
|
|
||||||
cachedLocal[page_id][itemid] = scope[name];
|
|
||||||
cachedPath[page_id][itemid] = location.href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof hook === "function") {
|
|
||||||
try {
|
|
||||||
hook(scope[name]);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (effect) {
|
|
||||||
if (meta.is_layout) {
|
|
||||||
if (cachedLayout[meta.item.id]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cachedLayout[meta.item.id] = true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
effect(scope[name]);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [...(deps || []), location.href]);
|
|
||||||
|
|
||||||
if (local_id) {
|
|
||||||
const scopeIndex = { ...existingScopeIndex, [meta.item.id]: local_id };
|
|
||||||
return modifyChildScopeIndex(children, scopeIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
import { ReactNode } from "react";
|
|
||||||
import { VG } from "../../../logic/global";
|
|
||||||
import { modifyChildScopeIndex } from "./mod-scope-index";
|
|
||||||
import hash_sum from "hash-sum";
|
|
||||||
|
|
||||||
export const createPassProp = (
|
|
||||||
v: VG,
|
|
||||||
id: string,
|
|
||||||
existingScopeIndex?: Record<string, any>
|
|
||||||
) => {
|
|
||||||
return (arg: Record<string, any> & { children: ReactNode; idx?: any }) => {
|
|
||||||
const meta = v.meta[id];
|
|
||||||
|
|
||||||
if (arg.idx &&meta && meta.item && meta.item.id) {
|
|
||||||
let idx = arg.idx;
|
|
||||||
if (!idx) {
|
|
||||||
const narg: any = {};
|
|
||||||
for (const [k, v] of Object.entries(arg)) {
|
|
||||||
if (typeof v !== "object" && typeof v !== "function") {
|
|
||||||
narg[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idx = hash_sum(narg);
|
|
||||||
arg.idx = idx;
|
|
||||||
}
|
|
||||||
meta.indexed_scope[idx] = {};
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(arg)) {
|
|
||||||
if (k === "children") continue;
|
|
||||||
meta.indexed_scope[idx][k] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
const scopeIndex = { ...existingScopeIndex, [meta.item.id]: idx };
|
|
||||||
|
|
||||||
if (!meta.scope) {
|
|
||||||
meta.scope = {};
|
|
||||||
}
|
|
||||||
for (const [k, v] of Object.entries(arg)) {
|
|
||||||
if (k === "children") continue;
|
|
||||||
meta.scope[k] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return modifyChildScopeIndex(arg.children, scopeIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!meta.scope) {
|
|
||||||
meta.scope = {};
|
|
||||||
}
|
|
||||||
for (const [k, v] of Object.entries(arg)) {
|
|
||||||
if (k === "children") continue;
|
|
||||||
meta.scope[k] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
return arg.children;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
import { useErrorBoundary, withErrorBoundary } from "react-use-error-boundary";
|
|
||||||
import { useGlobal, useLocal } from "web-utils";
|
|
||||||
import { IMeta } from "../../../../ed/logic/ed-global";
|
|
||||||
import { ViewGlobal } from "../../../logic/global";
|
|
||||||
|
|
||||||
export const ErrorBox = withErrorBoundary(
|
|
||||||
({
|
|
||||||
children,
|
|
||||||
meta,
|
|
||||||
id,
|
|
||||||
silent,
|
|
||||||
}: {
|
|
||||||
children: any;
|
|
||||||
meta?: IMeta;
|
|
||||||
id?: string;
|
|
||||||
silent?: boolean;
|
|
||||||
}) => {
|
|
||||||
const local = useLocal({ retrying: false });
|
|
||||||
const [error, resetError] = useErrorBoundary((error, errorInfo) => {
|
|
||||||
if (silent !== true) console.warn(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
let _meta = meta;
|
|
||||||
if (id) {
|
|
||||||
const p = useGlobal(ViewGlobal, "VIEW");
|
|
||||||
_meta = p.meta[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<div className="bg-red-100 border border-red-300 rounded-sm text-xs flex flex-col items-center">
|
|
||||||
<div className="text-[10px] font-bold text-red-900 self-stretch px-1">
|
|
||||||
ERROR {_meta?.item.name ? "[" + _meta.item.name + "]:" : ""}
|
|
||||||
</div>
|
|
||||||
<p className="border-b border-red-300 px-1 pb-1 min-w-[100px]">
|
|
||||||
{!local.retrying ? <>{(error as any).message}</> : <>Retrying...</>}
|
|
||||||
</p>
|
|
||||||
<div className="p-1">
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
local.retrying = true;
|
|
||||||
local.render();
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
local.retrying = false;
|
|
||||||
local.render();
|
|
||||||
resetError();
|
|
||||||
}, 100);
|
|
||||||
}}
|
|
||||||
className="bg-white border border-white hover:border-red-400 hover:bg-red-50 rounded px-2"
|
|
||||||
>
|
|
||||||
Try again
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import { IMeta } from "../../../../ed/logic/ed-global";
|
|
||||||
import { VG } from "../../../logic/global";
|
|
||||||
|
|
||||||
export const mergeScopeUpwards = (
|
|
||||||
v: VG,
|
|
||||||
id: string,
|
|
||||||
scopeIndex?: Record<string, any>,
|
|
||||||
each?: (meta: IMeta, values: Record<string, any>) => boolean
|
|
||||||
) => {
|
|
||||||
const meta = v.meta[id];
|
|
||||||
|
|
||||||
if (!meta.scope) {
|
|
||||||
meta.scope = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
let cur = meta;
|
|
||||||
const finalScope: any = {};
|
|
||||||
|
|
||||||
while (cur) {
|
|
||||||
let scope = null;
|
|
||||||
|
|
||||||
let indexedScope = null;
|
|
||||||
|
|
||||||
if (cur.indexed_scope && scopeIndex) {
|
|
||||||
const idx = scopeIndex[cur.item.id];
|
|
||||||
|
|
||||||
if (typeof idx !== "undefined" && cur.indexed_scope[idx]) {
|
|
||||||
indexedScope = cur.indexed_scope[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexedScope || cur.scope || cur.propval) {
|
|
||||||
scope = { ...cur.scope, ...indexedScope, ...cur.propval };
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(scope)) {
|
|
||||||
if (typeof finalScope[k] === "undefined") finalScope[k] = v;
|
|
||||||
}
|
|
||||||
if (each) {
|
|
||||||
if (!each(cur, scope)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = v.meta[cur.parent_item.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalScope;
|
|
||||||
};
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import { Fragment, ReactNode } from "react";
|
|
||||||
|
|
||||||
export const modifyChildScopeIndex = (
|
|
||||||
child: ReactNode | ReactNode[],
|
|
||||||
scopeIndex: Record<string, any>
|
|
||||||
) => {
|
|
||||||
if (Array.isArray(child)) {
|
|
||||||
const childs: any[] = [];
|
|
||||||
for (const c of child) {
|
|
||||||
childs.push(modifyChildScopeIndex(c, scopeIndex));
|
|
||||||
}
|
|
||||||
return childs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof child === "object" && child) {
|
|
||||||
const c = child as any;
|
|
||||||
if (c.type === Fragment) {
|
|
||||||
return (
|
|
||||||
<Fragment key={c.key}>
|
|
||||||
{modifyChildScopeIndex(c.props.children, scopeIndex)}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return { ...child, props: { ...(child as any).props, scopeIndex } };
|
|
||||||
}
|
|
||||||
return child;
|
|
||||||
};
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
import { FC, ReactNode, Suspense } from "react";
|
|
||||||
import { useGlobal } from "web-utils";
|
|
||||||
import { Loading } from "../../utils/ui/loading";
|
|
||||||
import { IMeta } from "../ed/logic/ed-global";
|
|
||||||
import { ViewGlobal } from "./logic/global";
|
|
||||||
import { vInit } from "./logic/init";
|
|
||||||
import { newLoadCode } from "./logic/load-code-new";
|
|
||||||
import { oldLoadCode } from "./logic/load-code-old";
|
|
||||||
import { VLoad, VLoadComponent } from "./logic/types";
|
|
||||||
import { VEntry } from "./render/entry";
|
|
||||||
import { ErrorBox } from "./render/meta/script/error-box";
|
|
||||||
|
|
||||||
type ViewProp = {
|
|
||||||
load: VLoad;
|
|
||||||
component: VLoadComponent;
|
|
||||||
site_id: string;
|
|
||||||
page_id: string;
|
|
||||||
api_url: string;
|
|
||||||
mode: "desktop" | "mobile";
|
|
||||||
code_mode?: "old" | "new";
|
|
||||||
layout?: { show: boolean };
|
|
||||||
isEditor?: boolean;
|
|
||||||
bind?: (arg: { render: () => void }) => void;
|
|
||||||
hidden?: (item: IMeta) => boolean;
|
|
||||||
hover?: { get: (item: IMeta) => boolean; set: (meta: IMeta) => void };
|
|
||||||
active?: {
|
|
||||||
get: (item: IMeta) => boolean;
|
|
||||||
set: (item: IMeta) => void;
|
|
||||||
text?: (arg: { meta: IMeta }) => ReactNode;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const View: FC<ViewProp> = (props) => {
|
|
||||||
return (
|
|
||||||
<ErrorBox>
|
|
||||||
<Suspense>
|
|
||||||
<BoxedView {...props} />
|
|
||||||
</Suspense>
|
|
||||||
</ErrorBox>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BoxedView: FC<ViewProp> = ({
|
|
||||||
load,
|
|
||||||
site_id,
|
|
||||||
layout,
|
|
||||||
page_id,
|
|
||||||
bind,
|
|
||||||
code_mode,
|
|
||||||
hover,
|
|
||||||
active,
|
|
||||||
hidden,
|
|
||||||
component,
|
|
||||||
api_url,
|
|
||||||
mode,
|
|
||||||
isEditor,
|
|
||||||
}) => {
|
|
||||||
const v = useGlobal(ViewGlobal, "VIEW");
|
|
||||||
|
|
||||||
v.script.api_url = api_url;
|
|
||||||
if (hidden) v.view.hidden = hidden;
|
|
||||||
if (hover && !v.view.hover) v.view.hover = hover;
|
|
||||||
if (active && !v.view.active) v.view.active = active;
|
|
||||||
|
|
||||||
if (v.current.page_id !== page_id || v.current.site_id !== site_id) {
|
|
||||||
v.status = "init";
|
|
||||||
}
|
|
||||||
|
|
||||||
v.layout = layout ? layout : { show: false };
|
|
||||||
v.component.load = component.load;
|
|
||||||
|
|
||||||
if (bind) {
|
|
||||||
bind({
|
|
||||||
render() {
|
|
||||||
v.status = "rebuild";
|
|
||||||
v.render();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.status === "init") {
|
|
||||||
vInit(v, { load, page_id, site_id, mode, isEditor: !!isEditor });
|
|
||||||
if (v.status === "init") {
|
|
||||||
return <Loading backdrop={false} note="init" />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.status === "load-code" || v.status === "loading-code") {
|
|
||||||
if (!code_mode || code_mode === "new") {
|
|
||||||
newLoadCode(v);
|
|
||||||
} else {
|
|
||||||
oldLoadCode(v);
|
|
||||||
}
|
|
||||||
if (v.status === "load-code" || v.status === "loading-code") {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Loading backdrop={false} note="rendering-view" />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.status === "rebuild") {
|
|
||||||
if (load.mode === "tree_meta") {
|
|
||||||
v.meta = load.meta;
|
|
||||||
v.entry = load.entry;
|
|
||||||
}
|
|
||||||
v.body_cache = <VEntry />;
|
|
||||||
v.status = "ready";
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="flex flex-1 flex-col relative">{v.body_cache}</div>;
|
|
||||||
};
|
|
||||||
Loading…
Reference in New Issue