@dooboostore/simple-web-component 1.0.31 → 1.0.33
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/README.md +280 -43
- 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 +27 -10
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/index.js +3 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/publishSwcAppMessage.js +86 -0
- package/dist/cjs/decorators/publishSwcAppMessage.js.map +7 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +62 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
- package/dist/cjs/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +16 -16
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
- package/dist/cjs/elements/SwcAppMixin.js +32 -3
- 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 +25 -8
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/decorators/index.js +3 -1
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/publishSwcAppMessage.js +67 -0
- package/dist/esm/decorators/publishSwcAppMessage.js.map +7 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +43 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
- package/dist/esm/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +13 -13
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
- package/dist/esm/elements/SwcAppMixin.js +32 -3
- 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 +2804 -2498
- 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 +1 -0
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +3 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/publishSwcAppMessage.d.ts +13 -0
- package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -0
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +16 -0
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +18 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -0
- package/dist/types/elements/SwcAppMixin.d.ts +3 -0
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/types.d.ts +14 -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 +2804 -2498
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +4 -4
- package/src/decorators/applyStyle.ts +1 -1
- package/src/decorators/attribute.ts +35 -30
- package/src/decorators/elementDefine.ts +28 -8
- package/src/decorators/index.ts +3 -1
- package/src/decorators/publishSwcAppMessage.ts +100 -0
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +73 -0
- package/src/decorators/{subscribeSwcAppRouteChange.ts → subscribeSwcAppRouteChangeWhileConnected.ts} +19 -19
- package/src/elements/SwcAppMixin.ts +43 -4
- 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 +14 -1
- package/src/utils/Utils.ts +11 -17
- package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +0 -7
- package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +0 -7
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +0 -18
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +0 -1
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
|
}
|
package/src/elements/SwcIf.ts
CHANGED
|
@@ -1,101 +1,79 @@
|
|
|
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 { SwcIfInterface } from '../types';
|
|
6
|
+
import { attributeHost } from '../decorators';
|
|
7
|
+
|
|
8
|
+
class SwcIf extends HTMLTemplateElement implements SwcIfInterface {
|
|
9
|
+
@attributeHost('value')
|
|
10
|
+
_value: any;
|
|
11
|
+
|
|
12
|
+
@attributeHost('replace-wrap')
|
|
13
|
+
_replaceWrap: string | null;
|
|
4
14
|
|
|
5
|
-
class SwcIf extends HTMLTemplateElement {
|
|
6
|
-
private _value = false;
|
|
7
15
|
private _nodes: Node[] = [];
|
|
8
16
|
|
|
9
17
|
get value(): boolean {
|
|
10
18
|
return this._value;
|
|
11
19
|
}
|
|
20
|
+
|
|
12
21
|
set value(nv: any) {
|
|
13
|
-
this._value =
|
|
14
|
-
this.
|
|
22
|
+
// this._value = nv;
|
|
23
|
+
this.refresh(nv);
|
|
15
24
|
}
|
|
16
25
|
|
|
17
|
-
private
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
27
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
28
|
+
const ae = new ActionExpression(html, config);
|
|
29
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
30
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
31
|
+
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
34
|
+
try {
|
|
35
|
+
const value = FunctionUtils.executeReturn({
|
|
36
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
37
|
+
context,
|
|
38
|
+
args: groupArgs
|
|
39
|
+
});
|
|
40
|
+
ae.replace(expr, String(value));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return ae.getUnprocessedTemplate();
|
|
21
46
|
}
|
|
22
47
|
|
|
23
48
|
@changedAttributeHost('value')
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this.value = false;
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
49
|
+
private setValue(valueAttr?: string | null) {
|
|
50
|
+
this.refresh();
|
|
51
|
+
}
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
35
|
-
const result = FunctionUtils.executeReturn({
|
|
36
|
-
script,
|
|
37
|
-
context: this,
|
|
38
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
39
|
-
});
|
|
40
|
-
this.value = result;
|
|
41
|
-
} else {
|
|
42
|
-
// 일반 문자열 값
|
|
43
|
-
this.value = Boolean(valueAttr);
|
|
44
|
-
}
|
|
53
|
+
@changedAttributeHost('replace-wrap')
|
|
54
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
55
|
+
this.refresh();
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
refresh(value = this._value) {
|
|
48
59
|
this.cleanup();
|
|
49
60
|
const portal = this.parentElement;
|
|
50
|
-
if (!portal) return;
|
|
61
|
+
if (!portal || !value) return;
|
|
51
62
|
|
|
52
63
|
const win = this.ownerDocument?.defaultView || window;
|
|
53
64
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
54
65
|
|
|
55
|
-
let
|
|
56
|
-
|
|
57
|
-
targetTpl = this;
|
|
58
|
-
} else {
|
|
59
|
-
targetTpl = this.content.querySelector('template[is="swc-default"]') as HTMLTemplateElement;
|
|
60
|
-
}
|
|
66
|
+
let htmlString = this.innerHTML;
|
|
67
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
61
68
|
|
|
62
|
-
|
|
63
|
-
const clone = targetTpl.content.cloneNode(true) as DocumentFragment;
|
|
64
|
-
// If it's the host template, remove sub-templates from clone
|
|
65
|
-
if (targetTpl === this) {
|
|
66
|
-
clone.querySelectorAll('template[is^="swc-"]').forEach(t => t.remove());
|
|
67
|
-
}
|
|
69
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// if (node instanceof HTMLElement) (node as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
76
|
-
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
77
|
-
|
|
78
|
-
// Attribute {{ }} 치환 - SwcChoose처럼 동적 치환
|
|
79
|
-
if (node instanceof HTMLElement) {
|
|
80
|
-
Array.from(node.attributes).forEach(attr => {
|
|
81
|
-
const value = attr.value || '';
|
|
82
|
-
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
83
|
-
const script = value.slice(2, -2).trim();
|
|
84
|
-
const result = FunctionUtils.executeReturn({
|
|
85
|
-
script,
|
|
86
|
-
context: node,
|
|
87
|
-
args: { ...groupArgs, $value: this._value }
|
|
88
|
-
});
|
|
89
|
-
node.setAttribute(attr.name, String(result));
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
96
|
-
|
|
97
|
-
portal.insertBefore(clone, this.nextSibling);
|
|
98
|
-
}
|
|
71
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
72
|
+
result.innerHTML = htmlString;
|
|
73
|
+
const processedFragment = result.content;
|
|
74
|
+
|
|
75
|
+
this._nodes = Array.from(processedFragment.childNodes);
|
|
76
|
+
portal.insertBefore(processedFragment, this.nextSibling);
|
|
99
77
|
}
|
|
100
78
|
|
|
101
79
|
private cleanup() {
|
|
@@ -103,9 +81,6 @@ class SwcIf extends HTMLTemplateElement {
|
|
|
103
81
|
this._nodes = [];
|
|
104
82
|
}
|
|
105
83
|
|
|
106
|
-
connectedCallback() {
|
|
107
|
-
this.refreshValue();
|
|
108
|
-
}
|
|
109
84
|
disconnectedCallback() {
|
|
110
85
|
this.cleanup();
|
|
111
86
|
}
|