@dooboostore/simple-web-component 1.0.31 → 1.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/decorators/applyStyle.js +1 -1
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +17 -1
- package/dist/cjs/decorators/attribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +26 -9
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/elements/SwcAppMixin.js +1 -1
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +69 -57
- package/dist/cjs/elements/SwcAsync.js.map +2 -2
- package/dist/cjs/elements/SwcChoose.js +66 -60
- package/dist/cjs/elements/SwcChoose.js.map +2 -2
- package/dist/cjs/elements/SwcIf.js +51 -66
- package/dist/cjs/elements/SwcIf.js.map +2 -2
- package/dist/cjs/elements/SwcLoop.js +58 -78
- package/dist/cjs/elements/SwcLoop.js.map +2 -2
- package/dist/cjs/elements/register.js +310 -335
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/Utils.js +7 -13
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +1 -1
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/attribute.js +18 -2
- package/dist/esm/decorators/attribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +24 -7
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/elements/SwcAppMixin.js +1 -1
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +70 -58
- package/dist/esm/elements/SwcAsync.js.map +2 -2
- package/dist/esm/elements/SwcChoose.js +67 -61
- package/dist/esm/elements/SwcChoose.js.map +2 -2
- package/dist/esm/elements/SwcIf.js +52 -67
- package/dist/esm/elements/SwcIf.js.map +2 -2
- package/dist/esm/elements/SwcLoop.js +59 -79
- package/dist/esm/elements/SwcLoop.js.map +2 -2
- package/dist/esm/elements/register.js +239 -264
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/Utils.js +7 -13
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2623 -2422
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/attribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/elements/register.d.ts.map +1 -1
- package/dist/types/types.d.ts +8 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2623 -2422
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +1 -1
- package/src/decorators/applyStyle.ts +1 -1
- package/src/decorators/attribute.ts +35 -30
- package/src/decorators/elementDefine.ts +26 -7
- package/src/elements/SwcAppMixin.ts +1 -1
- package/src/elements/SwcAsync.ts +75 -69
- package/src/elements/SwcChoose.ts +67 -80
- package/src/elements/SwcIf.ts +51 -76
- package/src/elements/SwcLoop.ts +56 -87
- package/src/elements/register.ts +235 -307
- package/src/types.ts +6 -1
- package/src/utils/Utils.ts +11 -17
package/src/elements/register.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { elementDefine } from '../decorators
|
|
1
|
+
import { elementDefine, attributeHost, changedAttributeHost } from '../decorators';
|
|
2
2
|
import { SwcAppMixin } from './SwcAppMixin';
|
|
3
3
|
import { SwcUtils } from '../utils/Utils';
|
|
4
|
-
import { FunctionUtils } from '@dooboostore/core';
|
|
5
|
-
import {
|
|
4
|
+
import { FunctionUtils,ActionExpression } from '@dooboostore/core';
|
|
5
|
+
import { ConvertUtils } from '@dooboostore/core-web';
|
|
6
6
|
|
|
7
7
|
type Constructor<T> = new (...args: any[]) => T;
|
|
8
8
|
|
|
@@ -148,99 +148,74 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
148
148
|
|
|
149
149
|
@elementDefine('swc-if', { extends: 'template', window: w })
|
|
150
150
|
class SwcIf extends HTMLTemplateElement {
|
|
151
|
-
|
|
151
|
+
@attributeHost('value')
|
|
152
|
+
_value: any;
|
|
153
|
+
|
|
154
|
+
@attributeHost('replace-wrap')
|
|
155
|
+
_replaceWrap: string | null;
|
|
156
|
+
|
|
152
157
|
private _nodes: Node[] = [];
|
|
153
158
|
|
|
154
159
|
get value(): boolean {
|
|
155
160
|
return this._value;
|
|
156
161
|
}
|
|
162
|
+
|
|
157
163
|
set value(nv: any) {
|
|
158
|
-
this._value =
|
|
159
|
-
this.
|
|
164
|
+
// this._value = nv;
|
|
165
|
+
this.refresh(nv);
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
private
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
169
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
170
|
+
const ae = new ActionExpression(html, config);
|
|
171
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
172
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
173
|
+
|
|
174
|
+
// @ts-ignore
|
|
175
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
176
|
+
try {
|
|
177
|
+
const value = FunctionUtils.executeReturn({
|
|
178
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
179
|
+
context,
|
|
180
|
+
args: groupArgs
|
|
181
|
+
});
|
|
182
|
+
ae.replace(expr, String(value));
|
|
183
|
+
} catch (e) {
|
|
184
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return ae.getUnprocessedTemplate();
|
|
166
188
|
}
|
|
167
189
|
|
|
168
190
|
@changedAttributeHost('value')
|
|
169
|
-
private
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
this.value = false;
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
191
|
+
private setValue(valueAttr?: string | null) {
|
|
192
|
+
this.refresh();
|
|
193
|
+
}
|
|
175
194
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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;
|
|
186
|
-
} else {
|
|
187
|
-
// 일반 문자열 값
|
|
188
|
-
this.value = Boolean(valueAttr);
|
|
189
|
-
}
|
|
195
|
+
@changedAttributeHost('replace-wrap')
|
|
196
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
197
|
+
this.refresh();
|
|
190
198
|
}
|
|
191
199
|
|
|
192
|
-
|
|
200
|
+
refresh(value = this._value) {
|
|
193
201
|
this.cleanup();
|
|
194
202
|
const portal = this.parentElement;
|
|
195
|
-
if (!portal) return;
|
|
203
|
+
if (!portal || !value) return;
|
|
196
204
|
|
|
197
205
|
const win = this.ownerDocument?.defaultView || window;
|
|
198
206
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
199
207
|
|
|
200
|
-
let
|
|
201
|
-
|
|
202
|
-
targetTpl = this;
|
|
203
|
-
} else {
|
|
204
|
-
targetTpl = this.content.querySelector('template[is="swc-default"]') as HTMLTemplateElement;
|
|
205
|
-
}
|
|
208
|
+
let htmlString = this.innerHTML;
|
|
209
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
206
210
|
|
|
207
|
-
|
|
208
|
-
const clone = targetTpl.content.cloneNode(true) as DocumentFragment;
|
|
209
|
-
// If it's the host template, remove sub-templates from clone
|
|
210
|
-
if (targetTpl === this) {
|
|
211
|
-
clone.querySelectorAll('template[is^="swc-"]').forEach(t => t.remove());
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
this._nodes = Array.from(clone.childNodes);
|
|
215
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
216
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
217
|
-
|
|
218
|
-
// 부모 체인을 정상적으로 유지하기 위해 __swc_host 할당 제거
|
|
219
|
-
this._nodes.forEach((node, nodeIdx) => {
|
|
220
|
-
// if (node instanceof HTMLElement) (node as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
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
|
-
}
|
|
238
|
-
});
|
|
211
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
239
212
|
|
|
240
|
-
|
|
213
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
214
|
+
result.innerHTML = htmlString;
|
|
215
|
+
const processedFragment = result.content;
|
|
241
216
|
|
|
242
|
-
|
|
243
|
-
|
|
217
|
+
this._nodes = Array.from(processedFragment.childNodes);
|
|
218
|
+
portal.insertBefore(processedFragment, this.nextSibling);
|
|
244
219
|
}
|
|
245
220
|
|
|
246
221
|
private cleanup() {
|
|
@@ -248,9 +223,6 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
248
223
|
this._nodes = [];
|
|
249
224
|
}
|
|
250
225
|
|
|
251
|
-
connectedCallback() {
|
|
252
|
-
this.refreshValue();
|
|
253
|
-
}
|
|
254
226
|
disconnectedCallback() {
|
|
255
227
|
this.cleanup();
|
|
256
228
|
}
|
|
@@ -258,57 +230,57 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
258
230
|
|
|
259
231
|
@elementDefine('swc-loop', { extends: 'template', window: w })
|
|
260
232
|
class SwcLoop extends HTMLTemplateElement {
|
|
261
|
-
|
|
233
|
+
@attributeHost('value')
|
|
234
|
+
_value: any[];
|
|
235
|
+
|
|
236
|
+
@attributeHost('replace-wrap')
|
|
237
|
+
_replaceWrap: string | null;
|
|
238
|
+
|
|
262
239
|
private _nodeGroups: Node[][] = [];
|
|
263
240
|
|
|
264
241
|
get value(): any[] {
|
|
265
242
|
return this._value;
|
|
266
243
|
}
|
|
267
244
|
set value(nv: any[]) {
|
|
268
|
-
this._value = Array.isArray(nv) ? [...nv] : [];
|
|
269
|
-
this.
|
|
245
|
+
// this._value = Array.isArray(nv) ? [...nv] : [];
|
|
246
|
+
this.refresh(nv);
|
|
270
247
|
}
|
|
271
248
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const script = this.getAttribute(attr);
|
|
276
|
-
if (!script) return;
|
|
277
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
249
|
+
@changedAttributeHost('value')
|
|
250
|
+
private setValue() {
|
|
251
|
+
this.refresh();
|
|
278
252
|
}
|
|
279
253
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
this.
|
|
254
|
+
@changedAttributeHost('replace-wrap')
|
|
255
|
+
private setReplaceWrap() {
|
|
256
|
+
this.refresh();
|
|
283
257
|
}
|
|
284
258
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.value = [];
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
// Parse {{ }} braces
|
|
293
|
-
if (script.startsWith('{{') && script.endsWith('}}')) {
|
|
294
|
-
script = script.slice(2, -2).trim();
|
|
295
|
-
}
|
|
259
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
260
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
261
|
+
const ae = new ActionExpression(html, config);
|
|
262
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
296
263
|
const win = this.ownerDocument?.defaultView || window;
|
|
297
|
-
const res = FunctionUtils.executeReturn({
|
|
298
|
-
script,
|
|
299
|
-
context: this,
|
|
300
|
-
args: SwcUtils.getHelperAndHostSet(win, this)
|
|
301
|
-
});
|
|
302
264
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
267
|
+
try {
|
|
268
|
+
const value = FunctionUtils.executeReturn({
|
|
269
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
270
|
+
context,
|
|
271
|
+
args: groupArgs
|
|
272
|
+
});
|
|
273
|
+
ae.replace(expr, String(value));
|
|
274
|
+
} catch (e) {
|
|
275
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
276
|
+
}
|
|
307
277
|
}
|
|
278
|
+
return ae.getUnprocessedTemplate();
|
|
308
279
|
}
|
|
309
280
|
|
|
310
|
-
|
|
311
|
-
this.
|
|
281
|
+
refresh(value = this._value) {
|
|
282
|
+
this.cleanup();
|
|
283
|
+
if (value?.length<=0) return;
|
|
312
284
|
const portal = this.parentElement;
|
|
313
285
|
if (!portal) return;
|
|
314
286
|
|
|
@@ -316,135 +288,115 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
316
288
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
317
289
|
const fragment = win.document.createDocumentFragment();
|
|
318
290
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const clone = defaultTpl.content.cloneNode(true);
|
|
323
|
-
const nodes = Array.from(clone.childNodes);
|
|
324
|
-
this._nodeGroups.push(nodes);
|
|
325
|
-
fragment.appendChild(clone);
|
|
326
|
-
}
|
|
327
|
-
} else {
|
|
328
|
-
this._value.forEach((item, index) => {
|
|
329
|
-
const clone = this.content.cloneNode(true) as DocumentFragment;
|
|
330
|
-
// Filter out sub-templates
|
|
331
|
-
const subTemplates = clone.querySelectorAll('template[is^="swc-"]');
|
|
332
|
-
subTemplates.forEach(t => t.remove());
|
|
333
|
-
|
|
334
|
-
const nodes = Array.from(clone.childNodes);
|
|
335
|
-
const elements = nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
336
|
-
|
|
337
|
-
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value, $nodes: nodes, $elements: elements, $firstElement: elements[0] };
|
|
338
|
-
|
|
339
|
-
nodes.forEach((node, nodeIdx) => {
|
|
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
|
-
}
|
|
357
|
-
});
|
|
291
|
+
value.forEach((item, index) => {
|
|
292
|
+
let htmlString = this.innerHTML;
|
|
293
|
+
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value };
|
|
358
294
|
|
|
359
|
-
|
|
360
|
-
this._nodeGroups.push(nodes);
|
|
361
|
-
fragment.appendChild(clone);
|
|
362
|
-
});
|
|
363
|
-
}
|
|
295
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
364
296
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
297
|
+
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
298
|
+
temp.innerHTML = htmlString;
|
|
299
|
+
|
|
300
|
+
const content = temp.content;
|
|
301
|
+
const nodes = Array.from(content.childNodes);
|
|
302
|
+
this._nodeGroups.push(nodes);
|
|
303
|
+
fragment.appendChild(content);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
portal.insertBefore(fragment, this.nextSibling);
|
|
370
307
|
}
|
|
371
308
|
|
|
372
|
-
|
|
373
|
-
this.
|
|
309
|
+
private cleanup() {
|
|
310
|
+
this._nodeGroups.forEach(nodes => nodes.forEach(n => n.parentElement?.removeChild(n)));
|
|
311
|
+
this._nodeGroups = [];
|
|
374
312
|
}
|
|
313
|
+
|
|
375
314
|
disconnectedCallback() {
|
|
376
|
-
this.
|
|
315
|
+
this.cleanup();
|
|
377
316
|
}
|
|
378
317
|
}
|
|
379
318
|
|
|
380
319
|
@elementDefine('swc-choose', { extends: 'template', window: w })
|
|
381
320
|
class SwcChoose extends HTMLTemplateElement {
|
|
321
|
+
@attributeHost('value')
|
|
322
|
+
_value: any;
|
|
323
|
+
|
|
324
|
+
@attributeHost('replace-wrap')
|
|
325
|
+
_replaceWrap: string | null;
|
|
326
|
+
|
|
382
327
|
private _nodes: Node[] = [];
|
|
383
|
-
private _value: any = null;
|
|
384
328
|
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
385
329
|
|
|
386
330
|
get value(): any {
|
|
387
331
|
return this._value;
|
|
388
332
|
}
|
|
333
|
+
|
|
389
334
|
set value(nv: any) {
|
|
390
|
-
this.
|
|
391
|
-
this.render();
|
|
335
|
+
this.refresh(nv);
|
|
392
336
|
}
|
|
393
337
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
FunctionUtils.execute({ script, context: this, args });
|
|
338
|
+
@changedAttributeHost('value')
|
|
339
|
+
private setValue() {
|
|
340
|
+
this.refresh();
|
|
398
341
|
}
|
|
399
342
|
|
|
400
|
-
@changedAttributeHost('
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
this.value = null;
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
343
|
+
@changedAttributeHost('replace-wrap')
|
|
344
|
+
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
345
|
+
this.refresh();
|
|
346
|
+
}
|
|
407
347
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
348
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
349
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
350
|
+
const ae = new ActionExpression(html, config);
|
|
351
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
352
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
353
|
+
|
|
354
|
+
// @ts-ignore
|
|
355
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
356
|
+
try {
|
|
357
|
+
const value = FunctionUtils.executeReturn({
|
|
358
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
359
|
+
context,
|
|
360
|
+
args: groupArgs
|
|
361
|
+
});
|
|
362
|
+
ae.replace(expr, String(value));
|
|
363
|
+
} catch (e) {
|
|
364
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
365
|
+
}
|
|
420
366
|
}
|
|
367
|
+
return ae.getUnprocessedTemplate();
|
|
421
368
|
}
|
|
422
369
|
|
|
423
|
-
|
|
424
|
-
|
|
370
|
+
refresh(value = this._value) {
|
|
371
|
+
const portal = this.parentElement;
|
|
372
|
+
if (!portal) return;
|
|
373
|
+
|
|
425
374
|
const win = this.ownerDocument?.defaultView || window;
|
|
426
375
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
376
|
+
const groupArgs = { ...helperSet, $value: value };
|
|
377
|
+
|
|
427
378
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
428
379
|
let selected: HTMLTemplateElement | null = null;
|
|
429
380
|
|
|
430
381
|
for (const t of templates) {
|
|
431
382
|
if (t.getAttribute('is') === 'swc-when') {
|
|
383
|
+
const attrVal = t.getAttribute('value') || '';
|
|
432
384
|
let matches = false;
|
|
433
|
-
const value = t.getAttribute('value') || '';
|
|
434
385
|
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
|
|
386
|
+
// Use ActionExpression to parse and extract script from value attribute
|
|
387
|
+
const ae = new ActionExpression(attrVal);
|
|
388
|
+
const expr = ae.getFirstExpression('replace');
|
|
389
|
+
|
|
390
|
+
if (expr) {
|
|
391
|
+
const decodedScript = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
438
392
|
const result = FunctionUtils.executeReturn({
|
|
439
|
-
script,
|
|
393
|
+
script: decodedScript,
|
|
440
394
|
context: t,
|
|
441
|
-
args:
|
|
395
|
+
args: groupArgs
|
|
442
396
|
});
|
|
443
|
-
|
|
444
|
-
matches = result === true;
|
|
397
|
+
matches = !!result;
|
|
445
398
|
} else {
|
|
446
|
-
|
|
447
|
-
matches = String(value) === String(this._value);
|
|
399
|
+
matches = String(attrVal) === String(value);
|
|
448
400
|
}
|
|
449
401
|
|
|
450
402
|
if (matches) {
|
|
@@ -456,11 +408,12 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
456
408
|
|
|
457
409
|
const target = selected || (this.content.querySelector('template[is="swc-otherwise"]') as HTMLTemplateElement);
|
|
458
410
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
const
|
|
463
|
-
|
|
411
|
+
const skipValue = target?.getAttribute?.('skip-if-same');
|
|
412
|
+
const skipValue2 = this._previousTemplate?.getAttribute?.('skip-if-same');
|
|
413
|
+
const hasSkipIfSame = target?.hasAttribute?.('skip-if-same');
|
|
414
|
+
const isSame = this._previousTemplate === target;
|
|
415
|
+
// console.log('---rrrr---', this._previousTemplate, target, hasSkipIfSame, isSame, skipValue, skipValue2);
|
|
416
|
+
if (hasSkipIfSame && isSame) {
|
|
464
417
|
return;
|
|
465
418
|
}
|
|
466
419
|
|
|
@@ -468,41 +421,15 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
468
421
|
this._previousTemplate = target;
|
|
469
422
|
|
|
470
423
|
if (target) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
474
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0] };
|
|
475
|
-
|
|
476
|
-
// 복제된 최상위 요소들은 SwcChoose의 직접 자식이 될 것이므로 __swc_host 설정 안 함
|
|
477
|
-
this._nodes.forEach((n, nodeIdx) => {
|
|
478
|
-
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
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
|
-
}
|
|
496
|
-
});
|
|
424
|
+
let htmlString = target.innerHTML;
|
|
425
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
497
426
|
|
|
498
|
-
this.
|
|
427
|
+
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
428
|
+
result.innerHTML = htmlString;
|
|
429
|
+
const processedFragment = result.content;
|
|
499
430
|
|
|
500
|
-
this.
|
|
501
|
-
|
|
502
|
-
// portal.insertBefore(clone, this.nextSibling);
|
|
503
|
-
// } else {
|
|
504
|
-
// portal.appendChild(clone);
|
|
505
|
-
// }
|
|
431
|
+
this._nodes = Array.from(processedFragment.childNodes);
|
|
432
|
+
portal.insertBefore(processedFragment, this.nextSibling);
|
|
506
433
|
}
|
|
507
434
|
}
|
|
508
435
|
|
|
@@ -511,9 +438,6 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
511
438
|
this._nodes = [];
|
|
512
439
|
}
|
|
513
440
|
|
|
514
|
-
connectedCallback() {
|
|
515
|
-
this.refresh();
|
|
516
|
-
}
|
|
517
441
|
disconnectedCallback() {
|
|
518
442
|
this.cleanup();
|
|
519
443
|
}
|
|
@@ -521,56 +445,82 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
521
445
|
|
|
522
446
|
@elementDefine('swc-async', { extends: 'template', window: w })
|
|
523
447
|
class SwcAsync extends HTMLTemplateElement {
|
|
524
|
-
|
|
525
|
-
|
|
448
|
+
@attributeHost('value')
|
|
449
|
+
_value: any;
|
|
526
450
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
451
|
+
@attributeHost('replace-wrap')
|
|
452
|
+
_replaceWrap: string | null;
|
|
453
|
+
|
|
454
|
+
resultValue?: any;
|
|
455
|
+
|
|
456
|
+
get value(): boolean {
|
|
457
|
+
return this._value;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
set value(nv: any) {
|
|
461
|
+
this.executeAsync(nv);
|
|
531
462
|
}
|
|
532
463
|
|
|
464
|
+
private _nodes: Node[] = [];
|
|
465
|
+
|
|
533
466
|
@changedAttributeHost('value')
|
|
534
|
-
private
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
this.render('default');
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
467
|
+
private setValue(valueAttr?: string | null) {
|
|
468
|
+
this.executeAsync(this._value);
|
|
469
|
+
}
|
|
540
470
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
}
|
|
471
|
+
@changedAttributeHost('replace-wrap')
|
|
472
|
+
private setReplaceWrap() {
|
|
473
|
+
this.executeAsync(this._value);
|
|
556
474
|
}
|
|
557
475
|
|
|
558
|
-
private executeAsync(result: any) {
|
|
476
|
+
private executeAsync(result: any = this._value) {
|
|
477
|
+
if (result === undefined || result === null) {
|
|
478
|
+
this.refresh('default');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
|
|
559
482
|
if (result instanceof Promise) {
|
|
560
|
-
this.
|
|
483
|
+
this.refresh('loading');
|
|
561
484
|
result
|
|
562
485
|
.then(v => {
|
|
563
|
-
this.
|
|
564
|
-
this.
|
|
486
|
+
this.resultValue = v;
|
|
487
|
+
this.refresh('success');
|
|
565
488
|
})
|
|
566
|
-
.catch(e =>
|
|
489
|
+
.catch(e => {
|
|
490
|
+
console.error('[SWC-ASYNC] Promise rejected:', e);
|
|
491
|
+
this.resultValue = e;
|
|
492
|
+
this.refresh('error');
|
|
493
|
+
});
|
|
567
494
|
} else {
|
|
568
|
-
this.
|
|
569
|
-
this.
|
|
495
|
+
this.resultValue = result;
|
|
496
|
+
this.refresh('success');
|
|
570
497
|
}
|
|
571
498
|
}
|
|
572
499
|
|
|
573
|
-
private
|
|
500
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap?: string | null): string {
|
|
501
|
+
const config = wrap ? { wrapExpression: wrap } : undefined;
|
|
502
|
+
const ae = new ActionExpression(html, config);
|
|
503
|
+
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
504
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
505
|
+
|
|
506
|
+
// @ts-ignore
|
|
507
|
+
for (const expr of ae.getExpressions(filterOptions)) {
|
|
508
|
+
try {
|
|
509
|
+
const value = FunctionUtils.executeReturn({
|
|
510
|
+
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
511
|
+
context,
|
|
512
|
+
args: groupArgs
|
|
513
|
+
});
|
|
514
|
+
ae.replace(expr, String(value));
|
|
515
|
+
} catch (e) {
|
|
516
|
+
console.error(`[SWC] Failed to execute ${expr.original}:`, e);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return ae.getUnprocessedTemplate();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
refresh(state: string = 'default') {
|
|
523
|
+
console.log('rrrrrrrrrrrrrrrrr', state);
|
|
574
524
|
this.cleanup();
|
|
575
525
|
const portal = this.parentElement;
|
|
576
526
|
if (!portal) return;
|
|
@@ -580,36 +530,17 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
580
530
|
|
|
581
531
|
const t = this.content.querySelector(`template[is="swc-${state}"]`) as HTMLTemplateElement;
|
|
582
532
|
if (t) {
|
|
583
|
-
|
|
584
|
-
this.
|
|
585
|
-
const elements = this._nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
586
|
-
const groupArgs = { ...helperSet, $value: this._value, $nodes: this._nodes, $elements: elements, $firstElement: elements[0], $state: state };
|
|
587
|
-
|
|
588
|
-
// 부모 체인을 정상적으로 유지하기 위해 __swc_host 할당 제거
|
|
589
|
-
this._nodes.forEach((n, nodeIdx) => {
|
|
590
|
-
// if (n instanceof HTMLElement) (n as any).__swc_host = this; // 제거: 부모 체인 유지
|
|
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
|
-
}
|
|
608
|
-
});
|
|
533
|
+
let htmlString = t.innerHTML;
|
|
534
|
+
const groupArgs = { ...helperSet, $value: this._value, $state: state };
|
|
609
535
|
|
|
610
|
-
this.
|
|
536
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this._replaceWrap);
|
|
611
537
|
|
|
612
|
-
|
|
538
|
+
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
539
|
+
temp.innerHTML = htmlString;
|
|
540
|
+
const content = temp.content;
|
|
541
|
+
|
|
542
|
+
this._nodes = Array.from(content.childNodes);
|
|
543
|
+
portal.insertBefore(content, this.nextSibling);
|
|
613
544
|
}
|
|
614
545
|
}
|
|
615
546
|
|
|
@@ -618,9 +549,6 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
618
549
|
this._nodes = [];
|
|
619
550
|
}
|
|
620
551
|
|
|
621
|
-
connectedCallback() {
|
|
622
|
-
this.refresh();
|
|
623
|
-
}
|
|
624
552
|
disconnectedCallback() {
|
|
625
553
|
this.cleanup();
|
|
626
554
|
}
|