UNPKG

@dooboostore/dom-render

Version:
605 lines (604 loc) 23.9 kB
import { RawSet } from "./rawsets/RawSet.js"; import { EventManager } from "./events/EventManager.js"; import { DomRenderFinalProxy, Shield } from "./types/Types.js"; import { RawSetType } from "./rawsets/RawSetType.js"; import { DrThisProperty } from "./operators/DrThisProperty.js"; import { RawSetOperatorType } from "./rawsets/RawSetOperatorType.js"; import { ComponentSet } from "./components/ComponentSet.js"; import { DomRenderNoProxyKey, isDomRenderNoProxy } from "./decorators/DomRenderNoProxy.js"; import { isOnCreateRender } from "./lifecycle/OnCreateRender.js"; import { isOnInitRender } from "./lifecycle/OnInitRender.js"; import { isOnCreateRenderData } from "./lifecycle/OnCreateRenderData.js"; import { isOnChangeAttrRender } from "./lifecycle/OnChangeAttrRender.js"; import { DocumentUtils } from "@dooboostore/core-web"; import { isOnBeforeReturnSet } from "./lifecycle/OnBeforeReturnSet.js"; import { isOnChildRenderedByProperty } from "./lifecycle/OnChildRenderedByProperty.js"; import { ObjectUtils } from "@dooboostore/core"; import { ValidUtils } from "@dooboostore/core"; import { isOnProxyDomRender } from "./lifecycle/OnProxyDomRender.js"; import { isOnRawSetRendered } from "./lifecycle/OnRawSetRendered.js"; import { isOnChildRawSetRendered } from "./lifecycle/OnChildRawSetRendered.js"; import { DomRenderComponentMetaKey, DomRenderProxyMetaKey } from "./rawsets/index.js"; const excludeGetSetPropertys = [ DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY, DomRenderProxyMetaKey.onBeforeReturnGet, DomRenderProxyMetaKey.onBeforeReturnSet, DomRenderProxyMetaKey.__render, DomRenderProxyMetaKey._rawSets, DomRenderProxyMetaKey._targets, DomRenderProxyMetaKey._domRender_proxy, DomRenderProxyMetaKey._DomRender_isFinal, DomRenderProxyMetaKey._domRender_ref, DomRenderProxyMetaKey._DomRender_origin, DomRenderProxyMetaKey._DomRender_ref, DomRenderProxyMetaKey._DomRender_proxy ]; const isWrapProxyDomRenderProxy = (obj) => { return obj && typeof obj === "object" && "_DomRender_isProxy" in obj; }; const getDomRenderOriginObject = (obj) => { if (isWrapProxyDomRenderProxy(obj)) { return obj._domRender_origin; } return obj; }; const getDomRenderConfig = (obj) => { if (isWrapProxyDomRenderProxy(obj)) { return obj._domRender_config; } return void 0; }; const getDomRenderProxy = (obj) => { if (isWrapProxyDomRenderProxy(obj)) { return obj._domRender_proxy; } return void 0; }; class DomRenderProxy { // public name = Math.random(); constructor(_domRender_origin, target, _domRender_config) { this._domRender_origin = _domRender_origin; this._domRender_config = _domRender_config; this._domRender_ref = /* @__PURE__ */ new Map(); this._rawSets = /* @__PURE__ */ new Map(); this._targets = /* @__PURE__ */ new Set(); if (target) { this._targets.add(target); } } static unFinal(obj) { return DomRenderFinalProxy.unFinal(obj); } static final(obj) { return DomRenderFinalProxy.final(obj); } static isFinal(obj) { return ValidUtils.isNull(obj) || DomRenderFinalProxy.isFinal(obj); } static isProxy(obj) { return ValidUtils.isNull(obj) || isWrapProxyDomRenderProxy(obj); } static getOriginalObject(obj) { if (isWrapProxyDomRenderProxy(obj)) { return obj._domRender_origin; } return obj; } async run(objProxy) { this._domRender_proxy = objProxy; if (isOnProxyDomRender(objProxy)) { objProxy.onProxyDomRender(this._domRender_config); } const obj = getDomRenderOriginObject(objProxy); if (obj) { Object.keys(obj).forEach((it) => { try { const isNoProxy = Reflect.getMetadata(DomRenderNoProxyKey, obj, it) || Reflect.getMetadata(DomRenderNoProxyKey, Object.getPrototypeOf(obj).constructor); if (isNoProxy) { return obj; } } catch (e) { } const target = obj[it]; if (target !== void 0 && target !== null && typeof target === "object" && !DomRenderProxy.isFinal(target) && !Object.isFrozen(target) && !(obj instanceof Shield)) { const isExcluded = this._domRender_config.proxyExcludeTyps?.some((it2) => target instanceof it2) ?? false; if (!isExcluded) { const proxyAfter = this.proxy(objProxy, target, it); obj[it] = proxyAfter; } } }); } for (let target of this._targets) { await this.initRender(target); } } async initRender(target, rawSet) { if (target instanceof Element) { target.innerHTML = target.innerHTML.replace(/@this@/g, "this"); } const onCreate = target.getAttribute?.(RawSet.DR_ON_CREATE_ARGUMENTS_OPTIONNAME); let createParam = []; if (onCreate) { createParam = ObjectUtils.Script.evaluateReturn(onCreate, this._domRender_proxy); if (!Array.isArray(createParam)) { createParam = [createParam]; } } if (isOnCreateRenderData(this._domRender_proxy)) { this._domRender_proxy?.onCreateRenderData({ rootParent: this._domRender_proxy }); } if (isOnCreateRender(this._domRender_proxy)) { this._domRender_proxy.onCreateRender(...createParam); } this._targets.add(target); const rawSets = RawSet.checkPointCreates(target, this._domRender_proxy, this._domRender_config); this._domRender_config.eventManager.applyEvent( this._domRender_proxy, this._domRender_config.eventManager.findAttrElements(target, this._domRender_config), this._domRender_config ); rawSets.forEach((it) => { const variables = it.getUsingTriggerVariables(this._domRender_config); if (variables.size <= 0) { this.addRawSet("", it); } else { variables.forEach((sit) => { this.addRawSet(sit, it); }); } }); const targetRawSets = await this.render(this.getRawSets()); for (let targetRawSet of targetRawSets) { let initParam; if (onCreate) { initParam = ObjectUtils.Script.evaluateReturn(onCreate, this._domRender_proxy); } if (isOnInitRender(this._domRender_proxy)) { await this._domRender_proxy.onInitRender( initParam, rawSet ?? { dataSet: { config: this._domRender_config } } ); } } } getRawSets() { const set = /* @__PURE__ */ new Set(); this._rawSets.forEach((v, k) => { v.forEach((it) => set.add(it)); }); return Array.from(set); } // 중요 important async render(raws, fullPathStr) { if (typeof raws === "string") { const iter = this._rawSets.get(raws); if (iter) { raws = Array.from(iter); } else { raws = void 0; } } const removeRawSets = []; const rawSets = raws ?? this.getRawSets(); const CHUNK_SIZE = 50; const chunks = []; let rawSetsArray = Array.from(rawSets); for (const rawSet of rawSetsArray) { await this.renderExecute(rawSet, fullPathStr, removeRawSets); } if (isOnChildRawSetRendered(this._domRender_proxy)) { await this._domRender_proxy.onChildRawSetRendered(); } if (removeRawSets.length > 0) { this.removeRawSet(...removeRawSets); } return this.getRawSets(); } async renderExecute(it, fullPathStr, removeRawSets) { it.getUsingTriggerVariables(this._domRender_config).forEach((path) => { this.addRawSet(path, it); }); let renderResult; if (it.isConnected) { const targetAttrMap = it.point.node?.getAttribute?.(EventManager.normalAttrMapAttrName); if (it.detect?.action) { it.detect.action(); } else if (it.type === RawSetType.TARGET_ELEMENT && it.dataSet?.render?.currentThis && fullPathStr && targetAttrMap) { const attrStart = performance.now(); new Map(JSON.parse(targetAttrMap)).forEach((v, k) => { var _a; const isUsing = v.variablePaths.some((it2) => EventManager.isUsingThisVar(it2.inner, `this.${fullPathStr}`)); if (isUsing) { const targetAttrObject = RawSet.getAttributeObject(it.point.node, { script: it.dataSet?.render?.renderScript ?? "", obj: Object.assign(this._domRender_proxy ?? {}, { __render: it.dataSet?.render }) }); (_a = it.dataSet).render ?? (_a.render = {}); it.dataSet.render.attribute = targetAttrObject; if (isOnChangeAttrRender(it.dataSet?.render?.currentThis)) { it.dataSet?.render?.currentThis?.onChangeAttrRender?.(k, targetAttrObject[k], { rawSet: it }); } } }); const attrEnd = performance.now(); } else { const renderStart = performance.now(); const rawSets = await it.render(this._domRender_proxy, this._domRender_config); const renderEnd = performance.now(); renderResult = rawSets; if (rawSets && rawSets.raws.length > 0) { await this.render(rawSets.raws); } } } else { removeRawSets.push(it); } const t = it.findNearThis(this._domRender_proxy); if (isOnRawSetRendered(t)) { await t.onRawSetRendered(it, { path: fullPathStr, value: ObjectUtils.Script.evaluateReturn(`this.${fullPathStr}`, this._domRender_proxy), root: this._domRender_proxy, renderResult }); } } // domrender_ref로 찾는걸로 바꿈 // public findRootDomRenderProxy(): DomRenderProxy<any> { // let current:DomRenderProxy<any> = this; // while (current.parentProxy) { // current = current.parentProxy; // } // return current; // } root(pathInfos, value, lastDoneExecute = true) { const rootStartTime = Date.now(); const pathKey = pathInfos.flat().map((i) => i.path).join("."); const fullPaths = []; if (this._domRender_ref.size > 0) { this._domRender_ref.forEach((it, key) => { if (DomRenderProxyMetaKey._DomRender_isProxy in key) { it.forEach((sit) => { try { const recursiveStartTime = Date.now(); const concat = pathInfos.concat([[{ path: sit, obj: key }]]); const items = key._DomRender_proxy?.root( concat, value, lastDoneExecute ); fullPaths.push(items.flat()); } catch (e) { } }); } }); } else { const pathProcessStartTime = Date.now(); const shortPaths = pathInfos.reverse().map((it) => it.map((it2) => it2.path).join(",")); const fullPathStr = shortPaths.map((it) => isNaN(Number(it)) ? "." + it : `[${it}]`).join("").slice(1); if (lastDoneExecute) { const iterable = this._rawSets.get(fullPathStr); const front = shortPaths.slice(0, shortPaths.length - 1).map((it) => isNaN(Number(it)) ? "." + it : `[${it}]`).join(""); const lastPropertyName = shortPaths[shortPaths.length - 1]; const path = "this" + front; const data = ObjectUtils.Script.evaluateReturn(ObjectUtils.Path.toOptionalChainPath(path), this._domRender_proxy); const promiseStartTime = Date.now(); new Promise(async (resolve) => { const promiseInnerStartTime = Date.now(); let rData = []; const firstPathStr = front.slice(1); const dictionaryCheckStartTime = Date.now(); const firstTargets = this._rawSets.get(firstPathStr); const firstTargetDictionary = []; firstTargets?.forEach((it) => { const type = it.point.start?.getAttribute?.("type"); if (type === RawSetOperatorType.DR_THIS_PROPERTY) { firstTargetDictionary.push(it); } }); if (firstTargetDictionary.length > 0) { const rawSets = []; let skip = false; firstTargetDictionary.forEach((it) => { const startElement = it.point.start; const keys = startElement.getAttribute(RawSet.DR_HAS_KEYS_OPTIONNAME)?.split(",") ?? []; if (value === void 0) { const rawSet = it.getHasRawSet(lastPropertyName); rawSet?.remove(); startElement.setAttribute( RawSet.DR_HAS_KEYS_OPTIONNAME, keys.filter((it2) => it2 !== lastPropertyName).join(",") ); } if (!keys.includes(lastPropertyName)) { const raws = DrThisProperty.append( this._domRender_proxy, fullPathStr, lastPropertyName, it, this._domRender_config ); if (raws) { rawSets.push(...raws); } } else { skip = true; } }); if (skip === false || rawSets.length > 0) { rData = await this.render(rawSets); } } const renderStartTime = Date.now(); if (lastPropertyName === "length" && Array.isArray(data)) { const aIterable = this._rawSets.get(firstPathStr); if (aIterable) { rData = await this.render(Array.from(aIterable)); } } else if (iterable) { rData = await this.render(Array.from(iterable), fullPathStr); } const eventProcessStartTime = Date.now(); const Node = this._domRender_config.window.Node; this._targets.forEach((it) => { if (it.nodeType === Node.DOCUMENT_FRAGMENT_NODE || it.nodeType === Node.ELEMENT_NODE) { const findAttrStartTime = Date.now(); const targets = this._domRender_config.eventManager.findAttrElements( it, this._domRender_config ); const targetCount = targets?.size || targets?.length || 0; const changeVarStartTime = Date.now(); this._domRender_config.eventManager.changeVar( this._domRender_proxy, targets, `this.${fullPathStr}`, this._domRender_config ); } }); if (rData?.length > 0 && isOnChildRenderedByProperty(data)) { const propertyValue = ObjectUtils.Script.evaluateReturn(`this.${lastPropertyName}`, data); data.onChildRenderedByProperty(lastPropertyName, propertyValue); } resolve(rData); }).then((it) => { }); } fullPaths.push([{ path: fullPathStr, obj: this._domRender_proxy }]); } return fullPaths; } set(target, p, value, receiver) { if (typeof p === "string" && p !== DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY && excludeGetSetPropertys.includes(p) || Reflect.getMetadata(DomRenderNoProxyKey, target, p)) { target[p] = value; return true; } let start = performance.now(); if (typeof p === "string") { value = this.proxy(receiver, value, p); } if (value instanceof ComponentSet && target[p] instanceof ComponentSet) { value.config.beforeComponentSet = target[p]; } target[p] = value; let fullPathInfo = []; if (typeof p === "string") { fullPathInfo = this.root([[{ path: p, obj: this._domRender_proxy }]], value); } const rootElement = this._domRender_config.rootElement ?? this._domRender_config.window.document; DocumentUtils.querySelectorAllByAttributeName(rootElement, EventManager.normalAttrMapAttrName)?.forEach( (elementInfo) => { const targets = new Map( ObjectUtils.Script.evaluateReturn(elementInfo.value) ); Array.from(targets.entries()).filter(ValidUtils.isDefined).flatMap(([key, valueScript]) => { return fullPathInfo.flat().filter((it) => valueScript.variablePaths?.some((vit) => vit.inner.includes(`this.${it.path}`))).flatMap((it) => ({ key, valueScript, pathInfo: it })); }).forEach((it) => { const variablePaths = it.valueScript.variablePaths; let targetScript = it.valueScript.originalAttrValue; let script; if (it.valueScript.isStringTemplate) { variablePaths.forEach((it2) => { let r = ObjectUtils.Path.toOptionalChainPath(it2.inner); targetScript = targetScript.replaceAll(it2.origin, `\${${r}}`); }); script = "`" + targetScript + "`"; } else { variablePaths.forEach((it2) => { let r = ObjectUtils.Path.toOptionalChainPath(it2.inner); targetScript = targetScript.replaceAll(it2.origin, `${r}`); }); script = targetScript; } const value1 = ObjectUtils.Script.evaluateReturn(script, it.pathInfo.obj); if (value1 === null || value1 === void 0) { elementInfo.element.removeAttribute(it.key); } else { elementInfo.element.setAttribute(it.key, value1); elementInfo.element[it.key] = value1; } }); } ); DocumentUtils.querySelectorAllByAttributeName(rootElement, EventManager.linkTargetMapAttrName)?.forEach( (elementInfo) => { const targets = new Map(ObjectUtils.Script.evaluateReturn(elementInfo.value)); Array.from(targets.entries()).filter(([key, value2]) => value2.trim()).filter(ValidUtils.isDefined).flatMap(([key, valueScript]) => { return fullPathInfo.flat().filter((it) => valueScript.includes(`this.${it.path}`)).flatMap((it) => ({ key, valueScript, pathInfo: it })); }).forEach((info) => { const value1 = ObjectUtils.Script.evaluateReturn(info.valueScript, info.pathInfo.obj); const applyAttributeName = EventManager.linkAttrs.find((it) => it.name === info.key); if (applyAttributeName) { if (value1 === null) { elementInfo.element.removeAttribute(applyAttributeName.property); } else { elementInfo.element.setAttribute(applyAttributeName.property, value1); } } }); Array.from(targets.entries()).filter(([key, value2]) => value2.trim()).filter(ValidUtils.isDefined).flatMap(([key, valueScript]) => { return fullPathInfo.flat().filter((it) => valueScript.includes(`this.${it.path}`)).flatMap((it) => ({ key, valueScript, pathInfo: it })); }).forEach((info) => { const linkInfo = EventManager.linkAttrs.find((it) => it.name === info.key); if (linkInfo) { elementInfo.element[linkInfo.property] = value; } }); } ); if (DomRenderProxyMetaKey.onBeforeReturnSet in receiver && typeof p === "string" && !(this._domRender_config.proxyExcludeOnBeforeReturnSets ?? []).concat(excludeGetSetPropertys).includes(p)) { if (isOnBeforeReturnSet(receiver)) { receiver.onBeforeReturnSet?.( p, value, fullPathInfo.map((it) => it.map((it2) => it2.path).join()) ); } } return true; } get(target, p, receiver) { if (p === DomRenderProxyMetaKey._DomRender_origin || p === DomRenderProxyMetaKey._domRender_origin) { return this._domRender_origin; } else if (p === DomRenderProxyMetaKey._DomRender_ref || p === DomRenderProxyMetaKey._domRender_ref) { return this._domRender_ref; } else if (p === DomRenderProxyMetaKey._DomRender_config || p === DomRenderProxyMetaKey._domRender_config) { return this._domRender_config; } else if (p === DomRenderProxyMetaKey._DomRender_proxy || p === DomRenderProxyMetaKey._domRender_proxy) { return this; } else { let it = target[p]; if (it && typeof it === "object" && DomRenderProxyMetaKey._DomRender_isProxy in it && Object.prototype.toString.call(it._DomRender_origin) === "[object Date]") { it = it._DomRender_origin; } if (DomRenderProxyMetaKey.onBeforeReturnGet in receiver && typeof p === "string" && !(this._domRender_config.proxyExcludeOnBeforeReturnGets ?? []).concat(excludeGetSetPropertys).includes(p)) { receiver?.onBeforeReturnGet?.( p, it, this.root([[{ path: p, obj: this._domRender_proxy }]], it, false) ); } return it; } } deleteProperty(target, p) { delete target[p]; if (typeof p === "string") { this.root([[{ path: p, obj: this._domRender_proxy }]]); } return true; } has(target, p) { return p === DomRenderProxyMetaKey._DomRender_isProxy || p in target; } proxy(parentProxy, obj, p) { try { const isObject = typeof obj === "object"; const isNoProxy = isObject && isDomRenderNoProxy(obj, p); const isExclude = this._domRender_config.proxyExcludeTyps?.some((it) => obj instanceof it) ?? false; const isFinal = isObject && DomRenderProxy.isFinal(obj); const isFrozen = Object.isFrozen(obj); const isShield = obj instanceof Shield; if (obj === void 0 || obj === null || isNoProxy || isExclude || ValidUtils.isNullOrUndefined(obj) || !isObject || isFinal || isFrozen || isShield) { return obj; } } catch (e) { } if (!isWrapProxyDomRenderProxy(obj)) { const domRender = new DomRenderProxy(obj, void 0, this._domRender_config); domRender.addRef(parentProxy, p); const proxy = new Proxy(obj, domRender); domRender.run(proxy); return proxy; } if (isWrapProxyDomRenderProxy(obj)) { const d = obj._DomRender_proxy; d.addRef(this._domRender_proxy, p); return obj; } else { return obj; } } addRef(parent, path) { if (!this._domRender_ref.get(parent)) { this._domRender_ref.set(parent, /* @__PURE__ */ new Set()); } this._domRender_ref.get(parent)?.add(path); } addRawSetAndRender(path, rawSet) { this.addRawSet(path, rawSet); this.render([rawSet]); } addRawSet(path, rawSet) { if (!this._rawSets.get(path)) { this._rawSets.set(path, /* @__PURE__ */ new Set()); } this._rawSets.get(path)?.add(rawSet); } // public removeRawSet(...raws: RawSet[]) { // this._rawSets.forEach(it => { // raws.forEach(sit => it.delete(sit)); // }) // this.garbageRawSet(); // } removeRawSet(...raws) { this._rawSets.forEach((it) => { it.forEach((sit) => { if (!sit.isConnected) { it.delete(sit); } else if (raws.includes(sit)) { it.delete(sit); } }); }); this.targetGarbageRawSet(); } // 특정 경로로 시작하는 모든 child RawSet들을 제거 // 예: path가 'users'이면 'users[0]', 'users[0].imgUrl', 'users.length' 등 모두 제거 removeChildRawSetsByPath(parentPath) { const pathsToRemove = []; this._rawSets.forEach((rawSetSet, path) => { if (path === parentPath || path.startsWith(parentPath + "[") || path.startsWith(parentPath + ".")) { pathsToRemove.push(path); } }); if (pathsToRemove.length > 0) { pathsToRemove.forEach((path) => { const rawSetSet = this._rawSets.get(path); if (rawSetSet) { rawSetSet.forEach((rawSet) => { rawSet.remove?.(); }); this._rawSets.delete(path); } }); } } targetGarbageRawSet() { this._targets.forEach((it) => { if (!it.isConnected) { this._targets.delete(it); } }); } garbageRawSet() { this._targets.forEach((it) => { if (!it.isConnected) { this._targets.delete(it); } }); this._rawSets.forEach((it) => { it.forEach((sit) => { if (!sit.isConnected) { it.delete(sit); } }); }); } } export { DomRenderProxy, getDomRenderConfig, getDomRenderOriginObject, getDomRenderProxy, isWrapProxyDomRenderProxy }; //# sourceMappingURL=DomRenderProxy.js.map