@dooboostore/dom-render
Version:
html view template engine
648 lines (647 loc) • 25 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ComponentBase_exports = {};
__export(ComponentBase_exports, {
ATTRIBUTE_METADATA_KEY: () => ATTRIBUTE_METADATA_KEY,
ComponentBase: () => ComponentBase,
EVENT_METADATA_KEY: () => EVENT_METADATA_KEY,
QUERY_METADATA_KEY: () => QUERY_METADATA_KEY,
attribute: () => attribute,
event: () => event,
query: () => query
});
module.exports = __toCommonJS(ComponentBase_exports);
var import_core_web = require("@dooboostore/core-web");
var import_RawSet = require("../rawsets/RawSet");
var import_DomRenderNoProxy = require("../decorators/DomRenderNoProxy");
var import_core = require("@dooboostore/core");
var import_core2 = require("@dooboostore/core");
var import_core3 = require("@dooboostore/core");
var import_core4 = require("@dooboostore/core");
var __decorate = function(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = function(k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var _a, _b;
const ATTRIBUTE_METADATA_KEY = Symbol("attribute");
const QUERY_METADATA_KEY = Symbol("query");
const EVENT_METADATA_KEY = Symbol("event");
function attribute(nameOrOptions) {
return (target, propertyKey, descriptor) => {
const attributes = import_core2.ReflectUtils.getMetadata(ATTRIBUTE_METADATA_KEY, target.constructor) || [];
let name;
let converter;
if (typeof nameOrOptions === "string") {
name = nameOrOptions;
} else if (nameOrOptions) {
name = nameOrOptions.name || String(propertyKey);
converter = nameOrOptions.converter;
} else {
name = String(propertyKey);
}
const attributeMetadata = {
propertyKey,
name,
converter,
isMethod: !!descriptor
};
attributes.push(attributeMetadata);
import_core2.ReflectUtils.defineMetadata(ATTRIBUTE_METADATA_KEY, attributes, target.constructor);
};
}
function query(selectorOrOptions) {
return (target, propertyKey, descriptor) => {
const queries = import_core2.ReflectUtils.getMetadata(QUERY_METADATA_KEY, target.constructor) || [];
let selector;
let convert;
let onDestroy;
let refreshTime;
let refreshRawSetRendered;
if (typeof selectorOrOptions === "string") {
selector = selectorOrOptions;
} else {
selector = selectorOrOptions.selector;
convert = selectorOrOptions.convert;
onDestroy = selectorOrOptions.onDestroy;
refreshTime = selectorOrOptions.refreshIntervalTime;
refreshRawSetRendered = selectorOrOptions.refreshRawSetRendered;
}
const queryMetadata = {
selector,
propertyKey,
isMethod: !!descriptor,
convert,
onDestroy,
refreshTime,
refreshRawSetRendered
};
queries.push(queryMetadata);
import_core2.ReflectUtils.defineMetadata(QUERY_METADATA_KEY, queries, target.constructor);
};
}
function event(options) {
return (target, propertyKey, descriptor) => {
const events = import_core2.ReflectUtils.getMetadata(EVENT_METADATA_KEY, target.constructor) || [];
const eventMetadata = {
query: options.query,
eventName: options.name,
methodName: propertyKey,
onDestroy: options.onDestroy,
refreshTime: options.refreshTime,
refreshRawSetRendered: options.refreshRawSetRendered
};
events.push(eventMetadata);
import_core2.ReflectUtils.defineMetadata(EVENT_METADATA_KEY, events, target.constructor);
};
}
class ComponentBase {
constructor(_config) {
this._config = _config;
this._children = [];
this._boundEventListeners = [];
this._queryBindings = [];
this._eventBindings = [];
this._refreshTimers = /* @__PURE__ */ new Map();
this.childrenSetSubject = new import_core3.Subject();
this.onRawSetRenderedOtherDataSubject = new import_core3.Subject();
this.onChildRawSetRenderedOtherDataSubject = new import_core3.Subject();
}
get componentConfig() {
return this._config;
}
get render() {
return this._render;
}
get rawSet() {
return this._rawSet;
}
get domRenderConfig() {
return this.rawSet?.dataSet.config;
}
_queryElements(selector, rawSet) {
const e = this.getElement();
if (e) {
return import_core_web.ElementUtils.querySelectorAll(e, selector);
} else {
let startNode = rawSet.point?.start;
let endNode = rawSet.point?.end;
if (rawSet.point?.start && startNode && !startNode.isConnected && startNode instanceof HTMLElement && startNode.hasAttribute("id")) {
rawSet.point.start = startNode = rawSet.dataSet.config.window.document.querySelector("#" + startNode.id);
}
if (rawSet.point?.end && endNode && !endNode.isConnected && endNode instanceof HTMLElement && endNode.hasAttribute("id")) {
rawSet.point.end = endNode = rawSet.dataSet.config.window.document.querySelector("#" + endNode.id);
}
if (startNode && endNode) {
return import_core_web.ElementUtils.querySelectorAll({ start: startNode, end: endNode }, selector);
}
}
return [];
}
_cleanupEventListeners() {
for (const { element, eventName, listener } of this._boundEventListeners) {
element.removeEventListener(eventName, listener);
}
this._boundEventListeners = [];
}
_cleanupQueryBindings() {
for (const { element, metadata } of this._queryBindings) {
if (metadata.onDestroy) {
metadata.onDestroy(this, element);
}
this._clearRefreshTimer(metadata);
}
this._queryBindings = [];
}
_cleanupEventBindings() {
for (const { element, metadata, listener } of this._eventBindings) {
element.removeEventListener(metadata.eventName, listener);
if (metadata.onDestroy) {
metadata.onDestroy(this, element);
}
this._clearRefreshTimer(metadata);
}
this._eventBindings = [];
}
_applyQueryBinding(queryInfo, elements, newElementsOnly = elements) {
const { propertyKey, isMethod, convert } = queryInfo;
elements.forEach((element) => {
this._queryBindings.push({ element, metadata: queryInfo });
});
const processedElements = convert ? elements.map(convert) : elements;
const processedNewElements = convert ? newElementsOnly.map(convert) : newElementsOnly;
if (isMethod) {
const method = this[propertyKey];
if (typeof method === "function") {
const paramTypes = import_core2.ReflectUtils.getParameterTypes(this, propertyKey);
if (paramTypes && paramTypes.length > 0 && paramTypes[0] === Array) {
method.call(this, processedNewElements, { all: processedElements });
} else {
if (processedNewElements.length > 0) {
method.call(this, processedNewElements[0], { all: processedElements, newAll: processedNewElements });
}
}
}
} else {
const propertyType = import_core2.ReflectUtils.getType(this, propertyKey);
if (propertyType === Array) {
this[propertyKey] = processedElements;
} else {
this[propertyKey] = processedElements[0] || null;
}
}
}
_setupQueryDecorators(rawSet) {
if (!rawSet)
return;
const queries = import_core2.ReflectUtils.getMetadata(QUERY_METADATA_KEY, this.constructor);
if (queries && Array.isArray(queries)) {
for (const queryInfo of queries) {
const elements = this._queryElements(queryInfo.selector, rawSet);
this._applyQueryBinding(queryInfo, elements);
this._setupRefreshTimer(queryInfo);
}
}
}
_updateQueryBinding(queryInfo, rawSet, forceUpdate = false) {
const newElements = this._queryElements(queryInfo.selector, rawSet);
const currentBindings = this._queryBindings.filter((binding) => binding.metadata === queryInfo);
const currentElements = currentBindings.map((binding) => binding.element);
const elementsChanged = forceUpdate || !this._arraysEqual(currentElements, newElements);
if (elementsChanged) {
let addedElements = [];
if (forceUpdate) {
currentBindings.forEach(({ element, metadata }) => {
if (metadata.onDestroy) {
metadata.onDestroy(this, element);
}
});
addedElements = newElements;
} else {
const removedElements = currentElements.filter((element) => !newElements.includes(element));
addedElements = newElements.filter((element) => !currentElements.includes(element));
removedElements.forEach((element) => {
if (queryInfo.onDestroy) {
queryInfo.onDestroy(this, element);
}
});
}
this._queryBindings = this._queryBindings.filter((binding) => binding.metadata !== queryInfo);
this._applyQueryBinding(queryInfo, newElements, addedElements);
}
}
_updateQueryDecorators(rawSet) {
if (!rawSet)
return;
const queries = import_core2.ReflectUtils.getMetadata(QUERY_METADATA_KEY, this.constructor);
if (queries && Array.isArray(queries)) {
for (const queryInfo of queries) {
this._updateQueryBinding(queryInfo, rawSet);
}
}
}
_arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length)
return false;
return arr1.every((element, index) => element === arr2[index]);
}
_setupRefreshTimer(metadata) {
if (!metadata.refreshTime || !this._rawSet)
return;
const timer = setInterval(() => {
if (!this._rawSet)
return;
if ("selector" in metadata) {
this._updateQueryBinding(metadata, this._rawSet);
} else {
this._updateEventBinding(metadata, this._rawSet);
}
}, metadata.refreshTime);
this._refreshTimers.set(metadata, timer);
}
_clearRefreshTimer(metadata) {
const timer = this._refreshTimers.get(metadata);
if (timer) {
clearInterval(timer);
this._refreshTimers.delete(metadata);
}
}
_clearAllRefreshTimers() {
for (const timer of Array.from(this._refreshTimers.values())) {
clearInterval(timer);
}
this._refreshTimers.clear();
}
async onRawSetRendered(rawSet, otherData) {
this.onRawSetRenderedOtherDataSubject.next(otherData);
const queries = import_core2.ReflectUtils.getMetadata(QUERY_METADATA_KEY, this.constructor);
if (queries) {
queries.filter((it) => it.refreshRawSetRendered).forEach((queryInfo) => {
this._updateQueryBinding(queryInfo, rawSet, true);
});
}
const events = import_core2.ReflectUtils.getMetadata(EVENT_METADATA_KEY, this.constructor);
if (events) {
events.filter((it) => it.refreshRawSetRendered).forEach((eventInfo) => {
this._updateEventBinding(eventInfo, rawSet, true);
});
}
}
async onChildRawSetRendered() {
this.onChildRawSetRenderedOtherDataSubject.next();
}
/**
* Manually refresh all query and event decorators
* Useful when DOM elements are dynamically added/removed and you want to update bindings
*/
refreshDecorators() {
if (this._rawSet) {
this._updateQueryDecorators(this._rawSet);
this._updateEventDecorators(this._rawSet);
}
}
/**
* Manually refresh specific query decorators by property key
* @param propertyKeys - Array of property keys to refresh, or single property key
*/
refreshQueryDecorators(propertyKeys) {
if (!this._rawSet)
return;
const keys = Array.isArray(propertyKeys) ? propertyKeys : [propertyKeys];
const queries = import_core2.ReflectUtils.getMetadata(QUERY_METADATA_KEY, this.constructor);
if (queries && Array.isArray(queries)) {
for (const queryInfo of queries) {
if (keys.includes(queryInfo.propertyKey)) {
this._updateQueryBinding(queryInfo, this._rawSet, true);
}
}
}
}
/**
* Manually refresh specific event decorators by method name
* @param methodNames - Array of method names to refresh, or single method name
*/
refreshEventDecorators(methodNames) {
if (!this._rawSet)
return;
const names = Array.isArray(methodNames) ? methodNames : [methodNames];
const events = import_core2.ReflectUtils.getMetadata(EVENT_METADATA_KEY, this.constructor);
if (events && Array.isArray(events)) {
for (const eventInfo of events) {
if (names.includes(eventInfo.methodName)) {
this._updateEventBinding(eventInfo, this._rawSet, true);
}
}
}
}
_applyEventBinding(eventInfo, elements) {
elements.forEach((element) => {
const listener = this[eventInfo.methodName].bind(this);
element.addEventListener(eventInfo.eventName, listener);
this._eventBindings.push({ element, metadata: eventInfo, listener });
this._boundEventListeners.push({ element, eventName: eventInfo.eventName, listener });
});
}
_setupEventDecorators(rawSet) {
if (!rawSet)
return;
const events = import_core2.ReflectUtils.getMetadata(EVENT_METADATA_KEY, this.constructor);
if (events && Array.isArray(events)) {
for (const eventInfo of events) {
const elements = this._queryElements(eventInfo.query, rawSet);
this._applyEventBinding(eventInfo, elements);
this._setupRefreshTimer(eventInfo);
}
}
}
_updateEventBinding(eventInfo, rawSet, forceUpdate = false) {
const newElements = this._queryElements(eventInfo.query, rawSet);
const currentBindings = this._eventBindings.filter((binding) => binding.metadata === eventInfo);
const currentElements = currentBindings.map((binding) => binding.element);
const elementsChanged = forceUpdate || !this._arraysEqual(currentElements, newElements);
if (elementsChanged) {
if (forceUpdate) {
currentBindings.forEach(({ element, metadata, listener }) => {
element.removeEventListener(metadata.eventName, listener);
if (metadata.onDestroy) {
metadata.onDestroy(this, element);
}
});
} else {
const removedElements = currentElements.filter((element) => !newElements.includes(element));
const removedBindings = currentBindings.filter((binding) => removedElements.includes(binding.element));
removedBindings.forEach(({ element, metadata, listener }) => {
element.removeEventListener(metadata.eventName, listener);
if (metadata.onDestroy) {
metadata.onDestroy(this, element);
}
});
}
this._eventBindings = this._eventBindings.filter((binding) => binding.metadata !== eventInfo);
this._boundEventListeners = this._boundEventListeners.filter((binding) => !currentBindings.some((cb) => cb.element === binding.element && cb.metadata.eventName === binding.eventName));
this._applyEventBinding(eventInfo, newElements);
}
}
_updateEventDecorators(rawSet) {
if (!rawSet)
return;
const events = import_core2.ReflectUtils.getMetadata(EVENT_METADATA_KEY, this.constructor);
if (events && Array.isArray(events)) {
for (const eventInfo of events) {
this._updateEventBinding(eventInfo, rawSet);
}
}
}
getAttributeNames(attribute2 = this._attribute) {
const target = attribute2;
if (!target)
return [];
const keys = Object.keys(target);
const names = /* @__PURE__ */ new Set();
for (const k of keys) {
names.add(k);
}
return Array.from(names);
}
getAttribute(name, attribute2 = this._attribute) {
const target = attribute2;
if (!target) {
return null;
}
const nameString = String(name);
let p = nameString;
if (p in target) {
return target[p];
}
p = import_core.ConvertUtils.snakeToCamelCase(nameString);
if (p in target) {
return target[p];
}
p = import_core.ConvertUtils.camelToSnakeCase(nameString);
if (p in target) {
return target[p];
}
p = nameString.toUpperCase();
if (p in target) {
return target[p];
}
p = nameString.toLowerCase();
if (p in target) {
return target[p];
}
return null;
}
hasAttribute(name) {
return this.getAttribute(name) !== null;
}
equalsAttributeName(n, name) {
return n === name || import_core.ConvertUtils.snakeToCamelCase(n) === name || import_core.ConvertUtils.camelToSnakeCase(n) === name || n.toUpperCase() === name.toUpperCase() || n.toLowerCase() === name.toLowerCase();
}
get uuid() {
return this._rawSet?.uuid;
}
get childrenSet() {
return this._children;
}
get children() {
return this._children.map((it) => it.instance);
}
getElement() {
return (this.render ?? this.rawSet?.dataSet?.render)?.getElement?.();
}
getFirstChild(type) {
return this._children.find((it) => it.instance instanceof type)?.instance;
}
getParentThis() {
return this.render?.parentThis;
}
getChildren(typeOrTypes) {
const targets = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
return this._children.filter((childSet) => targets.some((targetConstructor) => childSet.instance instanceof targetConstructor))?.map((it) => it.instance);
}
setRawSet(rawSet) {
this._rawSet = rawSet;
if (this._rawSet) {
this.setAttribute(this._rawSet.dataSet?.render?.attribute);
}
}
setAttribute(attribute2) {
this._attribute = attribute2;
}
// TODO: rawSet isConnected로 체크해서 들어가있는것만 처리되도록 또는 이미들어가있는것도 뺴야될것같은데.. 적용하긴했음..지켜봐야될듯.
onCreatedThisChild(child, data) {
const n = [...this._children];
n.push({ instance: child, data });
this._children = n.filter((it) => it.data.render?.rawSet?.isConnected);
this.childrenSetSubject.next(this._children);
if (this._rawSet) {
this._updateQueryDecorators(this._rawSet);
this._updateEventDecorators(this._rawSet);
}
}
onCreatedThisChildDebounce(childrenSet) {
}
onRawSetRenderedDebounce(childrenSet) {
}
onChildRawSetRenderedDebounce() {
}
onCreateRenderData(data) {
this._render = data.render;
if (data.render?.rawSet) {
this.setRawSet(data.render.rawSet);
}
if (this._config?.onlyParentType) {
const isOk = Array.isArray(this._config?.onlyParentType) ? this._config?.onlyParentType : [this._config?.onlyParentType].some((it) => data.render?.parentThis instanceof it);
if (!isOk) {
throw new Error("only my parentThis " + this._config?.onlyParentType);
}
}
}
onChangeAttrRender(name, value, other) {
if (other?.rawSet) {
this.setRawSet(other.rawSet);
}
const attributes = import_core2.ReflectUtils.getMetadata(ATTRIBUTE_METADATA_KEY, this.constructor);
if (attributes && Array.isArray(attributes)) {
for (const attrInfo of attributes) {
if (this.equalsAttributeName(name, attrInfo.name)) {
const finalValue = attrInfo.converter ? attrInfo.converter(value) : value;
if (attrInfo.isMethod) {
const method = this[attrInfo.propertyKey];
if (typeof method === "function") {
method.call(this, finalValue);
}
} else {
this[attrInfo.propertyKey] = finalValue;
}
}
}
}
}
async onInitRender(param, rawSet) {
const window = rawSet.dataSet?.config?.window;
this.createChildrenDebounceSubscription = this.childrenSetSubject.pipe(import_core4.MessageOperator.debounceTime(this.componentConfig?.createChildrenDebounce ?? 1, {
setTimeout: window ? window.setTimeout.bind(window) : void 0,
clearTimeout: window ? window.clearTimeout.bind(window) : void 0
})).subscribe((it) => {
this.onCreatedThisChildDebounce(it);
});
this.onRawSetRenderedOtherDataSubjectSubscription = this.onRawSetRenderedOtherDataSubject.pipe(import_core4.MessageOperator.bufferTime(this.componentConfig?.onRawSetRenderedOtherDataDebounce ?? 1, {
skipEmpty: true,
setInterval: window ? window.setInterval.bind(window) : void 0,
clearInterval: window ? window.clearInterval.bind(window) : void 0,
setTimeout: window ? window.setTimeout.bind(window) : void 0,
clearTimeout: window ? window.clearTimeout.bind(window) : void 0
})).subscribe((it) => {
this.onRawSetRenderedDebounce(it);
});
this.onChildRawSetRenderedOtherDataSubjectSubscription = this.onChildRawSetRenderedOtherDataSubject.pipe(import_core4.MessageOperator.debounceTime(this.componentConfig?.onChildRawSetRenderedOtherDataDebounce ?? 10, {
setTimeout: window ? window.setTimeout.bind(window) : void 0,
clearTimeout: window ? window.clearTimeout.bind(window) : void 0
})).subscribe((it) => {
this.onChildRawSetRenderedDebounce();
});
if (rawSet) {
this.setRawSet(rawSet);
const e = this.getElement();
if (e) {
e.component = this;
}
this._setupQueryDecorators(rawSet);
this._setupEventDecorators(rawSet);
}
}
onDrThisBind() {
}
onDrThisUnBind() {
this.onDestroy();
}
onDestroyRender(data) {
this.onDestroy();
}
onDestroy() {
this._cleanupEventListeners();
this._cleanupQueryBindings();
this._cleanupEventBindings();
this._clearAllRefreshTimers();
this.createChildrenDebounceSubscription?.unsubscribe();
this.onRawSetRenderedOtherDataSubjectSubscription?.unsubscribe();
this.onChildRawSetRenderedOtherDataSubjectSubscription?.unsubscribe();
}
}
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", typeof (_a = typeof import_RawSet.RawSet !== "undefined" && import_RawSet.RawSet) === "function" ? _a : Object)
], ComponentBase.prototype, "_rawSet", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Array)
], ComponentBase.prototype, "_children", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "_render", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "_attribute", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Array)
], ComponentBase.prototype, "_boundEventListeners", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Array)
], ComponentBase.prototype, "_queryBindings", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Array)
], ComponentBase.prototype, "_eventBindings", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", typeof (_b = typeof Map !== "undefined" && Map) === "function" ? _b : Object)
], ComponentBase.prototype, "_refreshTimers", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "childrenSetSubject", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "createChildrenDebounceSubscription", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "onRawSetRenderedOtherDataSubject", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "onChildRawSetRenderedOtherDataSubject", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "onRawSetRenderedOtherDataSubjectSubscription", void 0);
__decorate([
import_DomRenderNoProxy.DomRenderNoProxy,
__metadata("design:type", Object)
], ComponentBase.prototype, "onChildRawSetRenderedOtherDataSubjectSubscription", void 0);
//# sourceMappingURL=ComponentBase.js.map