@dooboostore/simple-web-component 1.0.29 → 1.0.31
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 +651 -27
- package/dist/cjs/decorators/elementDefine.js +5 -3
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +1 -0
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/setProperty.js +97 -0
- package/dist/cjs/decorators/setProperty.js.map +7 -0
- 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 +37 -53
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +55 -60
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +31 -60
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +20 -43
- 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 +216 -128
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.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 +26 -10
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +5 -3
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +1 -0
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/setProperty.js +78 -0
- package/dist/esm/decorators/setProperty.js.map +7 -0
- 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 +37 -34
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +55 -41
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +31 -41
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +20 -24
- 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 +216 -128
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.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 +26 -10
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +105 -13
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +1 -0
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/setProperty.d.ts +13 -0
- package/dist/types/decorators/setProperty.d.ts.map +1 -0
- 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 +3 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/router/ElementRouter.d.ts.map +1 -1
- package/dist/types/types.d.ts +3 -0
- 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 +105 -13
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +3 -3
- package/src/decorators/elementDefine.ts +10 -3
- package/src/decorators/emitCustomEvent.ts +1 -0
- package/src/decorators/index.ts +1 -0
- package/src/decorators/setProperty.ts +97 -0
- package/src/elements/SwcAppEngine.ts +3 -3
- package/src/elements/SwcAppMixin.ts +7 -28
- package/src/elements/SwcAsync.ts +46 -30
- package/src/elements/SwcChoose.ts +82 -38
- package/src/elements/SwcIf.ts +38 -38
- package/src/elements/SwcLoop.ts +24 -19
- package/src/elements/SwcSubTemplates.ts +6 -6
- package/src/elements/register.ts +261 -121
- package/src/index.ts +3 -1
- package/src/router/ElementRouter.ts +1 -12
- package/src/types.ts +3 -1
- package/src/utils/Utils.ts +40 -19
package/src/elements/SwcLoop.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { changedAttributeHost } from '../decorators/changedAttributeHost';
|
|
|
2
2
|
import { SwcUtils } from '../utils/Utils';
|
|
3
3
|
import { FunctionUtils } from '@dooboostore/core';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
class SwcLoop extends HTMLTemplateElement {
|
|
6
6
|
private _value: any[] = [];
|
|
7
7
|
private _nodeGroups: Node[][] = [];
|
|
8
8
|
|
|
@@ -14,21 +14,7 @@ export class SwcLoop extends HTMLTemplateElement {
|
|
|
14
14
|
this.render();
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
private _resolvePortal(): Element | null {
|
|
18
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
19
|
-
if (!portalScript) return this.parentElement;
|
|
20
17
|
|
|
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;
|
|
31
|
-
}
|
|
32
18
|
|
|
33
19
|
private _executeCloneCallback(attr: string, args: any) {
|
|
34
20
|
const script = this.getAttribute(attr);
|
|
@@ -41,13 +27,17 @@ export class SwcLoop extends HTMLTemplateElement {
|
|
|
41
27
|
this._nodeGroups = [];
|
|
42
28
|
}
|
|
43
29
|
|
|
44
|
-
@changedAttributeHost('
|
|
30
|
+
@changedAttributeHost('value')
|
|
45
31
|
private refreshValue() {
|
|
46
|
-
|
|
32
|
+
let script = this.getAttribute('value');
|
|
47
33
|
if (!script) {
|
|
48
34
|
this.value = [];
|
|
49
35
|
return;
|
|
50
36
|
}
|
|
37
|
+
// Parse {{ }} braces
|
|
38
|
+
if (script.startsWith('{{') && script.endsWith('}}')) {
|
|
39
|
+
script = script.slice(2, -2).trim();
|
|
40
|
+
}
|
|
51
41
|
const win = this.ownerDocument?.defaultView || window;
|
|
52
42
|
const res = FunctionUtils.executeReturn({
|
|
53
43
|
script,
|
|
@@ -64,7 +54,7 @@ export class SwcLoop extends HTMLTemplateElement {
|
|
|
64
54
|
|
|
65
55
|
render() {
|
|
66
56
|
this._cleanup();
|
|
67
|
-
const portal = this.
|
|
57
|
+
const portal = this.parentElement;
|
|
68
58
|
if (!portal) return;
|
|
69
59
|
|
|
70
60
|
const win = this.ownerDocument?.defaultView || window;
|
|
@@ -92,8 +82,23 @@ export class SwcLoop extends HTMLTemplateElement {
|
|
|
92
82
|
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value, $nodes: nodes, $elements: elements, $firstElement: elements[0] };
|
|
93
83
|
|
|
94
84
|
nodes.forEach((node, nodeIdx) => {
|
|
95
|
-
if (node instanceof HTMLElement) (node as any).__swc_host = this;
|
|
96
85
|
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
86
|
+
|
|
87
|
+
// Attribute {{ }} 치환 - SwcChoose처럼 동적 치환
|
|
88
|
+
if (node instanceof HTMLElement) {
|
|
89
|
+
Array.from(node.attributes).forEach(attr => {
|
|
90
|
+
const value = attr.value || '';
|
|
91
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
92
|
+
const script = value.slice(2, -2).trim();
|
|
93
|
+
const result = FunctionUtils.executeReturn({
|
|
94
|
+
script,
|
|
95
|
+
context: node,
|
|
96
|
+
args: groupArgs
|
|
97
|
+
});
|
|
98
|
+
node.setAttribute(attr.name, String(result));
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
@@ -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 {}
|
package/src/elements/register.ts
CHANGED
|
@@ -4,7 +4,9 @@ import { SwcUtils } from '../utils/Utils';
|
|
|
4
4
|
import { FunctionUtils } from '@dooboostore/core';
|
|
5
5
|
import { changedAttributeHost } from '../decorators/changedAttributeHost';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
type Constructor<T> = new (...args: any[]) => T;
|
|
8
|
+
|
|
9
|
+
export const registerAllElements = (w: any): Record<string, Constructor<HTMLElement>> => {
|
|
8
10
|
const {
|
|
9
11
|
HTMLElement: _HTMLElement,
|
|
10
12
|
HTMLTemplateElement: _HTMLTemplateElement,
|
|
@@ -157,52 +159,39 @@ export const registerAllElements = (w: any) => {
|
|
|
157
159
|
this.render();
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
private _resolvePortal(): Element | null {
|
|
161
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
162
|
-
if (!portalScript) return this.parentElement;
|
|
163
|
-
|
|
164
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
165
|
-
const res = FunctionUtils.executeReturn({
|
|
166
|
-
script: portalScript,
|
|
167
|
-
context: this,
|
|
168
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
if (res instanceof HTMLElement) return res;
|
|
172
|
-
if (typeof res === 'string') return win.document.querySelector(res);
|
|
173
|
-
return this.parentElement;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
162
|
private _executeCloneCallback(attr: string, args: any) {
|
|
177
163
|
const script = this.getAttribute(attr);
|
|
178
164
|
if (!script) return;
|
|
179
165
|
FunctionUtils.execute({ script, context: this, args });
|
|
180
166
|
}
|
|
181
167
|
|
|
182
|
-
@changedAttributeHost('
|
|
183
|
-
private refreshValue() {
|
|
184
|
-
|
|
185
|
-
if (
|
|
168
|
+
@changedAttributeHost('value')
|
|
169
|
+
private refreshValue(valueAttr?: string | null) {
|
|
170
|
+
valueAttr ??= this.getAttribute('value');
|
|
171
|
+
if (valueAttr === null) {
|
|
186
172
|
this.value = false;
|
|
187
173
|
return;
|
|
188
174
|
}
|
|
189
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
190
|
-
const res = FunctionUtils.executeReturn({
|
|
191
|
-
script,
|
|
192
|
-
context: this,
|
|
193
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
194
|
-
});
|
|
195
175
|
|
|
196
|
-
|
|
197
|
-
|
|
176
|
+
// {{ }} 브레이스로 감싸진 값은 스크립트 실행
|
|
177
|
+
if (valueAttr.startsWith('{{') && valueAttr.endsWith('}}')) {
|
|
178
|
+
const script = valueAttr.slice(2, -2).trim();
|
|
179
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
180
|
+
const result = FunctionUtils.executeReturn({
|
|
181
|
+
script,
|
|
182
|
+
context: this,
|
|
183
|
+
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
184
|
+
});
|
|
185
|
+
this.value = result;
|
|
198
186
|
} else {
|
|
199
|
-
|
|
187
|
+
// 일반 문자열 값
|
|
188
|
+
this.value = Boolean(valueAttr);
|
|
200
189
|
}
|
|
201
190
|
}
|
|
202
191
|
|
|
203
192
|
private render() {
|
|
204
193
|
this.cleanup();
|
|
205
|
-
const portal = this.
|
|
194
|
+
const portal = this.parentElement;
|
|
206
195
|
if (!portal) return;
|
|
207
196
|
|
|
208
197
|
const win = this.ownerDocument?.defaultView || window;
|
|
@@ -226,18 +215,31 @@ export const registerAllElements = (w: any) => {
|
|
|
226
215
|
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
227
216
|
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
228
217
|
|
|
218
|
+
// 부모 체인을 정상적으로 유지하기 위해 __swc_host 할당 제거
|
|
229
219
|
this._nodes.forEach((node, nodeIdx) => {
|
|
230
|
-
if (node instanceof HTMLElement) (node as any).__swc_host = this;
|
|
220
|
+
// if (node instanceof HTMLElement) (node as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
231
221
|
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
222
|
+
|
|
223
|
+
// Attribute {{ }} 치환 - SwcChoose처럼 동적 치환
|
|
224
|
+
if (node instanceof HTMLElement) {
|
|
225
|
+
Array.from(node.attributes).forEach(attr => {
|
|
226
|
+
const value = attr.value || '';
|
|
227
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
228
|
+
const script = value.slice(2, -2).trim();
|
|
229
|
+
const result = FunctionUtils.executeReturn({
|
|
230
|
+
script,
|
|
231
|
+
context: node,
|
|
232
|
+
args: { ...groupArgs, $value: this._value }
|
|
233
|
+
});
|
|
234
|
+
node.setAttribute(attr.name, String(result));
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
232
238
|
});
|
|
233
239
|
|
|
234
240
|
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
235
241
|
|
|
236
|
-
|
|
237
|
-
portal.insertBefore(clone, this.nextSibling);
|
|
238
|
-
} else {
|
|
239
|
-
portal.appendChild(clone);
|
|
240
|
-
}
|
|
242
|
+
portal.insertBefore(clone, this.nextSibling);
|
|
241
243
|
}
|
|
242
244
|
}
|
|
243
245
|
|
|
@@ -267,21 +269,7 @@ export const registerAllElements = (w: any) => {
|
|
|
267
269
|
this.render();
|
|
268
270
|
}
|
|
269
271
|
|
|
270
|
-
private _resolvePortal(): Element | null {
|
|
271
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
272
|
-
if (!portalScript) return this.parentElement;
|
|
273
|
-
|
|
274
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
275
|
-
const res = FunctionUtils.executeReturn({
|
|
276
|
-
script: portalScript,
|
|
277
|
-
context: this,
|
|
278
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
279
|
-
});
|
|
280
272
|
|
|
281
|
-
if (res instanceof HTMLElement) return res;
|
|
282
|
-
if (typeof res === 'string') return win.document.querySelector(res);
|
|
283
|
-
return this.parentElement;
|
|
284
|
-
}
|
|
285
273
|
|
|
286
274
|
private _executeCloneCallback(attr: string, args: any) {
|
|
287
275
|
const script = this.getAttribute(attr);
|
|
@@ -294,13 +282,17 @@ export const registerAllElements = (w: any) => {
|
|
|
294
282
|
this._nodeGroups = [];
|
|
295
283
|
}
|
|
296
284
|
|
|
297
|
-
@changedAttributeHost('
|
|
285
|
+
@changedAttributeHost('value')
|
|
298
286
|
private refreshValue() {
|
|
299
|
-
|
|
287
|
+
let script = this.getAttribute('value');
|
|
300
288
|
if (!script) {
|
|
301
289
|
this.value = [];
|
|
302
290
|
return;
|
|
303
291
|
}
|
|
292
|
+
// Parse {{ }} braces
|
|
293
|
+
if (script.startsWith('{{') && script.endsWith('}}')) {
|
|
294
|
+
script = script.slice(2, -2).trim();
|
|
295
|
+
}
|
|
304
296
|
const win = this.ownerDocument?.defaultView || window;
|
|
305
297
|
const res = FunctionUtils.executeReturn({
|
|
306
298
|
script,
|
|
@@ -317,7 +309,7 @@ export const registerAllElements = (w: any) => {
|
|
|
317
309
|
|
|
318
310
|
render() {
|
|
319
311
|
this._cleanup();
|
|
320
|
-
const portal = this.
|
|
312
|
+
const portal = this.parentElement;
|
|
321
313
|
if (!portal) return;
|
|
322
314
|
|
|
323
315
|
const win = this.ownerDocument?.defaultView || window;
|
|
@@ -345,8 +337,23 @@ export const registerAllElements = (w: any) => {
|
|
|
345
337
|
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value, $nodes: nodes, $elements: elements, $firstElement: elements[0] };
|
|
346
338
|
|
|
347
339
|
nodes.forEach((node, nodeIdx) => {
|
|
348
|
-
if (node instanceof HTMLElement) (node as any).__swc_host = this;
|
|
349
340
|
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: node, $nodeIndex: nodeIdx, $isElement: node.nodeType === 1 });
|
|
341
|
+
|
|
342
|
+
// Attribute {{ }} 치환 - SwcChoose처럼 동적 치환
|
|
343
|
+
if (node instanceof HTMLElement) {
|
|
344
|
+
Array.from(node.attributes).forEach(attr => {
|
|
345
|
+
const value = attr.value || '';
|
|
346
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
347
|
+
const script = value.slice(2, -2).trim();
|
|
348
|
+
const result = FunctionUtils.executeReturn({
|
|
349
|
+
script,
|
|
350
|
+
context: node,
|
|
351
|
+
args: groupArgs
|
|
352
|
+
});
|
|
353
|
+
node.setAttribute(attr.name, String(result));
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
350
357
|
});
|
|
351
358
|
|
|
352
359
|
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
@@ -374,6 +381,7 @@ export const registerAllElements = (w: any) => {
|
|
|
374
381
|
class SwcChoose extends HTMLTemplateElement {
|
|
375
382
|
private _nodes: Node[] = [];
|
|
376
383
|
private _value: any = null;
|
|
384
|
+
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
377
385
|
|
|
378
386
|
get value(): any {
|
|
379
387
|
return this._value;
|
|
@@ -383,76 +391,118 @@ export const registerAllElements = (w: any) => {
|
|
|
383
391
|
this.render();
|
|
384
392
|
}
|
|
385
393
|
|
|
386
|
-
private _resolvePortal(): Element | null {
|
|
387
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
388
|
-
if (!portalScript) return this.parentElement;
|
|
389
|
-
|
|
390
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
391
|
-
const res = FunctionUtils.executeReturn({
|
|
392
|
-
script: portalScript,
|
|
393
|
-
context: this,
|
|
394
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
if (res instanceof HTMLElement) return res;
|
|
398
|
-
if (typeof res === 'string') return win.document.querySelector(res);
|
|
399
|
-
return this.parentElement;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
394
|
private _executeCloneCallback(attr: string, args: any) {
|
|
403
395
|
const script = this.getAttribute(attr);
|
|
404
396
|
if (!script) return;
|
|
405
397
|
FunctionUtils.execute({ script, context: this, args });
|
|
406
398
|
}
|
|
407
399
|
|
|
408
|
-
@changedAttributeHost('
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (
|
|
400
|
+
@changedAttributeHost('value')
|
|
401
|
+
refresh(valueAttr?: string | null) {
|
|
402
|
+
valueAttr ??= this.getAttribute('value');
|
|
403
|
+
if (valueAttr === null) {
|
|
412
404
|
this.value = null;
|
|
413
405
|
return;
|
|
414
406
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
407
|
+
|
|
408
|
+
// {{ }} 브레이스로 감싸진 값은 스크립트 실행
|
|
409
|
+
if (valueAttr.startsWith('{{') && valueAttr.endsWith('}}')) {
|
|
410
|
+
const script = valueAttr.slice(2, -2).trim();
|
|
411
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
412
|
+
const helperAndHostSet = SwcUtils.getHelperAndHostSet(win, SwcUtils.findNearestSwcHost(this));
|
|
413
|
+
// console.log('vvvvvvvvvvvvvvvvvv323', helperAndHostSet);
|
|
414
|
+
const result = FunctionUtils.executeReturn({ script, context: this, args: helperAndHostSet });
|
|
415
|
+
this.value = result;
|
|
416
|
+
// console.log('----------vv', this.value);
|
|
417
|
+
} else {
|
|
418
|
+
// 일반 문자열 값
|
|
419
|
+
this.value = valueAttr;
|
|
420
|
+
}
|
|
418
421
|
}
|
|
419
422
|
|
|
420
423
|
private render() {
|
|
421
|
-
this.
|
|
422
|
-
const portal = this._resolvePortal();
|
|
423
|
-
if (!portal) return;
|
|
424
|
-
|
|
424
|
+
// console.log('-------------', this.value);
|
|
425
425
|
const win = this.ownerDocument?.defaultView || window;
|
|
426
426
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
427
|
-
|
|
428
427
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
429
428
|
let selected: HTMLTemplateElement | null = null;
|
|
429
|
+
|
|
430
430
|
for (const t of templates) {
|
|
431
|
-
if (t.getAttribute('is') === 'swc-when'
|
|
432
|
-
|
|
433
|
-
|
|
431
|
+
if (t.getAttribute('is') === 'swc-when') {
|
|
432
|
+
let matches = false;
|
|
433
|
+
const value = t.getAttribute('value') || '';
|
|
434
|
+
|
|
435
|
+
// {{ }} 브레이스로 감싸진 값은 스크립트 실행
|
|
436
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
437
|
+
const script = value.slice(2, -2).trim();
|
|
438
|
+
const result = FunctionUtils.executeReturn({
|
|
439
|
+
script,
|
|
440
|
+
context: t,
|
|
441
|
+
args: { ...helperSet, $value: this._value }
|
|
442
|
+
});
|
|
443
|
+
// console.log('rrrrrrrrrrrrrr', result);
|
|
444
|
+
matches = result === true;
|
|
445
|
+
} else {
|
|
446
|
+
// 일반 문자열 비교 (기존 방식)
|
|
447
|
+
matches = String(value) === String(this._value);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (matches) {
|
|
451
|
+
selected = t;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
434
454
|
}
|
|
435
455
|
}
|
|
456
|
+
|
|
436
457
|
const target = selected || (this.content.querySelector('template[is="swc-otherwise"]') as HTMLTemplateElement);
|
|
437
458
|
|
|
459
|
+
// skip-if-same attribute가 있고 이전과 같은 template이면 렌더링 스킵
|
|
460
|
+
// 최상위 skip-if-same 또는 각 when/otherwise의 skip-if-same 체크
|
|
461
|
+
const targetHasSkipIfSame = target?.hasAttribute('skip-if-same');
|
|
462
|
+
const shouldSkip = (this.hasAttribute('skip-if-same') || targetHasSkipIfSame) && this._previousTemplate === target;
|
|
463
|
+
if (shouldSkip) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
this.cleanup();
|
|
468
|
+
this._previousTemplate = target;
|
|
469
|
+
|
|
438
470
|
if (target) {
|
|
439
471
|
const clone = target.content.cloneNode(true) as DocumentFragment;
|
|
440
472
|
this._nodes = Array.from(clone.childNodes);
|
|
441
473
|
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
442
474
|
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
443
475
|
|
|
476
|
+
// 복제된 최상위 요소들은 SwcChoose의 직접 자식이 될 것이므로 __swc_host 설정 안 함
|
|
444
477
|
this._nodes.forEach((n, nodeIdx) => {
|
|
445
|
-
if (n instanceof HTMLElement) (n as any).__swc_host = this;
|
|
478
|
+
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
446
479
|
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: n, $nodeIndex: nodeIdx, $isElement: n.nodeType === 1 });
|
|
480
|
+
|
|
481
|
+
// Attribute {{ }} 치환 - HTML string 차원에서 동적 치환
|
|
482
|
+
if (n instanceof HTMLElement) {
|
|
483
|
+
Array.from(n.attributes).forEach(attr => {
|
|
484
|
+
const value = attr.value || '';
|
|
485
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
486
|
+
const script = value.slice(2, -2).trim();
|
|
487
|
+
const result = FunctionUtils.executeReturn({
|
|
488
|
+
script,
|
|
489
|
+
context: n,
|
|
490
|
+
args: { ...groupArgs, $value: this._value }
|
|
491
|
+
});
|
|
492
|
+
n.setAttribute(attr.name, String(result));
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
447
496
|
});
|
|
448
497
|
|
|
449
498
|
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
450
499
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
500
|
+
this.parentElement?.insertBefore(clone, this.nextSibling);
|
|
501
|
+
// if (portal === this.parentElement) {
|
|
502
|
+
// portal.insertBefore(clone, this.nextSibling);
|
|
503
|
+
// } else {
|
|
504
|
+
// portal.appendChild(clone);
|
|
505
|
+
// }
|
|
456
506
|
}
|
|
457
507
|
}
|
|
458
508
|
|
|
@@ -474,35 +524,38 @@ export const registerAllElements = (w: any) => {
|
|
|
474
524
|
private _nodes: Node[] = [];
|
|
475
525
|
private _value: any = null;
|
|
476
526
|
|
|
477
|
-
private _resolvePortal(): Element | null {
|
|
478
|
-
const portalScript = this.getAttribute('on-get-portal');
|
|
479
|
-
if (!portalScript) return this.parentElement;
|
|
480
|
-
|
|
481
|
-
const win = this.ownerDocument?.defaultView || window;
|
|
482
|
-
const res = FunctionUtils.executeReturn({
|
|
483
|
-
script: portalScript,
|
|
484
|
-
context: this,
|
|
485
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
if (res instanceof HTMLElement) return res;
|
|
489
|
-
if (typeof res === 'string') return win.document.querySelector(res);
|
|
490
|
-
return this.parentElement;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
527
|
private _executeCloneCallback(attr: string, args: any) {
|
|
494
528
|
const script = this.getAttribute(attr);
|
|
495
529
|
if (!script) return;
|
|
496
530
|
FunctionUtils.execute({ script, context: this, args });
|
|
497
531
|
}
|
|
498
532
|
|
|
499
|
-
@changedAttributeHost('
|
|
500
|
-
private refresh() {
|
|
501
|
-
|
|
502
|
-
if (!
|
|
503
|
-
|
|
504
|
-
|
|
533
|
+
@changedAttributeHost('value')
|
|
534
|
+
private refresh(valueAttr?: string | null) {
|
|
535
|
+
valueAttr ??= this.getAttribute('value');
|
|
536
|
+
if (!valueAttr) {
|
|
537
|
+
this.render('default');
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// {{ }} 브레이스로 감싸진 값은 스크립트 실행
|
|
542
|
+
if (valueAttr.startsWith('{{') && valueAttr.endsWith('}}')) {
|
|
543
|
+
const script = valueAttr.slice(2, -2).trim();
|
|
544
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
545
|
+
const result = FunctionUtils.executeReturn({
|
|
546
|
+
script,
|
|
547
|
+
context: this,
|
|
548
|
+
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
this.executeAsync(result);
|
|
552
|
+
} else {
|
|
553
|
+
// 일반 문자열 값 또는 직접 Promise 속성
|
|
554
|
+
this.executeAsync(valueAttr);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
505
557
|
|
|
558
|
+
private executeAsync(result: any) {
|
|
506
559
|
if (result instanceof Promise) {
|
|
507
560
|
this.render('loading');
|
|
508
561
|
result
|
|
@@ -519,7 +572,7 @@ export const registerAllElements = (w: any) => {
|
|
|
519
572
|
|
|
520
573
|
private render(state: string) {
|
|
521
574
|
this.cleanup();
|
|
522
|
-
const portal = this.
|
|
575
|
+
const portal = this.parentElement;
|
|
523
576
|
if (!portal) return;
|
|
524
577
|
|
|
525
578
|
const win = this.ownerDocument?.defaultView || window;
|
|
@@ -532,18 +585,31 @@ export const registerAllElements = (w: any) => {
|
|
|
532
585
|
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
533
586
|
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0], $state: state };
|
|
534
587
|
|
|
588
|
+
// 부모 체인을 정상적으로 유지하기 위해 __swc_host 할당 제거
|
|
535
589
|
this._nodes.forEach((n, nodeIdx) => {
|
|
536
|
-
if (n instanceof HTMLElement) (n as any).__swc_host = this;
|
|
590
|
+
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
537
591
|
this._executeCloneCallback('on-clone-node', { ...groupArgs, $node: n, $nodeIndex: nodeIdx, $isElement: n.nodeType === 1 });
|
|
592
|
+
|
|
593
|
+
// Attribute {{ }} 치환 - SwcChoose처럼 동적 치환
|
|
594
|
+
if (n instanceof HTMLElement) {
|
|
595
|
+
Array.from(n.attributes).forEach(attr => {
|
|
596
|
+
const value = attr.value || '';
|
|
597
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
598
|
+
const script = value.slice(2, -2).trim();
|
|
599
|
+
const result = FunctionUtils.executeReturn({
|
|
600
|
+
script,
|
|
601
|
+
context: n,
|
|
602
|
+
args: groupArgs
|
|
603
|
+
});
|
|
604
|
+
n.setAttribute(attr.name, String(result));
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
}
|
|
538
608
|
});
|
|
539
609
|
|
|
540
610
|
this._executeCloneCallback('on-clone-nodes', groupArgs);
|
|
541
611
|
|
|
542
|
-
|
|
543
|
-
portal.insertBefore(clone, this.nextSibling);
|
|
544
|
-
} else {
|
|
545
|
-
portal.appendChild(clone);
|
|
546
|
-
}
|
|
612
|
+
portal.insertBefore(clone, this.nextSibling);
|
|
547
613
|
}
|
|
548
614
|
}
|
|
549
615
|
|
|
@@ -732,4 +798,78 @@ export const registerAllElements = (w: any) => {
|
|
|
732
798
|
@elementDefine('swc-app-body', { extends: 'body', window: w })
|
|
733
799
|
class SwcAppBody extends SwcAppMixin(HTMLBodyElement) {}
|
|
734
800
|
|
|
801
|
+
|
|
802
|
+
return {
|
|
803
|
+
// Sub Templates
|
|
804
|
+
SwcLoading,
|
|
805
|
+
SwcError,
|
|
806
|
+
SwcSuccess,
|
|
807
|
+
SwcWhen,
|
|
808
|
+
SwcOtherwise,
|
|
809
|
+
SwcDefault,
|
|
810
|
+
// Core Elements
|
|
811
|
+
SwcApp,
|
|
812
|
+
SwcIf,
|
|
813
|
+
SwcLoop,
|
|
814
|
+
SwcChoose,
|
|
815
|
+
SwcAsync,
|
|
816
|
+
// App Elements
|
|
817
|
+
SwcAppAnchor,
|
|
818
|
+
SwcAppArea,
|
|
819
|
+
SwcAppAudio,
|
|
820
|
+
SwcAppBase,
|
|
821
|
+
SwcAppButton,
|
|
822
|
+
SwcAppCanvas,
|
|
823
|
+
SwcAppData,
|
|
824
|
+
SwcAppDataList,
|
|
825
|
+
SwcAppDetails,
|
|
826
|
+
SwcAppDialog,
|
|
827
|
+
SwcAppDiv,
|
|
828
|
+
SwcAppDList,
|
|
829
|
+
SwcAppEmbed,
|
|
830
|
+
SwcAppFieldSet,
|
|
831
|
+
SwcAppForm,
|
|
832
|
+
SwcAppHR,
|
|
833
|
+
SwcAppIFrame,
|
|
834
|
+
SwcAppImage,
|
|
835
|
+
SwcAppInput,
|
|
836
|
+
SwcAppLabel,
|
|
837
|
+
SwcAppLegend,
|
|
838
|
+
SwcAppLI,
|
|
839
|
+
SwcAppLink,
|
|
840
|
+
SwcAppMap,
|
|
841
|
+
SwcAppMeta,
|
|
842
|
+
SwcAppMeter,
|
|
843
|
+
SwcAppMod,
|
|
844
|
+
SwcAppObject,
|
|
845
|
+
SwcAppOList,
|
|
846
|
+
SwcAppOptGroup,
|
|
847
|
+
SwcAppOption,
|
|
848
|
+
SwcAppOutput,
|
|
849
|
+
SwcAppParagraph,
|
|
850
|
+
SwcAppParam,
|
|
851
|
+
SwcAppPicture,
|
|
852
|
+
SwcAppPre,
|
|
853
|
+
SwcAppProgress,
|
|
854
|
+
SwcAppQuote,
|
|
855
|
+
SwcAppScript,
|
|
856
|
+
SwcAppSelect,
|
|
857
|
+
SwcAppSlot,
|
|
858
|
+
SwcAppSource,
|
|
859
|
+
SwcAppSpan,
|
|
860
|
+
SwcAppStyle,
|
|
861
|
+
SwcAppTable,
|
|
862
|
+
SwcAppTableSection,
|
|
863
|
+
SwcAppTableCell,
|
|
864
|
+
SwcAppTemplate,
|
|
865
|
+
SwcAppTextArea,
|
|
866
|
+
SwcAppTime,
|
|
867
|
+
SwcAppTitle,
|
|
868
|
+
SwcAppTableRow,
|
|
869
|
+
SwcAppTrack,
|
|
870
|
+
SwcAppUList,
|
|
871
|
+
SwcAppVideo,
|
|
872
|
+
SwcAppHeading,
|
|
873
|
+
SwcAppBody,
|
|
874
|
+
};
|
|
735
875
|
};
|
package/src/index.ts
CHANGED
|
@@ -16,12 +16,14 @@ export * from './config/config';
|
|
|
16
16
|
|
|
17
17
|
// Registration Factory
|
|
18
18
|
export default (w: Window, other?: (((w: Window) => ConstructorType<any>) | any) []) => {
|
|
19
|
-
registerAllElements(w);
|
|
19
|
+
const cr = registerAllElements(w);
|
|
20
20
|
const r = other?.map(fn => {
|
|
21
21
|
if (typeof fn === 'function') {
|
|
22
22
|
const a = fn(w);
|
|
23
23
|
} else {
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
|
+
|
|
27
|
+
return cr;
|
|
26
28
|
// return r??[];
|
|
27
29
|
};
|
|
@@ -6,18 +6,7 @@ export class ElementRouter extends Router {
|
|
|
6
6
|
private _currentIndex = -1;
|
|
7
7
|
|
|
8
8
|
constructor(config: RouterConfig) {
|
|
9
|
-
|
|
10
|
-
// firstUrl을 제거하고 넘긴 뒤 자식에서 수동 처리합니다.
|
|
11
|
-
const { firstUrl, ...rest } = config;
|
|
12
|
-
super(rest);
|
|
13
|
-
|
|
14
|
-
const startUrl = firstUrl ?? '/';
|
|
15
|
-
this._history = [{ url: startUrl, data: null }];
|
|
16
|
-
this._currentIndex = 0;
|
|
17
|
-
|
|
18
|
-
if (firstUrl) {
|
|
19
|
-
this.replace(firstUrl, { config: { noEventAndPublish: true } });
|
|
20
|
-
}
|
|
9
|
+
super(config);
|
|
21
10
|
}
|
|
22
11
|
|
|
23
12
|
// Override pushState to manage internal history
|
package/src/types.ts
CHANGED
|
@@ -42,7 +42,9 @@ export type HostSet = {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
export type HelperHostSet = HelperSet & HostSet;
|
|
45
|
-
|
|
45
|
+
export interface SwcChooseInterface extends HTMLTemplateElement {
|
|
46
|
+
refresh(): void;
|
|
47
|
+
}
|
|
46
48
|
export interface SwcAppInterface extends HTMLElement {
|
|
47
49
|
simpleApplication?: SimpleApplication;
|
|
48
50
|
router?: Router;
|