@dooboostore/simple-web-component 1.0.34 → 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/applyNode.js +4 -0
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +1 -1
- package/dist/cjs/decorators/attribute.js.map +2 -2
- package/dist/cjs/decorators/changedAttributeHost.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +225 -180
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/emitCustomEvent.js +10 -4
- 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/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/elements/SwcAppEngine.js +8 -2
- package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +120 -65
- 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 +51 -32
- 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 +244 -117
- 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 +18 -4
- package/dist/cjs/utils/Utils.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +4 -0
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/attribute.js +1 -1
- package/dist/esm/decorators/attribute.js.map +2 -2
- package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +226 -181
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/emitCustomEvent.js +10 -4
- 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/subscribeSwcAppRouteChangeWhileConnected.js +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/elements/SwcAppEngine.js +9 -2
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +122 -66
- 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 +51 -32
- 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 +244 -117
- 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 +18 -4
- package/dist/esm/utils/Utils.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +319 -276
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/applyNode.d.ts +1 -0
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/changedAttributeHost.d.ts +1 -0
- package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +10 -6
- 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/subscribeSwcAppRouteChangeWhileConnected.d.ts +4 -5
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -1
- package/dist/types/elements/SwcAppEngine.d.ts +4 -1
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +11 -8
- 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 +319 -276
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +4 -4
- package/src/decorators/applyNode.ts +13 -1
- package/src/decorators/attribute.ts +1 -1
- package/src/decorators/changedAttributeHost.ts +3 -2
- package/src/decorators/elementDefine.ts +397 -354
- package/src/decorators/emitCustomEvent.ts +29 -15
- package/src/decorators/lifecycles.ts +11 -10
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +10 -10
- package/src/elements/SwcAppEngine.ts +10 -3
- package/src/elements/SwcAppMixin.ts +177 -97
- package/src/elements/SwcAsync.ts +28 -17
- package/src/elements/SwcChoose.ts +71 -34
- package/src/elements/SwcIf.ts +59 -22
- package/src/elements/SwcLoop.ts +140 -27
- package/src/elements/register.ts +296 -98
- package/src/types.ts +1 -0
- package/src/utils/Utils.ts +23 -5
- package/tsconfig.json +2 -2
package/src/elements/register.ts
CHANGED
|
@@ -148,11 +148,17 @@ 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
|
+
// id =
|
|
152
|
+
// @attributeHost('value')
|
|
152
153
|
_value: any;
|
|
153
154
|
|
|
154
|
-
@attributeHost('replace-wrap')
|
|
155
|
-
|
|
155
|
+
@attributeHost('replace-wrap-start')
|
|
156
|
+
_replaceWrapStart: string | null;
|
|
157
|
+
@attributeHost('replace-wrap-end')
|
|
158
|
+
_replaceWrapEnd: string | null;
|
|
159
|
+
|
|
160
|
+
@attributeHost('skip-if-same')
|
|
161
|
+
_skipIfSame: string | null;
|
|
156
162
|
|
|
157
163
|
private _nodes: Node[] = [];
|
|
158
164
|
|
|
@@ -165,14 +171,37 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
165
171
|
this.refresh(nv);
|
|
166
172
|
}
|
|
167
173
|
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
constructor() {
|
|
175
|
+
super();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@changedAttributeHost('value')
|
|
179
|
+
private setValue(value: any, o: string, n: string) {
|
|
180
|
+
this._value = value;
|
|
181
|
+
this.refresh(this._value);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// @changedAttributeHost('replace-wrap')
|
|
185
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
186
|
+
// this.refresh();
|
|
187
|
+
// }
|
|
188
|
+
|
|
189
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
190
|
+
let config: any = undefined;
|
|
191
|
+
if (wrap) {
|
|
192
|
+
config = {
|
|
193
|
+
expression: {
|
|
194
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
195
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
196
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
170
200
|
const ae = new ActionExpression(html, config);
|
|
171
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
172
201
|
const win = this.ownerDocument?.defaultView || window;
|
|
173
|
-
|
|
202
|
+
|
|
174
203
|
// @ts-ignore
|
|
175
|
-
for (const expr of ae.getExpressions(
|
|
204
|
+
for (const expr of ae.getExpressions('replace')) {
|
|
176
205
|
try {
|
|
177
206
|
const value = FunctionUtils.executeReturn({
|
|
178
207
|
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
@@ -187,39 +216,47 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
187
216
|
return ae.getUnprocessedTemplate();
|
|
188
217
|
}
|
|
189
218
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.refresh();
|
|
193
|
-
}
|
|
219
|
+
refresh(value?: any) {
|
|
220
|
+
const targetValue = value !== undefined ? value : (getAttributeValue(this, 'value') ?? this._value);
|
|
194
221
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
222
|
+
// skip-if-same 속성이 존재하고(true/빈 문자열), 이전 값과 새로운 값이 완전히 동일하면 렌더링 스킵!
|
|
223
|
+
if (this.hasAttribute('skip-if-same') && this._value === targetValue && this._nodes.length > 0) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
199
226
|
|
|
200
|
-
refresh(value = this._value) {
|
|
201
227
|
this.cleanup();
|
|
228
|
+
this._value = targetValue;
|
|
229
|
+
|
|
202
230
|
const portal = this.parentElement;
|
|
203
|
-
if (!portal || !
|
|
231
|
+
if (!portal || !this._value) return;
|
|
204
232
|
|
|
205
233
|
const win = this.ownerDocument?.defaultView || window;
|
|
206
234
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
207
235
|
|
|
208
236
|
let htmlString = this.innerHTML;
|
|
209
|
-
const groupArgs = { ...helperSet, $value:
|
|
237
|
+
const groupArgs = { ...helperSet, $value: this._value, $templateHost: this };
|
|
210
238
|
|
|
211
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
239
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
212
240
|
|
|
213
241
|
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
214
242
|
result.innerHTML = htmlString;
|
|
215
243
|
const processedFragment = result.content;
|
|
216
244
|
|
|
217
245
|
this._nodes = Array.from(processedFragment.childNodes);
|
|
246
|
+
this._nodes.forEach((node: any) => {
|
|
247
|
+
if (node instanceof HTMLElement) (node as any).__swc_template_host = this;
|
|
248
|
+
});
|
|
249
|
+
|
|
218
250
|
portal.insertBefore(processedFragment, this.nextSibling);
|
|
219
251
|
}
|
|
220
252
|
|
|
221
253
|
private cleanup() {
|
|
222
|
-
this._nodes.forEach(n =>
|
|
254
|
+
this._nodes.forEach(n => {
|
|
255
|
+
const realNode = (n as any).__upgraded_instance || n;
|
|
256
|
+
if (realNode.parentElement) {
|
|
257
|
+
realNode.parentElement.removeChild(realNode);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
223
260
|
this._nodes = [];
|
|
224
261
|
}
|
|
225
262
|
|
|
@@ -230,43 +267,64 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
230
267
|
|
|
231
268
|
@elementDefine('swc-loop', { extends: 'template', window: w })
|
|
232
269
|
class SwcLoop extends HTMLTemplateElement {
|
|
233
|
-
|
|
234
|
-
_value: any[];
|
|
270
|
+
_value: any[] = [];
|
|
235
271
|
|
|
236
|
-
@attributeHost('replace-wrap')
|
|
237
|
-
|
|
272
|
+
@attributeHost('replace-wrap-start')
|
|
273
|
+
_replaceWrapStart: string | null;
|
|
274
|
+
@attributeHost('replace-wrap-end')
|
|
275
|
+
_replaceWrapEnd: string | null;
|
|
238
276
|
|
|
239
277
|
private _nodeGroups: Node[][] = [];
|
|
240
278
|
|
|
241
279
|
get value(): any[] {
|
|
242
280
|
return this._value;
|
|
243
281
|
}
|
|
282
|
+
|
|
244
283
|
set value(nv: any[]) {
|
|
245
|
-
|
|
284
|
+
this._value = nv;
|
|
246
285
|
this.refresh(nv);
|
|
247
286
|
}
|
|
248
287
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
this.refresh();
|
|
288
|
+
getValue(index: number) {
|
|
289
|
+
return this._value?.[index];
|
|
252
290
|
}
|
|
253
291
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
292
|
+
constructor() {
|
|
293
|
+
super();
|
|
294
|
+
// console.log('swc SwcLoop constructor called!');
|
|
295
|
+
// console.log('swc SwcLoop', this.getAttribute('value'));
|
|
257
296
|
}
|
|
258
297
|
|
|
259
|
-
|
|
260
|
-
|
|
298
|
+
@changedAttributeHost('value')
|
|
299
|
+
private setValue(value: any, o: string, n: string) {
|
|
300
|
+
this._value = value;
|
|
301
|
+
this.refresh(this._value);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// @changedAttributeHost('replace-wrap')
|
|
305
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
306
|
+
// this.refresh();
|
|
307
|
+
// }
|
|
308
|
+
|
|
309
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
310
|
+
let config: any = undefined;
|
|
311
|
+
config = {
|
|
312
|
+
expression: {
|
|
313
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
314
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
315
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
316
|
+
}
|
|
317
|
+
};
|
|
261
318
|
const ae = new ActionExpression(html, config);
|
|
262
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
263
319
|
const win = this.ownerDocument?.defaultView || window;
|
|
264
320
|
|
|
265
321
|
// @ts-ignore
|
|
266
|
-
|
|
322
|
+
const expressions = ae.getExpressions('replace');
|
|
323
|
+
for (const expr of expressions) {
|
|
324
|
+
const script = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
267
325
|
try {
|
|
268
326
|
const value = FunctionUtils.executeReturn({
|
|
269
|
-
script:
|
|
327
|
+
script: script,
|
|
270
328
|
context,
|
|
271
329
|
args: groupArgs
|
|
272
330
|
});
|
|
@@ -278,35 +336,127 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
278
336
|
return ae.getUnprocessedTemplate();
|
|
279
337
|
}
|
|
280
338
|
|
|
281
|
-
|
|
282
|
-
this.cleanup();
|
|
283
|
-
if (value?.length<=0) return;
|
|
284
|
-
const portal = this.parentElement;
|
|
285
|
-
if (!portal) return;
|
|
286
|
-
|
|
339
|
+
private createFragmentAndNodes(items: any[], helperSet: any, startIndex: number = 0): { fragment: DocumentFragment; newNodesGroup: Node[][] } {
|
|
287
340
|
const win = this.ownerDocument?.defaultView || window;
|
|
288
|
-
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
289
341
|
const fragment = win.document.createDocumentFragment();
|
|
342
|
+
const newNodesGroup: Node[][] = [];
|
|
290
343
|
|
|
291
|
-
|
|
344
|
+
items.forEach((item, i) => {
|
|
345
|
+
const index = startIndex + i;
|
|
292
346
|
let htmlString = this.innerHTML;
|
|
293
347
|
const groupArgs = { ...helperSet, $item: item, $index: index, $value: this._value };
|
|
294
348
|
|
|
295
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
349
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
296
350
|
|
|
297
351
|
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
298
352
|
temp.innerHTML = htmlString;
|
|
299
353
|
|
|
300
354
|
const content = temp.content;
|
|
301
355
|
const nodes = Array.from(content.childNodes);
|
|
302
|
-
|
|
356
|
+
|
|
357
|
+
const setTemplateHost = (element: HTMLElement) => {
|
|
358
|
+
(element as any).__swc_template_host = this;
|
|
359
|
+
Array.from(element.children).forEach((child: any) => {
|
|
360
|
+
if (child instanceof HTMLElement) {
|
|
361
|
+
setTemplateHost(child);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
nodes.forEach((node: any) => {
|
|
367
|
+
if (node instanceof HTMLElement) {
|
|
368
|
+
setTemplateHost(node as HTMLElement);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
newNodesGroup.push(nodes);
|
|
303
372
|
fragment.appendChild(content);
|
|
304
373
|
});
|
|
305
374
|
|
|
375
|
+
return { fragment, newNodesGroup };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
appendItem(...items: any[]) {
|
|
379
|
+
if (!items || items.length <= 0) return;
|
|
380
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
381
|
+
if (!portal) return;
|
|
382
|
+
|
|
383
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
384
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
385
|
+
|
|
386
|
+
const startIndex = this._value ? this._value.length : 0;
|
|
387
|
+
|
|
388
|
+
// 내부 상태(value) 업데이트 (기존 배열에 새 아이템 추가)
|
|
389
|
+
if (this._value !== items) {
|
|
390
|
+
this._value = [...(this._value || []), ...items];
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(items, helperSet, startIndex);
|
|
394
|
+
this._nodeGroups.push(...newNodesGroup);
|
|
395
|
+
|
|
396
|
+
console.log('뭐야 씨발');
|
|
397
|
+
// append 위치 계산: 기존에 그려진 마지막 노드 뒤에 삽입, 없으면 템플릿 바로 뒤에 삽입
|
|
398
|
+
let insertReference: Node | null = this.nextSibling;
|
|
399
|
+
if (this._nodeGroups.length > items.length) {
|
|
400
|
+
const lastExistingGroup = this._nodeGroups[this._nodeGroups.length - items.length - 1];
|
|
401
|
+
if (lastExistingGroup && lastExistingGroup.length > 0) {
|
|
402
|
+
const lastNode = lastExistingGroup[lastExistingGroup.length - 1];
|
|
403
|
+
insertReference = lastNode.nextSibling;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
portal.insertBefore(fragment, insertReference);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async prependItem(...items: any[]) {
|
|
411
|
+
if (!items || items.length <= 0) return;
|
|
412
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
413
|
+
if (!portal) return;
|
|
414
|
+
|
|
415
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
416
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
417
|
+
|
|
418
|
+
// 내부 상태(value) 업데이트 (기존 배열의 앞쪽에 새 아이템 추가)
|
|
419
|
+
if (this._value !== items) {
|
|
420
|
+
this._value = [...items, ...(this._value || [])];
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(items, helperSet, 0);
|
|
424
|
+
|
|
425
|
+
// 기존의 nodeGroups 배열 맨 앞에 새로운 그룹들을 추가
|
|
426
|
+
this._nodeGroups = [...newNodesGroup, ...this._nodeGroups];
|
|
427
|
+
|
|
428
|
+
// prepend 위치: 이 템플릿(SwcLoop) 노드의 바로 다음 위치 (가장 위)
|
|
306
429
|
portal.insertBefore(fragment, this.nextSibling);
|
|
307
430
|
}
|
|
308
431
|
|
|
432
|
+
refresh(value?: any) {
|
|
433
|
+
// 1. 그릴 대상 확정
|
|
434
|
+
const targetValue = value !== undefined ? value : (getAttributeValue(this, 'value') ?? this._value ?? []);
|
|
435
|
+
|
|
436
|
+
// 2. 화면 정리
|
|
437
|
+
this.cleanup();
|
|
438
|
+
|
|
439
|
+
// 3. 상태 완전 교체 (이어붙이지 않음!)
|
|
440
|
+
this._value = targetValue;
|
|
441
|
+
|
|
442
|
+
if (!this._value || this._value.length <= 0) return;
|
|
443
|
+
|
|
444
|
+
// 4. 화면 다시 그리기 (appendItem을 쓰지 않고 바로 그리기)
|
|
445
|
+
const win = this.ownerDocument?.defaultView || window;
|
|
446
|
+
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
447
|
+
helperSet.$templateHost = this;
|
|
448
|
+
const { fragment, newNodesGroup } = this.createFragmentAndNodes(this._value, helperSet, 0);
|
|
449
|
+
|
|
450
|
+
this._nodeGroups = newNodesGroup;
|
|
451
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
452
|
+
if (portal) {
|
|
453
|
+
// console.log('append????!~~~~~!?',fragment)
|
|
454
|
+
portal.insertBefore(fragment, this.nextSibling);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
309
458
|
private cleanup() {
|
|
459
|
+
console.log('누가 cleanup');
|
|
310
460
|
this._nodeGroups.forEach(nodes => nodes.forEach(n => n.parentElement?.removeChild(n)));
|
|
311
461
|
this._nodeGroups = [];
|
|
312
462
|
}
|
|
@@ -318,13 +468,12 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
318
468
|
|
|
319
469
|
@elementDefine('swc-choose', { extends: 'template', window: w })
|
|
320
470
|
class SwcChoose extends HTMLTemplateElement {
|
|
321
|
-
// @attributeHost('value')
|
|
322
|
-
// fetchValue: any;
|
|
323
|
-
|
|
324
471
|
_value: any;
|
|
325
472
|
|
|
326
|
-
@attributeHost('replace-wrap')
|
|
327
|
-
|
|
473
|
+
@attributeHost('replace-wrap-start')
|
|
474
|
+
_replaceWrapStart: string | null;
|
|
475
|
+
@attributeHost('replace-wrap-end')
|
|
476
|
+
_replaceWrapEnd: string | null;
|
|
328
477
|
|
|
329
478
|
private _nodes: Node[] = [];
|
|
330
479
|
private _previousTemplate: HTMLTemplateElement | null = null;
|
|
@@ -354,24 +503,32 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
354
503
|
|
|
355
504
|
@changedAttributeHost('value')
|
|
356
505
|
private setValue(value: any, o: string, n: string) {
|
|
357
|
-
|
|
506
|
+
console.log('chooooooose value', value)
|
|
358
507
|
this._value = value;
|
|
359
508
|
this.refresh(this._value);
|
|
360
509
|
}
|
|
361
510
|
|
|
362
|
-
@changedAttributeHost('replace-wrap')
|
|
363
|
-
private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
364
|
-
|
|
365
|
-
}
|
|
511
|
+
// @changedAttributeHost('replace-wrap')
|
|
512
|
+
// private setReplaceWrap(replaceWrapAttr?: string | null) {
|
|
513
|
+
// this.refresh();
|
|
514
|
+
// }
|
|
366
515
|
|
|
367
|
-
private replaceExpressions(html: string, groupArgs: any, context: any, wrap
|
|
368
|
-
|
|
516
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
517
|
+
let config: any = undefined;
|
|
518
|
+
if (wrap) {
|
|
519
|
+
config = {
|
|
520
|
+
expression: {
|
|
521
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
522
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
523
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
}
|
|
369
527
|
const ae = new ActionExpression(html, config);
|
|
370
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
371
528
|
const win = this.ownerDocument?.defaultView || window;
|
|
372
529
|
|
|
373
530
|
// @ts-ignore
|
|
374
|
-
for (const expr of ae.getExpressions(
|
|
531
|
+
for (const expr of ae.getExpressions('replace')) {
|
|
375
532
|
try {
|
|
376
533
|
const value = FunctionUtils.executeReturn({
|
|
377
534
|
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
@@ -388,37 +545,48 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
388
545
|
|
|
389
546
|
refresh(value?: any) {
|
|
390
547
|
value = getAttributeValue(this, 'value') ?? this._value;
|
|
391
|
-
|
|
392
|
-
const portal = this
|
|
393
|
-
if (!portal)
|
|
548
|
+
console.log('[DEBUG] SwcChoose.refresh called, value:', value);
|
|
549
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
550
|
+
if (!portal) {
|
|
551
|
+
console.log('[DEBUG] SwcChoose portal is null!');
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
394
554
|
|
|
395
555
|
const win = (getElementConfig(this).window ?? this.ownerDocument?.defaultView) || window;
|
|
396
556
|
const helperSet = SwcUtils.getHelperAndHostSet(win, this);
|
|
397
|
-
const groupArgs = { ...helperSet, $value: value };
|
|
557
|
+
const groupArgs = { ...helperSet, $value: value, $templateHost: this };
|
|
398
558
|
|
|
399
559
|
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
400
560
|
let selected: HTMLTemplateElement | null = null;
|
|
401
561
|
|
|
402
562
|
for (const t of templates) {
|
|
403
563
|
if (t.getAttribute('is') === 'swc-when') {
|
|
404
|
-
const attrVal = t.getAttribute('
|
|
564
|
+
const attrVal = t.getAttribute('test') || '';
|
|
405
565
|
let matches = false;
|
|
406
566
|
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
const result = FunctionUtils.executeReturn({
|
|
570
|
+
script: attrVal,
|
|
571
|
+
context: t,
|
|
572
|
+
args: groupArgs
|
|
573
|
+
});
|
|
574
|
+
matches = !!result;
|
|
407
575
|
// Use ActionExpression to parse and extract script from value attribute
|
|
408
|
-
const ae = new ActionExpression(attrVal);
|
|
409
|
-
const expr = ae.getFirstExpression('replace');
|
|
410
|
-
|
|
411
|
-
if (expr) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
} else {
|
|
420
|
-
|
|
421
|
-
}
|
|
576
|
+
// const ae = new ActionExpression(attrVal);
|
|
577
|
+
// const expr = ae.getFirstExpression('replace');
|
|
578
|
+
|
|
579
|
+
// if (expr) {
|
|
580
|
+
// const decodedScript = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
581
|
+
// const result = FunctionUtils.executeReturn({
|
|
582
|
+
// script: decodedScript,
|
|
583
|
+
// context: t,
|
|
584
|
+
// args: groupArgs
|
|
585
|
+
// });
|
|
586
|
+
// matches = !!result;
|
|
587
|
+
// } else {
|
|
588
|
+
// matches = String(attrVal) === String(value);
|
|
589
|
+
// }
|
|
422
590
|
|
|
423
591
|
if (matches) {
|
|
424
592
|
selected = t;
|
|
@@ -443,14 +611,33 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
443
611
|
|
|
444
612
|
if (target) {
|
|
445
613
|
let htmlString = target.innerHTML;
|
|
446
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
614
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
447
615
|
|
|
448
616
|
const result = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
449
617
|
result.innerHTML = htmlString;
|
|
450
618
|
const processedFragment = result.content;
|
|
451
619
|
|
|
620
|
+
// console.log('[DEBUG] SwcChoose processedFragment children:', processedFragment._childNodesInternal?.length);
|
|
452
621
|
this._nodes = Array.from(processedFragment.childNodes);
|
|
622
|
+
|
|
623
|
+
const setTemplateHost = (element: HTMLElement) => {
|
|
624
|
+
(element as any).__swc_template_host = this;
|
|
625
|
+
Array.from(element.children).forEach((child: any) => {
|
|
626
|
+
if (child instanceof HTMLElement) {
|
|
627
|
+
setTemplateHost(child);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
this._nodes.forEach((node: any) => {
|
|
633
|
+
if (node instanceof HTMLElement) {
|
|
634
|
+
setTemplateHost(node as HTMLElement);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
console.log(`[DEBUG] SwcChoose before insertBefore, portal: ${portal?.tagName}, isConnected: ${(portal as any)?.isConnected}`);
|
|
453
639
|
portal.insertBefore(processedFragment, this.nextSibling);
|
|
640
|
+
console.log('[DEBUG] SwcChoose after insertBefore');
|
|
454
641
|
}
|
|
455
642
|
}
|
|
456
643
|
|
|
@@ -468,11 +655,10 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
468
655
|
class SwcAsync extends HTMLTemplateElement {
|
|
469
656
|
@attributeHost('value')
|
|
470
657
|
_value: any;
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
resultValue?: any;
|
|
658
|
+
@attributeHost('replace-wrap-start')
|
|
659
|
+
_replaceWrapStart: string | null;
|
|
660
|
+
@attributeHost('replace-wrap-end')
|
|
661
|
+
_replaceWrapEnd: string | null; resultValue?: any;
|
|
476
662
|
|
|
477
663
|
get value(): boolean {
|
|
478
664
|
return this._value;
|
|
@@ -489,10 +675,10 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
489
675
|
this.executeAsync(this._value);
|
|
490
676
|
}
|
|
491
677
|
|
|
492
|
-
@changedAttributeHost('replace-wrap')
|
|
493
|
-
private setReplaceWrap() {
|
|
494
|
-
|
|
495
|
-
}
|
|
678
|
+
// @changedAttributeHost('replace-wrap')
|
|
679
|
+
// private setReplaceWrap() {
|
|
680
|
+
// this.executeAsync(this._value);
|
|
681
|
+
// }
|
|
496
682
|
|
|
497
683
|
private executeAsync(result: any = this._value) {
|
|
498
684
|
if (result === undefined || result === null) {
|
|
@@ -518,14 +704,22 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
518
704
|
}
|
|
519
705
|
}
|
|
520
706
|
|
|
521
|
-
private replaceExpressions(html: string, groupArgs: any, context: any, wrap
|
|
522
|
-
|
|
707
|
+
private replaceExpressions(html: string, groupArgs: any, context: any, wrap: {start: string, end: string}): string {
|
|
708
|
+
let config: any = undefined;
|
|
709
|
+
if (wrap) {
|
|
710
|
+
config = {
|
|
711
|
+
expression: {
|
|
712
|
+
replace: { start: `${wrap.start}`, end: `${wrap.end}` },
|
|
713
|
+
callReturn: { start: `${wrap.start}=`, end: `${wrap.end}` },
|
|
714
|
+
call: { start: `${wrap.start}@`, end: `${wrap.end}` }
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
523
718
|
const ae = new ActionExpression(html, config);
|
|
524
|
-
const filterOptions = wrap ? { type: 'replace' as const, wrap } : 'replace';
|
|
525
719
|
const win = this.ownerDocument?.defaultView || window;
|
|
526
720
|
|
|
527
721
|
// @ts-ignore
|
|
528
|
-
for (const expr of ae.getExpressions(
|
|
722
|
+
for (const expr of ae.getExpressions('replace')) {
|
|
529
723
|
try {
|
|
530
724
|
const value = FunctionUtils.executeReturn({
|
|
531
725
|
script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
|
|
@@ -541,9 +735,9 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
541
735
|
}
|
|
542
736
|
|
|
543
737
|
refresh(state: string = 'default') {
|
|
544
|
-
console.log('rrrrrrrrrrrrrrrrr', state);
|
|
738
|
+
// console.log('rrrrrrrrrrrrrrrrr', state);
|
|
545
739
|
this.cleanup();
|
|
546
|
-
const portal = this
|
|
740
|
+
const portal = SwcUtils.getParentContainer(this);
|
|
547
741
|
if (!portal) return;
|
|
548
742
|
|
|
549
743
|
const win = this.ownerDocument?.defaultView || window;
|
|
@@ -552,15 +746,19 @@ export const registerAllElements = (w: any): Record<string, Constructor<HTMLElem
|
|
|
552
746
|
const t = this.content.querySelector(`template[is="swc-${state}"]`) as HTMLTemplateElement;
|
|
553
747
|
if (t) {
|
|
554
748
|
let htmlString = t.innerHTML;
|
|
555
|
-
const groupArgs = { ...helperSet, $value: this._value, $state: state };
|
|
749
|
+
const groupArgs = { ...helperSet, $value: this._value, $state: state, $templateHost: this };
|
|
556
750
|
|
|
557
|
-
htmlString = this.replaceExpressions(htmlString, groupArgs, this, this.
|
|
751
|
+
htmlString = this.replaceExpressions(htmlString, groupArgs, this, {start:this._replaceWrapStart ?? '{#{', end: this._replaceWrapEnd ?? '}#}'});
|
|
558
752
|
|
|
559
753
|
const temp = this.ownerDocument?.createElement('template') || document.createElement('template');
|
|
560
754
|
temp.innerHTML = htmlString;
|
|
561
755
|
const content = temp.content;
|
|
562
756
|
|
|
563
757
|
this._nodes = Array.from(content.childNodes);
|
|
758
|
+
this._nodes.forEach((node: any) => {
|
|
759
|
+
if (node instanceof HTMLElement) (node as any).__template_swc_host = this;
|
|
760
|
+
});
|
|
761
|
+
|
|
564
762
|
portal.insertBefore(content, this.nextSibling);
|
|
565
763
|
}
|
|
566
764
|
}
|
package/src/types.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type HostSet = {
|
|
|
35
35
|
$hosts: HTMLElement[]; // [root, ..., parent, self]
|
|
36
36
|
$firstHost: HTMLElement | null; // Top-most SWC ancestor
|
|
37
37
|
$lastHost: HTMLElement | null; // Same as $parentHost (for backward compatibility or clarity)
|
|
38
|
+
$templateHost: HTMLTemplateElement | null | undefined;
|
|
38
39
|
$appHost: SwcAppInterface | null;
|
|
39
40
|
$appHosts: SwcAppInterface[];
|
|
40
41
|
$firstAppHost: SwcAppInterface | null;
|
package/src/utils/Utils.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SwcAppInterface, HostSet, HelperSet, HelperHostSet } from '../types';
|
|
2
2
|
import {getElementConfig} from "../decorators";
|
|
3
3
|
import { getExpression, ExpressionResult, GetExpressionConfig, GetExpressionResult } from '@dooboostore/core';
|
|
4
|
+
import {Router} from "@dooboostore/core-web";
|
|
4
5
|
|
|
5
6
|
export const SWC_NOT_FOUND = Symbol.for('simple-web-component:not-found');
|
|
6
7
|
|
|
@@ -151,14 +152,30 @@ export const htmlArticleElement = (options?: { doc?: Document; attrs?: Record<st
|
|
|
151
152
|
export namespace SwcUtils {
|
|
152
153
|
|
|
153
154
|
|
|
155
|
+
export const getParentContainer = (e: Node) => {
|
|
156
|
+
return e.parentElement ?? e.getRootNode() as any;
|
|
157
|
+
}
|
|
158
|
+
|
|
154
159
|
export const parsePathPatternsSetAttributeString = (pathPattern: string[], path: string) => {
|
|
155
160
|
return JSON.stringify(SwcUtils.parsePathPatternsSet(pathPattern, path)).replace(/"/g, "'");
|
|
156
161
|
}
|
|
157
162
|
|
|
158
|
-
export const parsePathPatternsSet = (pathPattern: string[],
|
|
163
|
+
export const parsePathPatternsSet = (pathPattern: string[], urlAndRouter?: string | Router) => {
|
|
164
|
+
// if (!path) {
|
|
165
|
+
// return;
|
|
166
|
+
// }
|
|
167
|
+
urlAndRouter ??= '/'
|
|
168
|
+
const p = typeof urlAndRouter === 'string' ? urlAndRouter : urlAndRouter.value.url;
|
|
169
|
+
const searchParams = new URLSearchParams();
|
|
170
|
+
const qs = p.split('?')[1];
|
|
171
|
+
qs?.split('&').forEach(it => {
|
|
172
|
+
const [k, v] = it.split('=');
|
|
173
|
+
searchParams.set(k,v);
|
|
174
|
+
})
|
|
159
175
|
return {
|
|
160
|
-
path:
|
|
161
|
-
|
|
176
|
+
path: p,
|
|
177
|
+
searchParams,
|
|
178
|
+
pathData: SwcUtils.parsePathPatterns(pathPattern, p)
|
|
162
179
|
};
|
|
163
180
|
};
|
|
164
181
|
export const parsePathPatterns = (pathPattern: string[], path: string) => {
|
|
@@ -209,8 +226,8 @@ export namespace SwcUtils {
|
|
|
209
226
|
* Checks __swc_host property first, then climbs the DOM tree.
|
|
210
227
|
*/
|
|
211
228
|
export const findNearestSwcHost = (el: HTMLElement | Node): HTMLElement | undefined => {
|
|
212
|
-
|
|
213
|
-
|
|
229
|
+
const el1 = el as any;
|
|
230
|
+
if (el1.__swc_host) return el1.__swc_host;
|
|
214
231
|
|
|
215
232
|
let current: any = el.parentElement || (el.getRootNode?.() as any)?.host;
|
|
216
233
|
const doc = el.ownerDocument;
|
|
@@ -348,6 +365,7 @@ export namespace SwcUtils {
|
|
|
348
365
|
$hosts,
|
|
349
366
|
$firstHost,
|
|
350
367
|
$lastHost: $parentHost,
|
|
368
|
+
$templateHost: (el as any).__swc_template_host,
|
|
351
369
|
$appHost,
|
|
352
370
|
$appHosts,
|
|
353
371
|
$firstAppHost,
|
package/tsconfig.json
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
"declaration": true,
|
|
7
7
|
"declarationMap": true,
|
|
8
8
|
"stripInternal": true,
|
|
9
|
-
"target": "
|
|
9
|
+
"target": "es2022",
|
|
10
10
|
"noEmit": true,
|
|
11
|
-
"lib": ["dom", "dom.iterable", "esnext"],
|
|
11
|
+
"lib": ["dom", "dom.iterable", "es2024", "esnext"],
|
|
12
12
|
"experimentalDecorators": true,
|
|
13
13
|
"emitDecoratorMetadata": true,
|
|
14
14
|
"esModuleInterop": true,
|