250 lines
6.9 KiB
TypeScript
250 lines
6.9 KiB
TypeScript
import { createId } from "@paralleldrive/cuid2";
|
|
import type { Doc } from "yjs";
|
|
import { FMCompDef } from "../../../../utils/types/meta-fn";
|
|
import { IMeta, active } from "../../../ed/logic/ed-global";
|
|
import { VG } from "../global";
|
|
import { ViRender } from "../render";
|
|
import { viScriptArg } from "./arg";
|
|
import { replaceWithObject, replacement } from "./eval-script";
|
|
import { extractNavigate } from "./extract-nav";
|
|
|
|
export const w = window as any;
|
|
|
|
export const viEvalProps = (
|
|
vi: {
|
|
layout: VG["layout"];
|
|
mode: VG["mode"];
|
|
meta: VG["meta"];
|
|
site: { db: any; api: any };
|
|
page: VG["page"];
|
|
on_nav_loaded?: VG["on_preload"];
|
|
},
|
|
meta: IMeta,
|
|
is_layout: boolean,
|
|
passprop: any,
|
|
parent_key?: any
|
|
) => {
|
|
if (meta.item.component?.id) {
|
|
let script = meta.item.script;
|
|
|
|
if (parent_key) {
|
|
if (!meta.item.script_keyed) meta.item.script_keyed = {};
|
|
if (!meta.item.script_keyed[parent_key])
|
|
meta.item.script_keyed[parent_key] = {};
|
|
script = meta.item.script_keyed[parent_key];
|
|
} else {
|
|
if (!meta.item.script) {
|
|
meta.item.script = {};
|
|
}
|
|
script = meta.item.script;
|
|
}
|
|
|
|
if (!script) return;
|
|
|
|
const exports = (window as any).exports;
|
|
const arg = {
|
|
...exports,
|
|
db: vi.site.db,
|
|
api: vi.site.api,
|
|
...viScriptArg(vi),
|
|
...passprop,
|
|
params,
|
|
};
|
|
|
|
script.props = {};
|
|
let fails = new Set<string>();
|
|
if (!!meta.item.component.props) {
|
|
const _props: any = {};
|
|
for (const [name, prop] of Object.entries(meta.item.component.props)) {
|
|
try {
|
|
if (prop.meta?.type === "content-element") {
|
|
let val = {
|
|
_jsx: true,
|
|
fn: (arg: { passprop: any; meta: IMeta; prop_name: string }) => {
|
|
const id = prop.content?.id;
|
|
if (id) {
|
|
const m = is_layout ? vi.layout?.meta[id] : vi.meta[id];
|
|
|
|
if (!m) return null;
|
|
|
|
const instances = meta.instances;
|
|
if (!arg.meta.item.originalId || !instances) {
|
|
return null;
|
|
}
|
|
|
|
const instance = instances[meta.item.id];
|
|
if (!instance) return null;
|
|
const original_id = arg.meta.item.originalId;
|
|
if (
|
|
m.mitem &&
|
|
((prop.jsxCalledBy &&
|
|
(!prop.jsxCalledBy.includes(original_id) ||
|
|
prop.jsxCalledBy.length !== 2)) ||
|
|
!prop.jsxCalledBy)
|
|
) {
|
|
const mprop = meta.mitem
|
|
?.get("component")
|
|
?.get("props")
|
|
?.get(name);
|
|
if (mprop) {
|
|
let mjby = mprop.get("jsxCalledBy");
|
|
if (!mjby || typeof mjby !== "object") {
|
|
mprop.set("jsxCalledBy", [meta.item.id, original_id]);
|
|
} else {
|
|
if (
|
|
mjby &&
|
|
(!mjby.includes(original_id) ||
|
|
mjby.length !== 2 ||
|
|
mjby[0] !== meta.item.id ||
|
|
mjby[1] !== original_id)
|
|
) {
|
|
mprop.set("jsxCalledBy", [meta.item.id, original_id]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (
|
|
<ViRender
|
|
meta={m}
|
|
passprop={arg.passprop}
|
|
is_layout={is_layout}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
},
|
|
};
|
|
|
|
arg[name] = val;
|
|
|
|
if (passprop) {
|
|
passprop[name] = val;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (prop.value) {
|
|
extractNavigate(vi, prop.value);
|
|
}
|
|
|
|
if (!prop.valueBuilt && prop.value && meta.mitem) {
|
|
const mprop = meta.mitem?.get("component")?.get("props")?.get(name);
|
|
if (mprop) {
|
|
updatePropValueBuilt(mprop, prop.value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const js = prop.valueBuilt || "";
|
|
const src = replaceWithObject(js, replacement) || "";
|
|
const fn = new Function(
|
|
...Object.keys(arg),
|
|
`// [${meta.item.name}] ${name}: ${meta.item.id}
|
|
return ${src}
|
|
`
|
|
);
|
|
|
|
script.props[name] = { value: src };
|
|
let val = fn(...Object.values(arg));
|
|
|
|
if (typeof val === "function") {
|
|
script.props[name].fn = val;
|
|
val = (...args: any[]) => {
|
|
if (script) return script.props?.[name].fn(...args);
|
|
};
|
|
}
|
|
|
|
arg[name] = val;
|
|
_props[name] = val;
|
|
|
|
if (passprop) {
|
|
passprop[name] = val;
|
|
}
|
|
} catch (e) {
|
|
fails.add(name);
|
|
}
|
|
}
|
|
|
|
if (location.pathname.startsWith("/ed/") && active.item_id) {
|
|
if (meta.item.id === active.item_id) {
|
|
active.scope = {};
|
|
for (const [k, v] of Object.entries(passprop)) {
|
|
active.scope[k] = v;
|
|
}
|
|
|
|
active.scope.self_props = _props;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const conf = {
|
|
timeout: null as any,
|
|
set: new WeakSet<FMCompDef>(),
|
|
map: {} as Record<string, { mprop: FMCompDef }>,
|
|
src: {} as Record<string, string>,
|
|
};
|
|
const updatePropValueBuilt = (mprop: FMCompDef, src: string) => {
|
|
if (!conf.set.has(mprop)) {
|
|
conf.set.add(mprop);
|
|
const id = createId();
|
|
conf.map[id] = { mprop };
|
|
conf.src[id] = src;
|
|
}
|
|
clearTimeout(conf.timeout);
|
|
conf.timeout = setTimeout(async () => {
|
|
const result = await _api.code_build(conf.src);
|
|
|
|
let doc = null as unknown as Doc;
|
|
for (const [k, v] of Object.entries(result)) {
|
|
const mprop = conf.map[k].mprop;
|
|
if (!doc && mprop.doc) {
|
|
doc = mprop.doc;
|
|
break;
|
|
}
|
|
}
|
|
if (doc) {
|
|
doc.transact(() => {
|
|
for (const [k, v] of Object.entries(result)) {
|
|
const mprop = conf.map[k].mprop;
|
|
mprop.set("valueBuilt", v);
|
|
}
|
|
});
|
|
|
|
conf.set = new WeakSet();
|
|
conf.map = {};
|
|
conf.src = {};
|
|
}
|
|
}, 300);
|
|
};
|
|
|
|
export const updatePropScope = (
|
|
vi: { site: { db: any; api: any } },
|
|
meta: IMeta,
|
|
scope: any,
|
|
parent_key?: any
|
|
) => {
|
|
const script = parent_key
|
|
? meta.item.script_keyed?.[parent_key]
|
|
: meta.item.script;
|
|
|
|
if (!script) return;
|
|
|
|
if (script.props) {
|
|
const scopes = { ...scope, api: vi.site.api, db: vi.site.db };
|
|
for (const [name, prop] of Object.entries(script.props)) {
|
|
if (prop.fn) {
|
|
const fn = new Function(
|
|
...Object.keys(scopes),
|
|
`// [${meta.item.name}] ${name}: ${meta.item.id}
|
|
return ${prop.value || ""}
|
|
`
|
|
);
|
|
prop.fn = fn(...Object.values(scopes));
|
|
}
|
|
}
|
|
}
|
|
};
|