@dooboostore/simple-web-component 1.0.31 → 1.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/decorators/applyStyle.js +1 -1
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +17 -1
- package/dist/cjs/decorators/attribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +26 -9
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/elements/SwcAppMixin.js +1 -1
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +69 -57
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +66 -60
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +51 -66
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +58 -78
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/register.js +310 -335
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/Utils.js +7 -13
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +1 -1
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/attribute.js +18 -2
- package/dist/esm/decorators/attribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +24 -7
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/elements/SwcAppMixin.js +1 -1
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +70 -58
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +67 -61
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +52 -67
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +59 -79
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/register.js +239 -264
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/Utils.js +7 -13
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2623 -2422
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/attribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/types.d.ts +8 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2623 -2422
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +1 -1
- package/src/decorators/applyStyle.ts +1 -1
- package/src/decorators/attribute.ts +35 -30
- package/src/decorators/elementDefine.ts +26 -7
- package/src/elements/SwcAppMixin.ts +1 -1
- package/src/elements/SwcAsync.ts +75 -69
- package/src/elements/SwcChoose.ts +67 -80
- package/src/elements/SwcIf.ts +51 -76
- package/src/elements/SwcLoop.ts +56 -87
- package/src/elements/register.ts +235 -307
- package/src/types.ts +6 -1
- package/src/utils/Utils.ts +11 -17
package/package.json
CHANGED
|
@@ -34,7 +34,7 @@ function createStyleDecorator(action: StyleAction) {
|
|
|
34
34
|
if (res !== undefined) {
|
|
35
35
|
const win = (this as any).ownerDocument?.defaultView || window;
|
|
36
36
|
const host = this as unknown as HTMLElement;
|
|
37
|
-
const hostSet =
|
|
37
|
+
const hostSet = SwcUtils.getHelperAndHostSet(win, host);
|
|
38
38
|
const r = options.root || 'auto';
|
|
39
39
|
const targetEls: HTMLElement[] = [];
|
|
40
40
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {ReflectUtils} from '@dooboostore/core';
|
|
1
|
+
import {ReflectUtils, FunctionUtils, ActionExpression} from '@dooboostore/core';
|
|
2
2
|
import {ensureInit, getElementConfig} from './elementDefine';
|
|
3
3
|
import {SwcUtils} from '../utils/Utils';
|
|
4
4
|
import {SpecialSelector, SwcQueryOptions} from '../types';
|
|
5
|
+
import { ConvertUtils } from '@dooboostore/core-web';
|
|
5
6
|
export interface AttributeFieldOptions extends SwcQueryOptions {
|
|
6
7
|
name?: string;
|
|
7
8
|
// connectedInitialize?: boolean;
|
|
@@ -113,38 +114,42 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
|
|
|
113
114
|
|
|
114
115
|
Object.defineProperty(target, propertyKey, {
|
|
115
116
|
get(this: any) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
117
|
+
const attrName = options.name || String(propertyKey);
|
|
118
|
+
const conf = getElementConfig(this);
|
|
119
|
+
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
120
|
+
const targetType = options.type || designType;
|
|
121
|
+
|
|
122
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
123
|
+
const primaryTarget = targets[0];
|
|
124
|
+
|
|
125
|
+
if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function') {
|
|
126
|
+
if ((primaryTarget as any).hasAttribute(attrName)) {
|
|
127
|
+
let domVal = (primaryTarget as any).getAttribute(attrName);
|
|
128
|
+
|
|
129
|
+
// 표현식 체크
|
|
130
|
+
const ae = new ActionExpression(domVal);
|
|
131
|
+
const expr = ae.getFirstExpression('call-return');
|
|
132
|
+
if (expr) {
|
|
133
|
+
try {
|
|
134
|
+
const result = FunctionUtils.executeReturn({
|
|
135
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, currentWin.document),
|
|
136
|
+
context: this,
|
|
137
|
+
args: SwcUtils.getHelperAndHostSet(currentWin, this)
|
|
138
|
+
});
|
|
139
|
+
return convertValue(result, targetType);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
console.error(`[SWC] Failed to execute directive {{= ${expr.script} }}:`, e);
|
|
142
|
+
return convertValue(domVal, targetType);
|
|
143
|
+
}
|
|
137
144
|
}
|
|
138
|
-
|
|
145
|
+
|
|
146
|
+
return convertValue(domVal, targetType);
|
|
139
147
|
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
140
150
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return data;
|
|
144
|
-
// } catch (err) {
|
|
145
|
-
// console.error('Error in getter:', err);
|
|
146
|
-
// throw err;
|
|
147
|
-
// }
|
|
151
|
+
const data = convertValue(this[privateKey], targetType);
|
|
152
|
+
return data;
|
|
148
153
|
},
|
|
149
154
|
set(this: any, nv: any) {
|
|
150
155
|
// this[propertyKey] = nv;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
-
import { FunctionUtils } from '@dooboostore/core';
|
|
1
|
+
import { ReflectUtils, FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
3
2
|
import { getAddEventListenerMetadata } from './addEventListener';
|
|
4
3
|
import { ON_INITIALIZE_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata, getOnConnectedInnerHtmlMetadata } from './lifecycles';
|
|
5
4
|
import { getEmitCustomEventMetadataList } from './emitCustomEvent';
|
|
@@ -12,6 +11,7 @@ import { SwcUtils } from '../utils/Utils';
|
|
|
12
11
|
import { HTML_TAG_ENTRIES, DOM_EVENT_NAMES } from '../config/config';
|
|
13
12
|
import { SituationTypeContainer, SituationTypeContainers } from '@dooboostore/simple-boot/decorators/inject/Inject';
|
|
14
13
|
import { InjectSituationType, HostSet } from '../types';
|
|
14
|
+
import { ConvertUtils } from '@dooboostore/core-web';
|
|
15
15
|
|
|
16
16
|
// --- Core Interfaces & Types ---
|
|
17
17
|
|
|
@@ -214,8 +214,7 @@ const setupPrototype = (proto: any) => {
|
|
|
214
214
|
if (oldHandler) el.removeEventListener(eventName, oldHandler);
|
|
215
215
|
|
|
216
216
|
const handler = async (event: any) => {
|
|
217
|
-
const
|
|
218
|
-
const hostSet = SwcUtils.getHostSet(parent || el);
|
|
217
|
+
const hostSet = SwcUtils.getHostSet(el);
|
|
219
218
|
const conf = getElementConfig(this);
|
|
220
219
|
const currentWin = (this as any)._resolveWindow(conf);
|
|
221
220
|
const helpers = SwcUtils.getHelperSet(currentWin);
|
|
@@ -237,8 +236,7 @@ const setupPrototype = (proto: any) => {
|
|
|
237
236
|
proto.__swc_executeAttributeEvent = async function (el: HTMLElement, attrName: string, script: string, event: Event) {
|
|
238
237
|
ensureInit(this);
|
|
239
238
|
|
|
240
|
-
const
|
|
241
|
-
const hostSet = SwcUtils.getHostSet(parent || el);
|
|
239
|
+
const hostSet = SwcUtils.getHostSet(el);
|
|
242
240
|
const conf = getElementConfig(this);
|
|
243
241
|
const currentWin = (this as any)._resolveWindow(conf);
|
|
244
242
|
const currentHelpers = SwcUtils.getHelperSet(currentWin);
|
|
@@ -565,6 +563,27 @@ export const elementDefine =
|
|
|
565
563
|
|
|
566
564
|
const hSet = SwcUtils.getHostSet(this as any);
|
|
567
565
|
|
|
566
|
+
// Process expression directive before passing to handlers
|
|
567
|
+
let processedVal = newVal;
|
|
568
|
+
if (newVal !== null) {
|
|
569
|
+
const ae = new ActionExpression(newVal);
|
|
570
|
+
const expr = ae.getFirstExpression('call-return');
|
|
571
|
+
if (expr) {
|
|
572
|
+
const win = (this as any)._resolveWindow?.() || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
573
|
+
try {
|
|
574
|
+
const result = FunctionUtils.executeReturn({
|
|
575
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
576
|
+
context: this,
|
|
577
|
+
args: SwcUtils.getHelperAndHostSet(win,this as any)
|
|
578
|
+
});
|
|
579
|
+
processedVal = String(result);
|
|
580
|
+
} catch (e) {
|
|
581
|
+
console.error(`[SWC] Failed to execute directive {{= ${expr.script} }} on attribute ${name}:`, e);
|
|
582
|
+
processedVal = newVal;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
568
587
|
if (name.startsWith('swc-on-') && !swcLifecycleAttributes.includes(name)) {
|
|
569
588
|
if (newVal !== null) {
|
|
570
589
|
const eventName = name.substring(7);
|
|
@@ -579,7 +598,7 @@ export const elementDefine =
|
|
|
579
598
|
|
|
580
599
|
const mKeys = attrChangeMap.get(name);
|
|
581
600
|
if (mKeys && Array.isArray(mKeys)) {
|
|
582
|
-
for (const key of mKeys) (this as any)[key](
|
|
601
|
+
for (const key of mKeys) (this as any)[key](processedVal, old, name, hSet);
|
|
583
602
|
}
|
|
584
603
|
};
|
|
585
604
|
|
|
@@ -185,7 +185,7 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
|
|
|
185
185
|
const userConfig = FunctionUtils.executeReturn({
|
|
186
186
|
script: configStr,
|
|
187
187
|
context: this,
|
|
188
|
-
args: SwcUtils.getHelperAndHostSet(win,
|
|
188
|
+
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
189
189
|
});
|
|
190
190
|
this.connect(userConfig);
|
|
191
191
|
} catch (e) {
|
package/src/elements/SwcAsync.ts
CHANGED
|
@@ -1,58 +1,86 @@
|
|
|
1
1
|
import { changedAttributeHost } from '../decorators/changedAttributeHost';
|
|
2
2
|
import { SwcUtils } from '../utils/Utils';
|
|
3
|
-
import { FunctionUtils } from '@dooboostore/core';
|
|
3
|
+
import { FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
4
|
+
import { ConvertUtils } from '@dooboostore/core-web';
|
|
5
|
+
import { attributeHost } from '../decorators';
|
|
4
6
|
|
|
5
7
|
class SwcAsync extends HTMLTemplateElement {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
@attributeHost('value')
|
|
9
|
+
_value: any;
|
|
10
|
+
|
|
11
|
+
@attributeHost('replace-wrap')
|
|
12
|
+
_replaceWrap: string | null;
|
|
13
|
+
|
|
14
|
+
resultValue?: any;
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!script) return;
|
|
12
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
16
|
+
get value(): boolean {
|
|
17
|
+
return this._value;
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
set value(nv: any) {
|
|
21
|
+
this.executeAsync(nv);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private _nodes: Node[] = [];
|
|
25
|
+
|
|
15
26
|
@changedAttributeHost('value')
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.render('default');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
27
|
+
private setValue(valueAttr?: string | null) {
|
|
28
|
+
this.executeAsync(this._value);
|
|
29
|
+
}
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
27
|
-
const result = FunctionUtils.executeReturn({
|
|
28
|
-
script,
|
|
29
|
-
context: this,
|
|
30
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
this.executeAsync(result);
|
|
34
|
-
} else {
|
|
35
|
-
// 일반 문자열 값 또는 직접 Promise 속성
|
|
36
|
-
this.executeAsync(valueAttr);
|
|
37
|
-
}
|
|
31
|
+
@changedAttributeHost('replace-wrap')
|
|
32
|
+
private setReplaceWrap() {
|
|
33
|
+
this.executeAsync(this._value);
|
|
38
34
|
}
|
|
39
35
|
|
|
40
|
-
private executeAsync(result: any) {
|
|
36
|
+
private executeAsync(result: any = this._value) {
|
|
37
|
+
if (result === undefined || result === null) {
|
|
38
|
+
this.refresh('default');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
41
42
|
if (result instanceof Promise) {
|
|
42
|
-
this.
|
|
43
|
+
this.refresh('loading');
|
|
43
44
|
result
|
|
44
45
|
.then(v => {
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
46
|
+
this.resultValue = v;
|
|
47
|
+
this.refresh('success');
|
|
47
48
|
})
|
|
48
|
-
.catch(e =>
|
|
49
|
+
.catch(e => {
|
|
50
|
+
console.error('[SWC-ASYNC] Promise rejected:', e);
|
|
51
|
+
this.resultValue = e;
|
|
52
|
+
this.refresh('error');
|
|
53
|
+
});
|
|
49
54
|
} else {
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
55
|
+
this.resultValue = result;
|
|
56
|
+
this.refresh('success');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
61
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
62
|
+
const ae = new ActionExpression(html, config);
|
|
63
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
64
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
65
|
+
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
68
|
+
try {
|
|
69
|
+
const value = FunctionUtils.executeReturn({
|
|
70
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
71
|
+
context,
|
|
72
|
+
args: groupArgs
|
|
73
|
+
});
|
|
74
|
+
ae.replace(expr, String(value));
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
77
|
+
}
|
|
52
78
|
}
|
|
79
|
+
return ae.getUnprocessedTemplate();
|
|
53
80
|
}
|
|
54
81
|
|
|
55
|
-
|
|
82
|
+
refresh(state: string = 'default') {
|
|
83
|
+
console.log('rrrrrrrrrrrrrrrrr', state);
|
|
56
84
|
this.cleanup();
|
|
57
85
|
const portal = this.parentElement;
|
|
58
86
|
if (!portal) return;
|
|
@@ -62,36 +90,17 @@ class SwcAsync extends HTMLTemplateElement {
|
|
|
62
90
|
|
|
63
91
|
const t = this.content.querySelector(`template[is="swc-${state}"]`) as HTMLTemplateElement;
|
|
64
92
|
if (t) {
|
|
65
|
-
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (n instanceof HTMLElement) {
|
|
77
|
-
Array.from(n.attributes).forEach(attr => {
|
|
78
|
-
const value = attr.value || '';
|
|
79
|
-
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
80
|
-
const script = value.slice(2, -2).trim();
|
|
81
|
-
const result = FunctionUtils.executeReturn({
|
|
82
|
-
script,
|
|
83
|
-
context: n,
|
|
84
|
-
args: groupArgs
|
|
85
|
-
});
|
|
86
|
-
n.setAttribute(attr.name, String(result));
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
93
|
-
|
|
94
|
-
portal.insertBefore(clone, this.nextSibling);
|
|
93
|
+
let htmlString = t.innerHTML;
|
|
94
|
+
const groupArgs = { ...helperSet, $value: this._value, $state: state };
|
|
95
|
+
|
|
96
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
97
|
+
|
|
98
|
+
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
99
|
+
temp.innerHTML = htmlString;
|
|
100
|
+
const content = temp.content;
|
|
101
|
+
|
|
102
|
+
this._nodes = Array.from(content.childNodes);
|
|
103
|
+
portal.insertBefore(content, this.nextSibling);
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
|
|
@@ -100,9 +109,6 @@ class SwcAsync extends HTMLTemplateElement {
|
|
|
100
109
|
this._nodes = [];
|
|
101
110
|
}
|
|
102
111
|
|
|
103
|
-
connectedCallback() {
|
|
104
|
-
this.refresh();
|
|
105
|
-
}
|
|
106
112
|
disconnectedCallback() {
|
|
107
113
|
this.cleanup();
|
|
108
114
|
}
|
|
@@ -1,75 +1,90 @@
|
|
|
1
1
|
import { changedAttributeHost } from '../decorators/changedAttributeHost';
|
|
2
2
|
import { SwcUtils } from '../utils/Utils';
|
|
3
|
-
import { FunctionUtils } from '@dooboostore/core';
|
|
3
|
+
import { FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
4
|
+
import { ConvertUtils } from '@dooboostore/core-web';
|
|
4
5
|
import { SwcChooseInterface } from '../types';
|
|
6
|
+
import { attributeHost } from '../decorators';
|
|
5
7
|
|
|
6
8
|
class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
9
|
+
@attributeHost('value')
|
|
10
|
+
_value: any;
|
|
11
|
+
|
|
12
|
+
@attributeHost('replace-wrap')
|
|
13
|
+
_replaceWrap: string | null;
|
|
14
|
+
|
|
7
15
|
private _nodes: Node[] = [];
|
|
8
|
-
private _value: any = null;
|
|
9
16
|
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
10
17
|
|
|
11
18
|
get value(): any {
|
|
12
19
|
return this._value;
|
|
13
20
|
}
|
|
21
|
+
|
|
14
22
|
set value(nv: any) {
|
|
15
|
-
this.
|
|
16
|
-
this.render();
|
|
23
|
+
this.refresh(nv);
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
26
|
+
@changedAttributeHost('value')
|
|
27
|
+
private setValue() {
|
|
28
|
+
this.refresh();
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
@changedAttributeHost('
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.value = null;
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
31
|
+
@changedAttributeHost('replace-wrap')
|
|
32
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
33
|
+
this.refresh();
|
|
34
|
+
}
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
37
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
38
|
+
const ae = new ActionExpression(html, config);
|
|
39
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
40
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
41
|
+
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
44
|
+
try {
|
|
45
|
+
const value = FunctionUtils.executeReturn({
|
|
46
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
47
|
+
context,
|
|
48
|
+
args: groupArgs
|
|
49
|
+
});
|
|
50
|
+
ae.replace(expr, String(value));
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
53
|
+
}
|
|
45
54
|
}
|
|
55
|
+
return ae.getUnprocessedTemplate();
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
refresh(value = this._value) {
|
|
59
|
+
const portal = this.parentElement;
|
|
60
|
+
if (!portal) return;
|
|
61
|
+
|
|
50
62
|
const win = this.ownerDocument?.defaultView || window;
|
|
51
63
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
64
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
65
|
+
|
|
52
66
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
53
67
|
let selected: HTMLTemplateElement | null = null;
|
|
54
68
|
|
|
55
69
|
for (const t of templates) {
|
|
56
70
|
if (t.getAttribute('is') === 'swc-when') {
|
|
71
|
+
const attrVal = t.getAttribute('value') || '';
|
|
57
72
|
let matches = false;
|
|
58
|
-
const value = t.getAttribute('value') || '';
|
|
59
73
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
// Use ActionExpression to parse and extract script from value attribute
|
|
75
|
+
const ae = new ActionExpression(attrVal);
|
|
76
|
+
const expr = ae.getFirstExpression('replace');
|
|
77
|
+
|
|
78
|
+
if (expr) {
|
|
79
|
+
const decodedScript = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
63
80
|
const result = FunctionUtils.executeReturn({
|
|
64
|
-
script,
|
|
81
|
+
script: decodedScript,
|
|
65
82
|
context: t,
|
|
66
|
-
args:
|
|
83
|
+
args: groupArgs
|
|
67
84
|
});
|
|
68
|
-
|
|
69
|
-
matches = result === true;
|
|
85
|
+
matches = !!result;
|
|
70
86
|
} else {
|
|
71
|
-
|
|
72
|
-
matches = String(value) === String(this._value);
|
|
87
|
+
matches = String(attrVal) === String(value);
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
if (matches) {
|
|
@@ -81,11 +96,12 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
81
96
|
|
|
82
97
|
const target = selected || (this.content.querySelector('template[is="swc-otherwise"]') as HTMLTemplateElement);
|
|
83
98
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
99
|
+
const skipValue = target?.getAttribute?.('skip-if-same');
|
|
100
|
+
const skipValue2 = this._previousTemplate?.getAttribute?.('skip-if-same');
|
|
101
|
+
const hasSkipIfSame = target?.hasAttribute?.('skip-if-same');
|
|
102
|
+
const isSame = this._previousTemplate === target;
|
|
103
|
+
// console.log('---rrrr---', this._previousTemplate, target, hasSkipIfSame, isSame, skipValue, skipValue2);
|
|
104
|
+
if (hasSkipIfSame && isSame) {
|
|
89
105
|
return;
|
|
90
106
|
}
|
|
91
107
|
|
|
@@ -93,41 +109,15 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
93
109
|
this._previousTemplate = target;
|
|
94
110
|
|
|
95
111
|
if (target) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
99
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
100
|
-
|
|
101
|
-
// 복제된 최상위 요소들은 SwcChoose의 직접 자식이 될 것이므로 __swc_host 설정 안 함
|
|
102
|
-
this._nodes.forEach((n, nodeIdx) => {
|
|
103
|
-
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
104
|
-
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: n, $nodeIndex: nodeIdx, $isElement: n.nodeType === 1 });
|
|
105
|
-
|
|
106
|
-
// Attribute {{ }} 치환 - HTML string 차원에서 동적 치환
|
|
107
|
-
if (n instanceof HTMLElement) {
|
|
108
|
-
Array.from(n.attributes).forEach(attr => {
|
|
109
|
-
const value = attr.value || '';
|
|
110
|
-
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
111
|
-
const script = value.slice(2, -2).trim();
|
|
112
|
-
const result = FunctionUtils.executeReturn({
|
|
113
|
-
script,
|
|
114
|
-
context: n,
|
|
115
|
-
args: { ...groupArgs, $value: this._value }
|
|
116
|
-
});
|
|
117
|
-
n.setAttribute(attr.name, String(result));
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
});
|
|
112
|
+
let htmlString = target.innerHTML;
|
|
113
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
122
114
|
|
|
123
|
-
this.
|
|
115
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
116
|
+
result.innerHTML = htmlString;
|
|
117
|
+
const processedFragment = result.content;
|
|
124
118
|
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
// portal.insertBefore(clone, this.nextSibling);
|
|
128
|
-
// } else {
|
|
129
|
-
// portal.appendChild(clone);
|
|
130
|
-
// }
|
|
119
|
+
this._nodes = Array.from(processedFragment.childNodes);
|
|
120
|
+
portal.insertBefore(processedFragment, this.nextSibling);
|
|
131
121
|
}
|
|
132
122
|
}
|
|
133
123
|
|
|
@@ -136,9 +126,6 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
136
126
|
this._nodes = [];
|
|
137
127
|
}
|
|
138
128
|
|
|
139
|
-
connectedCallback() {
|
|
140
|
-
this.refresh();
|
|
141
|
-
}
|
|
142
129
|
disconnectedCallback() {
|
|
143
130
|
this.cleanup();
|
|
144
131
|
}
|