@dooboostore/simple-web-component 1.0.33 → 1.0.35
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 +23 -30
- package/dist/cjs/decorators/addEventListener.js.map +1 -1
- package/dist/cjs/decorators/applyAttribute.js +67 -57
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +80 -70
- package/dist/cjs/decorators/applyClass.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +5 -8
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +66 -56
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +35 -29
- package/dist/cjs/decorators/attribute.js.map +2 -2
- package/dist/cjs/decorators/changedAttributeHost.js +32 -12
- package/dist/cjs/decorators/changedAttributeHost.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +238 -180
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/emitCustomEvent.js +67 -48
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +15 -17
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/setProperty.js +50 -39
- package/dist/cjs/decorators/setProperty.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +1 -1
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/elements/SwcAppEngine.js +14 -8
- package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
- package/dist/cjs/elements/SwcAppMixin.js +154 -81
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +28 -18
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +68 -45
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +52 -30
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +109 -35
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/register.js +263 -131
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/router/ElementRouter.js +4 -2
- package/dist/cjs/router/ElementRouter.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/Utils.js +25 -7
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js.map +1 -1
- package/dist/esm/decorators/applyAttribute.js +67 -57
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +80 -70
- package/dist/esm/decorators/applyClass.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +5 -8
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +66 -56
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/attribute.js +35 -29
- package/dist/esm/decorators/attribute.js.map +2 -2
- package/dist/esm/decorators/changedAttributeHost.js +32 -12
- package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +240 -182
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +67 -48
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +15 -17
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/setProperty.js +50 -39
- package/dist/esm/decorators/setProperty.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +1 -1
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/elements/SwcAppEngine.js +14 -7
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +156 -82
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +28 -18
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +69 -46
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +53 -31
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +110 -36
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/register.js +264 -132
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/router/ElementRouter.js +5 -2
- package/dist/esm/router/ElementRouter.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/Utils.js +25 -7
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +728 -595
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +4 -1
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +5 -1
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +4 -0
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +5 -1
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +5 -1
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/attribute.d.ts +5 -0
- package/dist/types/decorators/attribute.d.ts.map +1 -1
- package/dist/types/decorators/changedAttributeHost.d.ts +14 -3
- package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +15 -7
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +10 -7
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/setProperty.d.ts +5 -1
- package/dist/types/decorators/setProperty.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +2 -2
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +5 -6
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
- package/dist/types/elements/SwcAppEngine.d.ts +9 -3
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +12 -7
- 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 +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts +4 -1
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +728 -595
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +5 -5
- package/src/decorators/addEventListener.ts +1 -1
- package/src/decorators/applyAttribute.ts +74 -61
- package/src/decorators/applyClass.ts +91 -77
- package/src/decorators/applyNode.ts +16 -13
- package/src/decorators/applyStyle.ts +75 -61
- package/src/decorators/attribute.ts +55 -43
- package/src/decorators/changedAttributeHost.ts +49 -15
- package/src/decorators/elementDefine.ts +401 -340
- package/src/decorators/emitCustomEvent.ts +92 -62
- package/src/decorators/lifecycles.ts +11 -10
- package/src/decorators/setProperty.ts +58 -44
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +2 -2
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +11 -11
- package/src/elements/SwcAppEngine.ts +19 -13
- package/src/elements/SwcAppMixin.ts +214 -102
- package/src/elements/SwcAsync.ts +28 -17
- package/src/elements/SwcChoose.ts +94 -36
- package/src/elements/SwcIf.ts +59 -22
- package/src/elements/SwcLoop.ts +140 -27
- package/src/elements/register.ts +319 -100
- package/src/types.ts +1 -0
- package/src/utils/Utils.ts +38 -10
- package/tsconfig.json +2 -2
|
@@ -3,14 +3,15 @@ import { SwcUtils } from '../utils/Utils';
|
|
|
3
3
|
import { FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
4
4
|
import { ConvertUtils } from '@dooboostore/core-web';
|
|
5
5
|
import { SwcChooseInterface } from '../types';
|
|
6
|
-
import { attributeHost } from '../decorators';
|
|
6
|
+
import { attributeHost, getAttributeValue, getElementConfig } from '../decorators';
|
|
7
7
|
|
|
8
8
|
class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
9
|
-
@attributeHost('value')
|
|
10
9
|
_value: any;
|
|
11
10
|
|
|
12
|
-
@attributeHost('replace-wrap')
|
|
13
|
-
|
|
11
|
+
@attributeHost('replace-wrap-start')
|
|
12
|
+
_replaceWrapStart: string | null;
|
|
13
|
+
@attributeHost('replace-wrap-end')
|
|
14
|
+
_replaceWrapEnd: string | null;
|
|
14
15
|
|
|
15
16
|
private _nodes: Node[] = [];
|
|
16
17
|
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
@@ -20,27 +21,52 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
set value(nv: any) {
|
|
23
|
-
this.
|
|
24
|
+
this._value = nv;
|
|
25
|
+
this.refresh(this._value);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
// console.log('swc chooooooooooooooooooooooooose constructor called!');
|
|
31
|
+
// console.log('swc cccccccss', this.getAttribute('value'));
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
// static get observedAttributes() {
|
|
35
|
+
// return ['value'];
|
|
36
|
+
// }
|
|
37
|
+
|
|
38
|
+
attributeChangedCallback(na, o, n) {
|
|
39
|
+
// console.log('-----------------choooooooose attr origin', na, o, n);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@changedAttributeHost('value')
|
|
43
|
+
private setValue(value: any, o: string, n: string) {
|
|
44
|
+
console.log('chooooooose value', value)
|
|
45
|
+
this._value = value;
|
|
46
|
+
this.refresh(this._value);
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
// @changedAttributeHost('replace-wrap')
|
|
50
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
51
|
+
// this.refresh();
|
|
52
|
+
// }
|
|
53
|
+
|
|
54
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
55
|
+
let config: any = undefined;
|
|
56
|
+
if (wrap) {
|
|
57
|
+
config = {
|
|
58
|
+
expression: {
|
|
59
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
60
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
61
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
38
65
|
const ae = new ActionExpression(html, config);
|
|
39
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
40
66
|
const win = this.ownerDocument?.defaultView || window;
|
|
41
67
|
|
|
42
68
|
// @ts-ignore
|
|
43
|
-
for (const expr of ae.getExpressions(
|
|
69
|
+
for (const expr of ae.getExpressions('replace')) {
|
|
44
70
|
try {
|
|
45
71
|
const value = FunctionUtils.executeReturn({
|
|
46
72
|
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
@@ -55,37 +81,50 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
55
81
|
return ae.getUnprocessedTemplate();
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
refresh(value
|
|
59
|
-
|
|
60
|
-
|
|
84
|
+
refresh(value?: any) {
|
|
85
|
+
value = getAttributeValue(this, 'value') ?? this._value;
|
|
86
|
+
console.log('[DEBUG] SwcChoose.refresh called, value:', value);
|
|
87
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
88
|
+
if (!portal) {
|
|
89
|
+
console.log('[DEBUG] SwcChoose portal is null!');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
61
92
|
|
|
62
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
93
|
+
const win = (getElementConfig(this).window ?? this.ownerDocument?.defaultView) || window;
|
|
63
94
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
64
|
-
const groupArgs = { ...helperSet, $value: value };
|
|
95
|
+
const groupArgs = { ...helperSet, $value: value, $templateHost: this };
|
|
65
96
|
|
|
66
97
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
67
98
|
let selected: HTMLTemplateElement | null = null;
|
|
68
99
|
|
|
69
100
|
for (const t of templates) {
|
|
70
101
|
if (t.getAttribute('is') === 'swc-when') {
|
|
71
|
-
const attrVal = t.getAttribute('
|
|
102
|
+
const attrVal = t.getAttribute('test') || '';
|
|
72
103
|
let matches = false;
|
|
73
104
|
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
const result = FunctionUtils.executeReturn({
|
|
108
|
+
script: attrVal,
|
|
109
|
+
context: t,
|
|
110
|
+
args: groupArgs
|
|
111
|
+
});
|
|
112
|
+
matches = !!result;
|
|
74
113
|
// 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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} else {
|
|
87
|
-
|
|
88
|
-
}
|
|
114
|
+
// const ae = new ActionExpression(attrVal);
|
|
115
|
+
// const expr = ae.getFirstExpression('replace');
|
|
116
|
+
|
|
117
|
+
// if (expr) {
|
|
118
|
+
// const decodedScript = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
119
|
+
// const result = FunctionUtils.executeReturn({
|
|
120
|
+
// script: decodedScript,
|
|
121
|
+
// context: t,
|
|
122
|
+
// args: groupArgs
|
|
123
|
+
// });
|
|
124
|
+
// matches = !!result;
|
|
125
|
+
// } else {
|
|
126
|
+
// matches = String(attrVal) === String(value);
|
|
127
|
+
// }
|
|
89
128
|
|
|
90
129
|
if (matches) {
|
|
91
130
|
selected = t;
|
|
@@ -110,14 +149,33 @@ class SwcChoose extends HTMLTemplateElement implements SwcChooseInterface {
|
|
|
110
149
|
|
|
111
150
|
if (target) {
|
|
112
151
|
let htmlString = target.innerHTML;
|
|
113
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
152
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
114
153
|
|
|
115
154
|
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
116
155
|
result.innerHTML = htmlString;
|
|
117
156
|
const processedFragment = result.content;
|
|
118
157
|
|
|
158
|
+
// console.log('[DEBUG] SwcChoose processedFragment children:', processedFragment._childNodesInternal?.length);
|
|
119
159
|
this._nodes = Array.from(processedFragment.childNodes);
|
|
160
|
+
|
|
161
|
+
const setTemplateHost = (element: HTMLElement) => {
|
|
162
|
+
(element as any).__swc_template_host = this;
|
|
163
|
+
Array.from(element.children).forEach((child: any) => {
|
|
164
|
+
if (child instanceof HTMLElement) {
|
|
165
|
+
setTemplateHost(child);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
this._nodes.forEach((node: any) => {
|
|
171
|
+
if (node instanceof HTMLElement) {
|
|
172
|
+
setTemplateHost(node as HTMLElement);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
console.log(`[DEBUG] SwcChoose before insertBefore, portal: ${portal?.tagName}, isConnected: ${(portal as any)?.isConnected}`);
|
|
120
177
|
portal.insertBefore(processedFragment, this.nextSibling);
|
|
178
|
+
console.log('[DEBUG] SwcChoose after insertBefore');
|
|
121
179
|
}
|
|
122
180
|
}
|
|
123
181
|
|
package/src/elements/SwcIf.ts
CHANGED
|
@@ -3,14 +3,20 @@ import { SwcUtils } from '../utils/Utils';
|
|
|
3
3
|
import { FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
4
4
|
import { ConvertUtils } from '@dooboostore/core-web';
|
|
5
5
|
import { SwcIfInterface } from '../types';
|
|
6
|
-
import { attributeHost } from '../decorators';
|
|
6
|
+
import { attributeHost, getAttributeValue } from '../decorators';
|
|
7
7
|
|
|
8
8
|
class SwcIf extends HTMLTemplateElement implements SwcIfInterface {
|
|
9
|
-
|
|
9
|
+
// id =
|
|
10
|
+
// @attributeHost('value')
|
|
10
11
|
_value: any;
|
|
11
12
|
|
|
12
|
-
@attributeHost('replace-wrap')
|
|
13
|
-
|
|
13
|
+
@attributeHost('replace-wrap-start')
|
|
14
|
+
_replaceWrapStart: string | null;
|
|
15
|
+
@attributeHost('replace-wrap-end')
|
|
16
|
+
_replaceWrapEnd: string | null;
|
|
17
|
+
|
|
18
|
+
@attributeHost('skip-if-same')
|
|
19
|
+
_skipIfSame: string | null;
|
|
14
20
|
|
|
15
21
|
private _nodes: Node[] = [];
|
|
16
22
|
|
|
@@ -23,14 +29,37 @@ class SwcIf extends HTMLTemplateElement implements SwcIfInterface {
|
|
|
23
29
|
this.refresh(nv);
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@changedAttributeHost('value')
|
|
37
|
+
private setValue(value: any, o: string, n: string) {
|
|
38
|
+
this._value = value;
|
|
39
|
+
this.refresh(this._value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// @changedAttributeHost('replace-wrap')
|
|
43
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
44
|
+
// this.refresh();
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
48
|
+
let config: any = undefined;
|
|
49
|
+
if (wrap) {
|
|
50
|
+
config = {
|
|
51
|
+
expression: {
|
|
52
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
53
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
54
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
28
58
|
const ae = new ActionExpression(html, config);
|
|
29
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
30
59
|
const win = this.ownerDocument?.defaultView || window;
|
|
31
|
-
|
|
60
|
+
|
|
32
61
|
// @ts-ignore
|
|
33
|
-
for (const expr of ae.getExpressions(
|
|
62
|
+
for (const expr of ae.getExpressions('replace')) {
|
|
34
63
|
try {
|
|
35
64
|
const value = FunctionUtils.executeReturn({
|
|
36
65
|
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
@@ -45,39 +74,47 @@ class SwcIf extends HTMLTemplateElement implements SwcIfInterface {
|
|
|
45
74
|
return ae.getUnprocessedTemplate();
|
|
46
75
|
}
|
|
47
76
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.refresh();
|
|
51
|
-
}
|
|
77
|
+
refresh(value?: any) {
|
|
78
|
+
const targetValue = value !== undefined ? value : (getAttributeValue(this, 'value') ?? this._value);
|
|
52
79
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
80
|
+
// skip-if-same 속성이 존재하고(true/빈 문자열), 이전 값과 새로운 값이 완전히 동일하면 렌더링 스킵!
|
|
81
|
+
if (this.hasAttribute('skip-if-same') && this._value === targetValue && this._nodes.length > 0) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
57
84
|
|
|
58
|
-
refresh(value = this._value) {
|
|
59
85
|
this.cleanup();
|
|
86
|
+
this._value = targetValue;
|
|
87
|
+
|
|
60
88
|
const portal = this.parentElement;
|
|
61
|
-
if (!portal || !
|
|
89
|
+
if (!portal || !this._value) return;
|
|
62
90
|
|
|
63
91
|
const win = this.ownerDocument?.defaultView || window;
|
|
64
92
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
65
93
|
|
|
66
94
|
let htmlString = this.innerHTML;
|
|
67
|
-
const groupArgs = { ...helperSet, $value:
|
|
95
|
+
const groupArgs = { ...helperSet, $value: this._value, $templateHost: this };
|
|
68
96
|
|
|
69
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
97
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
70
98
|
|
|
71
99
|
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
72
100
|
result.innerHTML = htmlString;
|
|
73
101
|
const processedFragment = result.content;
|
|
74
102
|
|
|
75
103
|
this._nodes = Array.from(processedFragment.childNodes);
|
|
104
|
+
this._nodes.forEach((node: any) => {
|
|
105
|
+
if (node instanceof HTMLElement) (node as any).__swc_template_host = this;
|
|
106
|
+
});
|
|
107
|
+
|
|
76
108
|
portal.insertBefore(processedFragment, this.nextSibling);
|
|
77
109
|
}
|
|
78
110
|
|
|
79
111
|
private cleanup() {
|
|
80
|
-
this._nodes.forEach(n =>
|
|
112
|
+
this._nodes.forEach(n => {
|
|
113
|
+
const realNode = (n as any).__upgraded_instance || n;
|
|
114
|
+
if (realNode.parentElement) {
|
|
115
|
+
realNode.parentElement.removeChild(realNode);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
81
118
|
this._nodes = [];
|
|
82
119
|
}
|
|
83
120
|
|
package/src/elements/SwcLoop.ts
CHANGED
|
@@ -2,46 +2,67 @@ import { changedAttributeHost } from '../decorators/changedAttributeHost';
|
|
|
2
2
|
import { SwcUtils } from '../utils/Utils';
|
|
3
3
|
import { FunctionUtils, ActionExpression } from '@dooboostore/core';
|
|
4
4
|
import { ConvertUtils } from '@dooboostore/core-web';
|
|
5
|
-
import { attributeHost } from '../decorators';
|
|
5
|
+
import { attributeHost, getAttributeValue } from '../decorators';
|
|
6
6
|
|
|
7
7
|
class SwcLoop extends HTMLTemplateElement {
|
|
8
|
-
|
|
9
|
-
_value: any[];
|
|
8
|
+
_value: any[] = [];
|
|
10
9
|
|
|
11
|
-
@attributeHost('replace-wrap')
|
|
12
|
-
|
|
10
|
+
@attributeHost('replace-wrap-start')
|
|
11
|
+
_replaceWrapStart: string | null;
|
|
12
|
+
@attributeHost('replace-wrap-end')
|
|
13
|
+
_replaceWrapEnd: string | null;
|
|
13
14
|
|
|
14
15
|
private _nodeGroups: Node[][] = [];
|
|
15
16
|
|
|
16
17
|
get value(): any[] {
|
|
17
18
|
return this._value;
|
|
18
19
|
}
|
|
20
|
+
|
|
19
21
|
set value(nv: any[]) {
|
|
20
|
-
|
|
22
|
+
this._value = nv;
|
|
21
23
|
this.refresh(nv);
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
getValue(index: number) {
|
|
27
|
+
return this._value?.[index];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
super();
|
|
32
|
+
// console.log('swc SwcLoop constructor called!');
|
|
33
|
+
// console.log('swc SwcLoop', this.getAttribute('value'));
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
@changedAttributeHost('
|
|
30
|
-
private
|
|
31
|
-
this.
|
|
36
|
+
@changedAttributeHost('value')
|
|
37
|
+
private setValue(value: any, o: string, n: string) {
|
|
38
|
+
this._value = value;
|
|
39
|
+
this.refresh(this._value);
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
// @changedAttributeHost('replace-wrap')
|
|
43
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
44
|
+
// this.refresh();
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
48
|
+
let config: any = undefined;
|
|
49
|
+
config = {
|
|
50
|
+
expression: {
|
|
51
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
52
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
53
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
54
|
+
}
|
|
55
|
+
};
|
|
36
56
|
const ae = new ActionExpression(html, config);
|
|
37
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
38
57
|
const win = this.ownerDocument?.defaultView || window;
|
|
39
58
|
|
|
40
59
|
// @ts-ignore
|
|
41
|
-
|
|
60
|
+
const expressions = ae.getExpressions('replace');
|
|
61
|
+
for (const expr of expressions) {
|
|
62
|
+
const script = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
42
63
|
try {
|
|
43
64
|
const value = FunctionUtils.executeReturn({
|
|
44
|
-
script:
|
|
65
|
+
script: script,
|
|
45
66
|
context,
|
|
46
67
|
args: groupArgs
|
|
47
68
|
});
|
|
@@ -53,35 +74,127 @@ class SwcLoop extends HTMLTemplateElement {
|
|
|
53
74
|
return ae.getUnprocessedTemplate();
|
|
54
75
|
}
|
|
55
76
|
|
|
56
|
-
|
|
57
|
-
this.cleanup();
|
|
58
|
-
if (value?.length<=0) return;
|
|
59
|
-
const portal = this.parentElement;
|
|
60
|
-
if (!portal) return;
|
|
61
|
-
|
|
77
|
+
private createFragmentAndNodes(items: any[], helperSet: any, startIndex: number = 0): { fragment: DocumentFragment; newNodesGroup: Node[][] } {
|
|
62
78
|
const win = this.ownerDocument?.defaultView || window;
|
|
63
|
-
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
64
79
|
const fragment = win.document.createDocumentFragment();
|
|
80
|
+
const newNodesGroup: Node[][] = [];
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
items.forEach((item, i) => {
|
|
83
|
+
const index = startIndex + i;
|
|
67
84
|
let htmlString = this.innerHTML;
|
|
68
85
|
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value };
|
|
69
86
|
|
|
70
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
87
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
71
88
|
|
|
72
89
|
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
73
90
|
temp.innerHTML = htmlString;
|
|
74
91
|
|
|
75
92
|
const content = temp.content;
|
|
76
93
|
const nodes = Array.from(content.childNodes);
|
|
77
|
-
|
|
94
|
+
|
|
95
|
+
const setTemplateHost = (element: HTMLElement) => {
|
|
96
|
+
(element as any).__swc_template_host = this;
|
|
97
|
+
Array.from(element.children).forEach((child: any) => {
|
|
98
|
+
if (child instanceof HTMLElement) {
|
|
99
|
+
setTemplateHost(child);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
nodes.forEach((node: any) => {
|
|
105
|
+
if (node instanceof HTMLElement) {
|
|
106
|
+
setTemplateHost(node as HTMLElement);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
newNodesGroup.push(nodes);
|
|
78
110
|
fragment.appendChild(content);
|
|
79
111
|
});
|
|
80
112
|
|
|
113
|
+
return { fragment, newNodesGroup };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
appendItem(...items: any[]) {
|
|
117
|
+
if (!items || items.length <= 0) return;
|
|
118
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
119
|
+
if (!portal) return;
|
|
120
|
+
|
|
121
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
122
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
123
|
+
|
|
124
|
+
const startIndex = this._value ? this._value.length : 0;
|
|
125
|
+
|
|
126
|
+
// 내부 상태(value) 업데이트 (기존 배열에 새 아이템 추가)
|
|
127
|
+
if (this._value !== items) {
|
|
128
|
+
this._value = [...(this._value || []), ...items];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(items, helperSet, startIndex);
|
|
132
|
+
this._nodeGroups.push(...newNodesGroup);
|
|
133
|
+
|
|
134
|
+
console.log('뭐야 씨발');
|
|
135
|
+
// append 위치 계산: 기존에 그려진 마지막 노드 뒤에 삽입, 없으면 템플릿 바로 뒤에 삽입
|
|
136
|
+
let insertReference: Node | null = this.nextSibling;
|
|
137
|
+
if (this._nodeGroups.length > items.length) {
|
|
138
|
+
const lastExistingGroup = this._nodeGroups[this._nodeGroups.length - items.length - 1];
|
|
139
|
+
if (lastExistingGroup && lastExistingGroup.length > 0) {
|
|
140
|
+
const lastNode = lastExistingGroup[lastExistingGroup.length - 1];
|
|
141
|
+
insertReference = lastNode.nextSibling;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
portal.insertBefore(fragment, insertReference);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async prependItem(...items: any[]) {
|
|
149
|
+
if (!items || items.length <= 0) return;
|
|
150
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
151
|
+
if (!portal) return;
|
|
152
|
+
|
|
153
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
154
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
155
|
+
|
|
156
|
+
// 내부 상태(value) 업데이트 (기존 배열의 앞쪽에 새 아이템 추가)
|
|
157
|
+
if (this._value !== items) {
|
|
158
|
+
this._value = [...items, ...(this._value || [])];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(items, helperSet, 0);
|
|
162
|
+
|
|
163
|
+
// 기존의 nodeGroups 배열 맨 앞에 새로운 그룹들을 추가
|
|
164
|
+
this._nodeGroups = [...newNodesGroup, ...this._nodeGroups];
|
|
165
|
+
|
|
166
|
+
// prepend 위치: 이 템플릿(SwcLoop) 노드의 바로 다음 위치 (가장 위)
|
|
81
167
|
portal.insertBefore(fragment, this.nextSibling);
|
|
82
168
|
}
|
|
83
169
|
|
|
170
|
+
refresh(value?: any) {
|
|
171
|
+
// 1. 그릴 대상 확정
|
|
172
|
+
const targetValue = value !== undefined ? value : (getAttributeValue(this, 'value') ?? this._value ?? []);
|
|
173
|
+
|
|
174
|
+
// 2. 화면 정리
|
|
175
|
+
this.cleanup();
|
|
176
|
+
|
|
177
|
+
// 3. 상태 완전 교체 (이어붙이지 않음!)
|
|
178
|
+
this._value = targetValue;
|
|
179
|
+
|
|
180
|
+
if (!this._value || this._value.length <= 0) return;
|
|
181
|
+
|
|
182
|
+
// 4. 화면 다시 그리기 (appendItem을 쓰지 않고 바로 그리기)
|
|
183
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
184
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
185
|
+
helperSet.$templateHost = this;
|
|
186
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(this._value, helperSet, 0);
|
|
187
|
+
|
|
188
|
+
this._nodeGroups = newNodesGroup;
|
|
189
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
190
|
+
if (portal) {
|
|
191
|
+
// console.log('append????!~~~~~!?',fragment)
|
|
192
|
+
portal.insertBefore(fragment, this.nextSibling);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
84
196
|
private cleanup() {
|
|
197
|
+
console.log('누가 cleanup');
|
|
85
198
|
this._nodeGroups.forEach(nodes => nodes.forEach(n => n.parentElement?.removeChild(n)));
|
|
86
199
|
this._nodeGroups = [];
|
|
87
200
|
}
|