@dooboostore/simple-web-component 1.0.30 → 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/README.md +220 -1
- 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 +29 -12
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/elements/SwcAppEngine.js +3 -3
- package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +1 -8
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +71 -78
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +66 -81
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +52 -96
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +60 -103
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/SwcSubTemplates.js +0 -27
- package/dist/cjs/elements/SwcSubTemplates.js.map +2 -2
- package/dist/cjs/elements/register.js +314 -343
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/router/ElementRouter.js +1 -8
- package/dist/cjs/router/ElementRouter.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/Utils.js +31 -24
- 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 +27 -10
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/elements/SwcAppEngine.js +3 -3
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +1 -8
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +72 -60
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +67 -63
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +53 -78
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +61 -85
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/SwcSubTemplates.js +0 -8
- package/dist/esm/elements/SwcSubTemplates.js.map +2 -2
- package/dist/esm/elements/register.js +246 -275
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/router/ElementRouter.js +1 -8
- package/dist/esm/router/ElementRouter.js.map +2 -2
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/Utils.js +31 -24
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2223 -2009
- 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/SwcAppMixin.d.ts.map +1 -1
- package/dist/types/elements/SwcAsync.d.ts +1 -11
- package/dist/types/elements/SwcAsync.d.ts.map +1 -1
- package/dist/types/elements/SwcChoose.d.ts +1 -13
- package/dist/types/elements/SwcChoose.d.ts.map +1 -1
- package/dist/types/elements/SwcIf.d.ts +1 -13
- package/dist/types/elements/SwcIf.d.ts.map +1 -1
- package/dist/types/elements/SwcLoop.d.ts +1 -13
- package/dist/types/elements/SwcLoop.d.ts.map +1 -1
- package/dist/types/elements/SwcSubTemplates.d.ts +6 -6
- package/dist/types/elements/SwcSubTemplates.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/router/ElementRouter.d.ts.map +1 -1
- package/dist/types/types.d.ts +11 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts +10 -0
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2223 -2009
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +3 -3
- package/src/decorators/applyStyle.ts +1 -1
- package/src/decorators/attribute.ts +35 -30
- package/src/decorators/elementDefine.ts +32 -10
- package/src/elements/SwcAppEngine.ts +3 -3
- package/src/elements/SwcAppMixin.ts +6 -27
- package/src/elements/SwcAsync.ts +75 -57
- package/src/elements/SwcChoose.ts +69 -77
- package/src/elements/SwcIf.ts +50 -75
- package/src/elements/SwcLoop.ts +56 -82
- package/src/elements/SwcSubTemplates.ts +6 -6
- package/src/elements/register.ts +234 -285
- package/src/router/ElementRouter.ts +1 -12
- package/src/types.ts +9 -2
- package/src/utils/Utils.ts +48 -37
|
@@ -1,70 +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';
|
|
5
|
+
import { SwcChooseInterface } from '../types';
|
|
6
|
+
import { attributeHost } from '../decorators';
|
|
7
|
+
|
|
8
|
+
class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
9
|
+
@attributeHost('value')
|
|
10
|
+
_value: any;
|
|
11
|
+
|
|
12
|
+
@attributeHost('replace-wrap')
|
|
13
|
+
_replaceWrap: string | null;
|
|
4
14
|
|
|
5
|
-
export class SwcChoose extends HTMLTemplateElement {
|
|
6
15
|
private _nodes: Node[] = [];
|
|
7
|
-
private _value: any = null;
|
|
8
16
|
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
9
17
|
|
|
10
18
|
get value(): any {
|
|
11
19
|
return this._value;
|
|
12
20
|
}
|
|
21
|
+
|
|
13
22
|
set value(nv: any) {
|
|
14
|
-
this.
|
|
15
|
-
this.render();
|
|
23
|
+
this.refresh(nv);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
26
|
+
@changedAttributeHost('value')
|
|
27
|
+
private setValue() {
|
|
28
|
+
this.refresh();
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
@changedAttributeHost('
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.value = null;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
+
@changedAttributeHost('replace-wrap')
|
|
32
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
33
|
+
this.refresh();
|
|
34
|
+
}
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
}
|
|
41
54
|
}
|
|
55
|
+
return ae.getUnprocessedTemplate();
|
|
42
56
|
}
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
refresh(value = this._value) {
|
|
59
|
+
const portal = this.parentElement;
|
|
60
|
+
if (!portal) return;
|
|
61
|
+
|
|
45
62
|
const win = this.ownerDocument?.defaultView || window;
|
|
46
63
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
64
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
65
|
+
|
|
47
66
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
48
67
|
let selected: HTMLTemplateElement | null = null;
|
|
49
68
|
|
|
50
69
|
for (const t of templates) {
|
|
51
70
|
if (t.getAttribute('is') === 'swc-when') {
|
|
71
|
+
const attrVal = t.getAttribute('value') || '';
|
|
52
72
|
let matches = false;
|
|
53
|
-
const value = t.getAttribute('value') || '';
|
|
54
73
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
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);
|
|
58
80
|
const result = FunctionUtils.executeReturn({
|
|
59
|
-
script,
|
|
81
|
+
script: decodedScript,
|
|
60
82
|
context: t,
|
|
61
|
-
args:
|
|
83
|
+
args: groupArgs
|
|
62
84
|
});
|
|
63
|
-
|
|
64
|
-
matches = result === true;
|
|
85
|
+
matches = !!result;
|
|
65
86
|
} else {
|
|
66
|
-
|
|
67
|
-
matches = String(value) === String(this._value);
|
|
87
|
+
matches = String(attrVal) === String(value);
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
if (matches) {
|
|
@@ -76,11 +96,12 @@ export class SwcChoose extends HTMLTemplateElement {
|
|
|
76
96
|
|
|
77
97
|
const target = selected || (this.content.querySelector('template[is="swc-otherwise"]') as HTMLTemplateElement);
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
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) {
|
|
84
105
|
return;
|
|
85
106
|
}
|
|
86
107
|
|
|
@@ -88,41 +109,15 @@ export class SwcChoose extends HTMLTemplateElement {
|
|
|
88
109
|
this._previousTemplate = target;
|
|
89
110
|
|
|
90
111
|
if (target) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
94
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
95
|
-
|
|
96
|
-
// 복제된 최상위 요소들은 SwcChoose의 직접 자식이 될 것이므로 __swc_host 설정 안 함
|
|
97
|
-
this._nodes.forEach((n, nodeIdx) => {
|
|
98
|
-
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
99
|
-
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: n, $nodeIndex: nodeIdx, $isElement: n.nodeType === 1 });
|
|
100
|
-
|
|
101
|
-
// Attribute {{ }} 치환 - HTML string 차원에서 동적 치환
|
|
102
|
-
if (n instanceof HTMLElement) {
|
|
103
|
-
Array.from(n.attributes).forEach(attr => {
|
|
104
|
-
const value = attr.value || '';
|
|
105
|
-
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
106
|
-
const script = value.slice(2, -2).trim();
|
|
107
|
-
const result = FunctionUtils.executeReturn({
|
|
108
|
-
script,
|
|
109
|
-
context: n,
|
|
110
|
-
args: { ...groupArgs, $value: this._value }
|
|
111
|
-
});
|
|
112
|
-
n.setAttribute(attr.name, String(result));
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
});
|
|
112
|
+
let htmlString = target.innerHTML;
|
|
113
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
117
114
|
|
|
118
|
-
this.
|
|
115
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
116
|
+
result.innerHTML = htmlString;
|
|
117
|
+
const processedFragment = result.content;
|
|
119
118
|
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
// portal.insertBefore(clone, this.nextSibling);
|
|
123
|
-
// } else {
|
|
124
|
-
// portal.appendChild(clone);
|
|
125
|
-
// }
|
|
119
|
+
this._nodes = Array.from(processedFragment.childNodes);
|
|
120
|
+
portal.insertBefore(processedFragment, this.nextSibling);
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
123
|
|
|
@@ -131,9 +126,6 @@ export class SwcChoose extends HTMLTemplateElement {
|
|
|
131
126
|
this._nodes = [];
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
connectedCallback() {
|
|
135
|
-
this.refresh();
|
|
136
|
-
}
|
|
137
129
|
disconnectedCallback() {
|
|
138
130
|
this.cleanup();
|
|
139
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
|
-
export 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';
|
|
21
30
|
const win = this.ownerDocument?.defaultView || window;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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();
|
|
31
46
|
}
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
48
|
+
@changedAttributeHost('value')
|
|
49
|
+
private setValue(valueAttr?: string | null) {
|
|
50
|
+
this.refresh();
|
|
37
51
|
}
|
|
38
52
|
|
|
39
|
-
@changedAttributeHost('
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
if (!script) {
|
|
43
|
-
this.value = false;
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
47
|
-
const res = FunctionUtils.executeReturn({
|
|
48
|
-
script,
|
|
49
|
-
context: this,
|
|
50
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
if (res instanceof Promise) {
|
|
54
|
-
res.then(v => (this.value = v)).catch(() => (this.value = false));
|
|
55
|
-
} else {
|
|
56
|
-
this.value = res;
|
|
57
|
-
}
|
|
53
|
+
@changedAttributeHost('replace-wrap')
|
|
54
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
55
|
+
this.refresh();
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
refresh(value = this._value) {
|
|
61
59
|
this.cleanup();
|
|
62
|
-
const portal = this.
|
|
63
|
-
if (!portal) return;
|
|
60
|
+
const portal = this.parentElement;
|
|
61
|
+
if (!portal || !value) return;
|
|
64
62
|
|
|
65
63
|
const win = this.ownerDocument?.defaultView || window;
|
|
66
64
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
67
65
|
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
targetTpl = this;
|
|
71
|
-
} else {
|
|
72
|
-
targetTpl = this.content.querySelector('template[is="swc-default"]') as HTMLTemplateElement;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (targetTpl) {
|
|
76
|
-
const clone = targetTpl.content.cloneNode(true) as DocumentFragment;
|
|
77
|
-
// If it's the host template, remove sub-templates from clone
|
|
78
|
-
if (targetTpl === this) {
|
|
79
|
-
clone.querySelectorAll('template[is^="swc-"]').forEach(t => t.remove());
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this._nodes = Array.from(clone.childNodes);
|
|
83
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
84
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
66
|
+
let htmlString = this.innerHTML;
|
|
67
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
85
68
|
|
|
86
|
-
|
|
87
|
-
if (node instanceof HTMLElement) (node as any).__swc_host = this;
|
|
88
|
-
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
89
|
-
});
|
|
69
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
90
70
|
|
|
91
|
-
|
|
71
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
72
|
+
result.innerHTML = htmlString;
|
|
73
|
+
const processedFragment = result.content;
|
|
92
74
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
} else {
|
|
96
|
-
portal.appendChild(clone);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
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 @@ export 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
|
}
|
package/src/elements/SwcLoop.ts
CHANGED
|
@@ -1,118 +1,92 @@
|
|
|
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';
|
|
6
|
+
|
|
7
|
+
class SwcLoop extends HTMLTemplateElement {
|
|
8
|
+
@attributeHost('value')
|
|
9
|
+
_value: any[];
|
|
10
|
+
|
|
11
|
+
@attributeHost('replace-wrap')
|
|
12
|
+
_replaceWrap: string | null;
|
|
4
13
|
|
|
5
|
-
export class SwcLoop extends HTMLTemplateElement {
|
|
6
|
-
private _value: any[] = [];
|
|
7
14
|
private _nodeGroups: Node[][] = [];
|
|
8
15
|
|
|
9
16
|
get value(): any[] {
|
|
10
17
|
return this._value;
|
|
11
18
|
}
|
|
12
19
|
set value(nv: any[]) {
|
|
13
|
-
this._value = Array.isArray(nv) ? [...nv] : [];
|
|
14
|
-
this.
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
private _resolvePortal(): Element | null {
|
|
18
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
19
|
-
if (!portalScript) return this.parentElement;
|
|
20
|
-
|
|
21
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
22
|
-
const res = FunctionUtils.executeReturn({
|
|
23
|
-
script: portalScript,
|
|
24
|
-
context: this,
|
|
25
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (res instanceof HTMLElement) return res;
|
|
29
|
-
if (typeof res === 'string') return win.document.querySelector(res);
|
|
30
|
-
return this.parentElement;
|
|
20
|
+
// this._value = Array.isArray(nv) ? [...nv] : [];
|
|
21
|
+
this.refresh(nv);
|
|
31
22
|
}
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
24
|
+
@changedAttributeHost('value')
|
|
25
|
+
private setValue() {
|
|
26
|
+
this.refresh();
|
|
37
27
|
}
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
29
|
+
@changedAttributeHost('replace-wrap')
|
|
30
|
+
private setReplaceWrap() {
|
|
31
|
+
this.refresh();
|
|
42
32
|
}
|
|
43
33
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
this.value = [];
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
34
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
35
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
36
|
+
const ae = new ActionExpression(html, config);
|
|
37
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
51
38
|
const win = this.ownerDocument?.defaultView || window;
|
|
52
|
-
const res = FunctionUtils.executeReturn({
|
|
53
|
-
script,
|
|
54
|
-
context: this,
|
|
55
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
56
|
-
});
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
42
|
+
try {
|
|
43
|
+
const value = FunctionUtils.executeReturn({
|
|
44
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
45
|
+
context,
|
|
46
|
+
args: groupArgs
|
|
47
|
+
});
|
|
48
|
+
ae.replace(expr, String(value));
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
51
|
+
}
|
|
62
52
|
}
|
|
53
|
+
return ae.getUnprocessedTemplate();
|
|
63
54
|
}
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
this.
|
|
67
|
-
|
|
56
|
+
refresh(value = this._value) {
|
|
57
|
+
this.cleanup();
|
|
58
|
+
if (value?.length<=0) return;
|
|
59
|
+
const portal = this.parentElement;
|
|
68
60
|
if (!portal) return;
|
|
69
61
|
|
|
70
62
|
const win = this.ownerDocument?.defaultView || window;
|
|
71
63
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
72
64
|
const fragment = win.document.createDocumentFragment();
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const clone = defaultTpl.content.cloneNode(true);
|
|
78
|
-
const nodes = Array.from(clone.childNodes);
|
|
79
|
-
this._nodeGroups.push(nodes);
|
|
80
|
-
fragment.appendChild(clone);
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
this._value.forEach((item, index) => {
|
|
84
|
-
const clone = this.content.cloneNode(true) as DocumentFragment;
|
|
85
|
-
// Filter out sub-templates
|
|
86
|
-
const subTemplates = clone.querySelectorAll('template[is^="swc-"]');
|
|
87
|
-
subTemplates.forEach(t => t.remove());
|
|
88
|
-
|
|
89
|
-
const nodes = Array.from(clone.childNodes);
|
|
90
|
-
const elements = nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
66
|
+
value.forEach((item, index) => {
|
|
67
|
+
let htmlString = this.innerHTML;
|
|
68
|
+
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value };
|
|
91
69
|
|
|
92
|
-
|
|
70
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
93
71
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
97
|
-
});
|
|
72
|
+
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
73
|
+
temp.innerHTML = htmlString;
|
|
98
74
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
75
|
+
const content = temp.content;
|
|
76
|
+
const nodes = Array.from(content.childNodes);
|
|
77
|
+
this._nodeGroups.push(nodes);
|
|
78
|
+
fragment.appendChild(content);
|
|
79
|
+
});
|
|
104
80
|
|
|
105
|
-
|
|
106
|
-
portal.insertBefore(fragment, this.nextSibling);
|
|
107
|
-
} else {
|
|
108
|
-
portal.appendChild(fragment);
|
|
109
|
-
}
|
|
81
|
+
portal.insertBefore(fragment, this.nextSibling);
|
|
110
82
|
}
|
|
111
83
|
|
|
112
|
-
|
|
113
|
-
this.
|
|
84
|
+
private cleanup() {
|
|
85
|
+
this._nodeGroups.forEach(nodes => nodes.forEach(n => n.parentElement?.removeChild(n)));
|
|
86
|
+
this._nodeGroups = [];
|
|
114
87
|
}
|
|
88
|
+
|
|
115
89
|
disconnectedCallback() {
|
|
116
|
-
this.
|
|
90
|
+
this.cleanup();
|
|
117
91
|
}
|
|
118
92
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
class SwcLoading extends HTMLTemplateElement {}
|
|
2
|
+
class SwcError extends HTMLTemplateElement {}
|
|
3
|
+
class SwcSuccess extends HTMLTemplateElement {}
|
|
4
|
+
class SwcWhen extends HTMLTemplateElement {}
|
|
5
|
+
class SwcOtherwise extends HTMLTemplateElement {}
|
|
6
|
+
class SwcDefault extends HTMLTemplateElement {}
|