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 {
|
||||
GenMetaP,
|
||||
IMeta as LogicMeta,
|
||||
ISimpleMeta,
|
||||
} from "../../view/logic/meta/types";
|
||||
IMeta as LogicMeta,
|
||||
} from "../../vi/utils/types";
|
||||
|
||||
export type IMeta = LogicMeta;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { ReactNode } from "react";
|
||||
import { parseJs } from "../../../../../../srv/ws/sync/editor/parser/parse-js";
|
||||
import { IContent } from "../../../../utils/types/general";
|
||||
import { IItem, MItem } from "../../../../utils/types/item";
|
||||
import { createViLocal } from "../../../vi/render/script/local";
|
||||
import { createViPassProp } from "../../../vi/render/script/passprop";
|
||||
import { parseJs } from "../../../../../srv/ws/sync/editor/parser/parse-js";
|
||||
import { IContent } from "../../../utils/types/general";
|
||||
import { IItem, MItem } from "../../../utils/types/item";
|
||||
import { createViLocal } from "../render/script/local";
|
||||
import { createViPassProp } from "../render/script/passprop";
|
||||
|
||||
export type GenMetaP = {
|
||||
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