diff --git a/app/srv/ws/sync/actions/page_load.ts b/app/srv/ws/sync/actions/page_load.ts index 7068dc3b..c4e0b73b 100644 --- a/app/srv/ws/sync/actions/page_load.ts +++ b/app/srv/ws/sync/actions/page_load.ts @@ -184,6 +184,7 @@ const scanMeta = async (doc: DPage, sync: SyncConnection) => { await Promise.all( childs.map((m) => serverWalkLoad(m, scope_comps, sync, loaded)) ); + childs.map((m, i) => { serverWalkMap( { sync, scope, scope_comps, note: "page-load" }, diff --git a/app/srv/ws/sync/editor/load-component.ts b/app/srv/ws/sync/editor/load-component.ts index 7d840ecf..21f53d8e 100644 --- a/app/srv/ws/sync/editor/load-component.ts +++ b/app/srv/ws/sync/editor/load-component.ts @@ -29,7 +29,8 @@ export const loadComponent = async (id: string, sync: SyncConnection) => { const sv_local = await gzipAsync(update); - user.active.findAll({ comp_id: id }).map((e) => { + const all = user.active.findAll({ comp_id: id }); + all.map((e) => { if (origin !== um) { if (e.client_id === origin) return; } diff --git a/app/srv/ws/sync/editor/load-page.ts b/app/srv/ws/sync/editor/load-page.ts index 007a2bcb..051acefd 100644 --- a/app/srv/ws/sync/editor/load-page.ts +++ b/app/srv/ws/sync/editor/load-page.ts @@ -15,7 +15,11 @@ import { SyncConnection } from "../type"; import { loadComponent } from "./load-component"; import { extractMItemProps } from "./load-page-comp"; import { ArgParentMComp, parseJs } from "./parser/parse-js"; +import { user } from "../entity/user"; +const defaultActive = { + select: "" as "" | "comp" | "item" | "section" | "text", +}; export const serverWalkLoad = async ( mitem: MItem, scope_comps: IScopeComp, @@ -35,6 +39,18 @@ export const serverWalkLoad = async ( loaded.add(id); if (!docs.comp[id]) { await loadComponent(id, sync); + } else { + const conf = sync.conf; + if (conf) { + user.active.add({ + ...defaultActive, + client_id: sync.client_id, + user_id: sync.user_id, + site_id: conf.site_id, + page_id: conf.page_id, + comp_id: comp.id, + }); + } } const pcomp = docs.comp[id]; diff --git a/app/web/src/nova/ed/ed-mid.tsx b/app/web/src/nova/ed/ed-mid.tsx index 59d8fca1..81444151 100644 --- a/app/web/src/nova/ed/ed-mid.tsx +++ b/app/web/src/nova/ed/ed-mid.tsx @@ -5,7 +5,6 @@ import { EdAddText } from "./panel/header/mid/add-text"; import { EdCompPicker } from "./panel/header/mid/comp-picker"; import { EdPagePicker } from "./panel/header/mid/page-picker"; import { TopBtn } from "./panel/header/top-btn"; -import { EdMain } from "./panel/main/main"; export const EdMid: FC<{}> = () => { return ( @@ -15,12 +14,12 @@ export const EdMid: FC<{}> = () => { "h-[35px] border-b flex p-1 items-stretch text-[12px] justify-between" )} > -
+
-
-
+
+
ADD
diff --git a/app/web/src/nova/ed/panel/main/main.tsx b/app/web/src/nova/ed/panel/main/main.tsx index fffa7476..dcddd623 100644 --- a/app/web/src/nova/ed/panel/main/main.tsx +++ b/app/web/src/nova/ed/panel/main/main.tsx @@ -43,23 +43,37 @@ export const EdMain = () => { p.page.render = render; }} hidden={(meta) => { - if (meta.item.hidden) return true + if (meta.item.hidden) return true; return false; }} hover={{ get(meta) { const item = meta.item; - if (item.originalId === active.hover_id || item.id === active.hover_id) + if (active.comp_id) { + if (meta.parent_mcomp) { + if ( + meta.parent_mcomp?.mcomp.get("component")?.get("id") !== + active.comp_id + ) + return false; + } + } + + if ( + item.originalId === active.hover_id || + item.id === active.hover_id + ) return true; - return false + return false; }, set(meta) { if (meta.parent_mcomp) { - const id = meta.parent_mcomp.mitem.get('id'); + const id = meta.parent_mcomp.mitem.get("id"); if (active.instance.item_id !== id) { - const original_id = meta.parent_mcomp.mitem.get('originalId'); + const original_id = + meta.parent_mcomp.mitem.get("originalId"); if (active.comp_id && original_id) { active.hover_id = original_id; @@ -79,14 +93,14 @@ export const EdMain = () => { const parent = meta.parent_mcomp; if (parent) { const mcomp = parent.mcomp; - if (mcomp.get('component')?.get('id') === active.comp_id) { + if (mcomp.get("component")?.get("id") === active.comp_id) { active.hover_id = meta.item.originalId || meta.item.id; } } else { active.hover_id = meta.item.id; } } else { - active.hover_id = meta.item.id + active.hover_id = meta.item.id; } p.render(); @@ -97,18 +111,32 @@ export const EdMain = () => { get(meta) { const item = meta.item; - if (item.originalId === active.item_id || item.id === active.item_id) + if (active.comp_id) { + if (meta.parent_mcomp) { + if ( + meta.parent_mcomp?.mcomp.get("component")?.get("id") !== + active.comp_id + ) + return false; + } + } + + if ( + item.originalId === active.item_id || + item.id === active.item_id + ) return true; - return false + return false; }, set(meta) { if (meta.parent_mcomp) { - const id = meta.parent_mcomp.mitem.get('id'); + const id = meta.parent_mcomp.mitem.get("id"); if (active.instance.item_id !== id) { - const original_id = meta.parent_mcomp.mitem.get('originalId'); + const original_id = + meta.parent_mcomp.mitem.get("originalId"); - let active_id = "" + let active_id = ""; if (active.comp_id && original_id) { active_id = original_id; } else if (id) { @@ -119,7 +147,9 @@ export const EdMain = () => { if (active.item_id !== active_id) { active.item_id = active_id; } else { - const comp_id = meta.parent_mcomp.mcomp.get('component')?.get('id'); + const comp_id = meta.parent_mcomp.mcomp + .get("component") + ?.get("id"); if (comp_id) { active.instance.item_id = active_id; active.instance.comp_id = active.comp_id; @@ -147,7 +177,7 @@ export const EdMain = () => { const parent = meta.parent_mcomp; if (parent) { const mcomp = parent.mcomp; - if (mcomp.get('component')?.get('id') === active.comp_id) { + if (mcomp.get("component")?.get("id") === active.comp_id) { active.item_id = meta.item.originalId || meta.item.id; } } else { @@ -157,13 +187,12 @@ export const EdMain = () => { active.instance.comp_id = ""; } } else { - active.item_id = meta.item.id + active.item_id = meta.item.id; } p.render(); p.page.render(); focus(); - }, text(meta) { const { item } = meta; @@ -172,33 +201,40 @@ export const EdMain = () => { active.text.content = item.html || ""; } - return
{ - if (ref !== document.activeElement && ref) { - const renaming = document.querySelector('.rename-item'); - const modals = document.querySelectorAll('[data-floating-ui-portal]'); - if (modals.length === 0 && !renaming) { - ref.focus(); - setEndOfContenteditable(ref) + return ( +
{ + if (ref !== document.activeElement && ref) { + const renaming = document.querySelector(".rename-item"); + const modals = document.querySelectorAll( + "[data-floating-ui-portal]" + ); + if (modals.length === 0 && !renaming) { + ref.focus(); + setEndOfContenteditable(ref); + } } - } - }} - contentEditable - spellCheck={false} - onInput={(e) => { - const val = e.currentTarget.innerHTML; - active.text.id = item.id; - active.text.content = val; - }} - onBlur={() => { - const meta = getMetaById(p, item.id); - if (meta && meta.mitem && active.text.id === item.id) { - meta.mitem.set('html', active.text.content) - } - }} - dangerouslySetInnerHTML={{ __html: item.html || "" }}>
- } + }} + contentEditable + spellCheck={false} + onInput={(e) => { + const val = e.currentTarget.innerHTML; + active.text.id = item.id; + active.text.content = val; + }} + onBlur={() => { + const meta = getMetaById(p, item.id); + if (meta && meta.mitem && active.text.id === item.id) { + meta.mitem.set("html", active.text.content); + } + }} + dangerouslySetInnerHTML={{ __html: item.html || "" }} + >
+ ); + }, }} /> )} @@ -209,12 +245,12 @@ export const EdMain = () => { function setEndOfContenteditable(div: any) { let range: any, sel: any; - if (document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ - { + if (document.createRange) { + //Firefox, Chrome, Opera, Safari, IE 9+ range = document.createRange(); range.selectNodeContents(div); sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } -} \ No newline at end of file +} diff --git a/app/web/src/nova/ed/panel/popup/script/monaco.tsx b/app/web/src/nova/ed/panel/popup/script/monaco.tsx index f122608b..5c2140ae 100644 --- a/app/web/src/nova/ed/panel/popup/script/monaco.tsx +++ b/app/web/src/nova/ed/panel/popup/script/monaco.tsx @@ -7,7 +7,7 @@ import { useGlobal, useLocal } from "web-utils"; import { jscript } from "../../../../../utils/script/jscript"; import { jsMount } from "../../../../../utils/script/mount"; import { monacoTypings } from "../../../../../utils/script/typings"; -import { EDGlobal, active } from "../../../logic/ed-global"; +import { EDGlobal, EdMeta, active } from "../../../logic/ed-global"; import { getMetaById } from "../../../logic/tree/build"; import { declareScope } from "./scope"; @@ -30,9 +30,11 @@ export const ScriptMonaco = () => { const Editor = jscript.editor; if (!Editor) return null; - let meta = p.page.meta[active.item_id]; - if (active.comp_id && p.comp.list[active.comp_id]) { - meta = p.comp.list[active.comp_id].meta[active.item_id]; + let meta: EdMeta | null = p.page.meta[active.item_id]; + if (active.comp_id) { + if (p.comp.list[active.comp_id]) { + meta = p.comp.list[active.comp_id].meta[active.item_id]; + } else meta = null; } let val = ""; @@ -164,6 +166,8 @@ async () => { } } + if (!meta) return null; + return ( { const p = useGlobal(EDGlobal, "EDITOR"); diff --git a/app/web/src/nova/ed/panel/tree/search.tsx b/app/web/src/nova/ed/panel/tree/search.tsx index 60e21479..caeb5432 100644 --- a/app/web/src/nova/ed/panel/tree/search.tsx +++ b/app/web/src/nova/ed/panel/tree/search.tsx @@ -1,7 +1,7 @@ import { NodeModel } from "@minoru/react-dnd-treeview"; import { useEffect } from "react"; import { useGlobal, useLocal } from "web-utils"; -import { EDGlobal, EdMeta, PG } from "../../logic/ed-global"; +import { EDGlobal, EdMeta, PG, active } from "../../logic/ed-global"; import { fuzzy } from "../../../../utils/ui/fuzzy"; export const EdTreeSearch = () => { @@ -115,7 +115,13 @@ export const doTreeSearch = (p: PG) => { const search = p.ui.tree.search.toLowerCase(); let i = 0; - for (const row of p.page.tree) { + + let ptree = p.page.tree; + if (active.comp_id && p.comp.list[active.comp_id].tree) { + ptree = p.comp.list[active.comp_id].tree; + } + + for (const row of ptree) { const item = row.data?.item; if (item) { const js = item.adv?.js; diff --git a/app/web/src/nova/view/render/meta/script.tsx b/app/web/src/nova/view/render/meta/script.tsx index 65600800..c68f1680 100644 --- a/app/web/src/nova/view/render/meta/script.tsx +++ b/app/web/src/nova/view/render/meta/script.tsx @@ -136,7 +136,6 @@ export const ViewMetaScript: FC<{ } const output = { jsx: null as any }; - args = { ...w.exports, ...finalScope, diff --git a/app/web/src/nova/view/render/meta/script/comp-propval.tsx b/app/web/src/nova/view/render/meta/script/comp-propval.tsx index 0613944d..0059b37d 100644 --- a/app/web/src/nova/view/render/meta/script/comp-propval.tsx +++ b/app/web/src/nova/view/render/meta/script/comp-propval.tsx @@ -22,93 +22,90 @@ export const compPropVal = ( props = icomp.props; cprops = Object.entries({ ...icomp.props }); - 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); + 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 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; + 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}` + 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 ); - - 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; - }) => { - if (prop.content) { - const meta = v.meta[prop.content.id] as EdMeta; - let parent = v.meta[parent_id]; - - if (meta && parent) { - if (v.scope) { - while (parent) { - if (v.scope[parent.item.id]) { - v.scope[prop.content.id] = - v.scope[parent.item.id]; - } - parent = v.meta[parent.parent_item.id]; - } - } - - return ( - - ); - } - } - return <>; - }, - }; - } - value = jsxProps[id]; - } - } - - result[name] = 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; + }) => { + if (prop.content) { + const meta = v.meta[prop.content.id] as EdMeta; + let parent = v.meta[parent_id]; + + if (meta && parent) { + if (v.scope) { + while (parent) { + if (v.scope[parent.item.id]) { + v.scope[prop.content.id] = v.scope[parent.item.id]; + } + parent = v.meta[parent.parent_item.id]; + } + } + + return ( + + ); + } + } + return <>; + }, + }; + } + value = jsxProps[id]; + } + } + + result[name] = value; meta.propval = result; } } diff --git a/app/web/src/utils/script/init-api.ts b/app/web/src/utils/script/init-api.ts index 6826206d..0e4f2b67 100644 --- a/app/web/src/utils/script/init-api.ts +++ b/app/web/src/utils/script/init-api.ts @@ -21,7 +21,7 @@ export const createAPI = (url: string) => { w.prasiApi = {}; } if (!url) { - throw new Error("No URL provided"); + return null; } return w.apiClient(w.prasiApi[url]?.apiEntry, url); diff --git a/app/web/src/utils/sync/idx-map.ts b/app/web/src/utils/sync/idx-map.ts index 3b05321d..6037d9c4 100644 --- a/app/web/src/utils/sync/idx-map.ts +++ b/app/web/src/utils/sync/idx-map.ts @@ -1,38 +1,68 @@ +import hash_sum from "hash-sum"; + +const match = (item: any, where: any) => { + for (const [k, v] of Object.entries(where)) { + if (item[k] !== v) return false; + } + + return true; +}; + export const IndexedMap = { create: , KEY extends string>(id: KEY) => { - const all = {} as Record>; + const all = {} as Record>; return { - add(item: OBJ & Record) { - const _id = item[id]; - all[_id] = item as any; - return _id; + add(item: OBJ & Record) { + const pk = item[id] as KEY; + + if (!all[pk]) { + all[pk] = {}; + } + const _id = hash_sum(item) as any; + + const items = all[pk] as Record; + items[_id] = item; + + return pk; }, - find(id: string) { - return all[id]; - }, - del(id: string) { - delete all[id]; - }, - findAll(where: Partial>) { - return Object.entries(all) - .filter(([k, item]) => { - for (const f in where) { - if (f === id) { - if (k !== where[f]) { - return false; + findAll(where: Partial>, withId?: boolean) { + const founds = []; + if (where[id]) { + const _id = where[id] as KEY; + + if (all[_id]) { + for (const [k, item] of Object.entries(all[_id])) { + if (match(item, where)) { + if (withId) { + founds.push({ ...item, _id: k }); + } else { + founds.push(item); } - } else if (item[f] !== where[f]) { - return false; } } - return true; - }) - .map(([_, item]) => item); + } + } else { + for (const _items of Object.values(all)) { + const items = _items as Record; + + for (const [k, item] of Object.entries(items)) { + if (match(item, where)) { + if (withId) { + founds.push({ ...item, _id: k }); + } else { + founds.push(item); + } + } + } + } + } + + return founds; }, delAll(where: Partial>) { - for (const item of this.findAll(where)) { - delete all[item[id]]; + for (const item of this.findAll(where, true)) { + delete all[item[id]][item._id]; } }, };