@dooboostore/simple-web-component 1.0.16 → 1.0.18
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 +109 -48
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/appendChild.js +48 -0
- package/dist/cjs/decorators/appendChild.js.map +7 -0
- package/dist/cjs/decorators/elementDefine.js +216 -67
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/index.js +2 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/{innerHtml.js → onConnectedInnerHtml.js} +8 -8
- package/dist/cjs/decorators/onConnectedInnerHtml.js.map +7 -0
- package/dist/cjs/decorators/query.js +38 -0
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/queryAll.js +32 -0
- package/dist/cjs/decorators/queryAll.js.map +2 -2
- package/dist/cjs/decorators/replaceChildren.js +53 -0
- package/dist/cjs/decorators/replaceChildren.js.map +7 -0
- package/dist/cjs/elements/SwcAppEngine.js +2 -1
- package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
- package/dist/cjs/elements/SwcAsync.js +188 -0
- package/dist/cjs/elements/SwcAsync.js.map +7 -0
- package/dist/cjs/elements/SwcChoose.js +155 -0
- package/dist/cjs/elements/SwcChoose.js.map +7 -0
- package/dist/cjs/elements/SwcIf.js +167 -0
- package/dist/cjs/elements/SwcIf.js.map +7 -0
- package/dist/cjs/elements/SwcLoop.js +246 -0
- package/dist/cjs/elements/SwcLoop.js.map +7 -0
- package/dist/cjs/elements/SwcSubTemplates.js +65 -0
- package/dist/cjs/elements/SwcSubTemplates.js.map +7 -0
- package/dist/cjs/elements/index.js +7 -0
- package/dist/cjs/elements/index.js.map +2 -2
- package/dist/cjs/index.js +12 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/types.js.map +1 -1
- package/dist/cjs/utils/Utils.js +74 -37
- package/dist/cjs/utils/Utils.js.map +3 -3
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/appendChild.js +29 -0
- package/dist/esm/decorators/appendChild.js.map +7 -0
- package/dist/esm/decorators/elementDefine.js +216 -67
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/decorators/index.js +2 -1
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/{innerHtml.js → onConnectedInnerHtml.js} +5 -5
- package/dist/esm/decorators/onConnectedInnerHtml.js.map +7 -0
- package/dist/esm/decorators/query.js +38 -0
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/queryAll.js +32 -0
- package/dist/esm/decorators/queryAll.js.map +2 -2
- package/dist/esm/decorators/replaceChildren.js +34 -0
- package/dist/esm/decorators/replaceChildren.js.map +7 -0
- package/dist/esm/elements/SwcAppEngine.js +2 -1
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAsync.js +169 -0
- package/dist/esm/elements/SwcAsync.js.map +7 -0
- package/dist/esm/elements/SwcChoose.js +136 -0
- package/dist/esm/elements/SwcChoose.js.map +7 -0
- package/dist/esm/elements/SwcIf.js +148 -0
- package/dist/esm/elements/SwcIf.js.map +7 -0
- package/dist/esm/elements/SwcLoop.js +227 -0
- package/dist/esm/elements/SwcLoop.js.map +7 -0
- package/dist/esm/elements/SwcSubTemplates.js +46 -0
- package/dist/esm/elements/SwcSubTemplates.js.map +7 -0
- package/dist/esm/elements/index.js +7 -0
- package/dist/esm/elements/index.js.map +2 -2
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/Utils.js +74 -37
- package/dist/esm/utils/Utils.js.map +3 -3
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +1226 -149
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +1 -0
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/appendChild.d.ts +17 -0
- package/dist/types/decorators/appendChild.d.ts.map +1 -0
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +2 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/onConnectedInnerHtml.d.ts +15 -0
- package/dist/types/decorators/onConnectedInnerHtml.d.ts.map +1 -0
- package/dist/types/decorators/query.d.ts +0 -2
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +0 -2
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/types/decorators/replaceChildren.d.ts +9 -0
- package/dist/types/decorators/replaceChildren.d.ts.map +1 -0
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAsync.d.ts +16 -0
- package/dist/types/elements/SwcAsync.d.ts.map +1 -0
- package/dist/types/elements/SwcChoose.d.ts +13 -0
- package/dist/types/elements/SwcChoose.d.ts.map +1 -0
- package/dist/types/elements/SwcIf.d.ts +15 -0
- package/dist/types/elements/SwcIf.d.ts.map +1 -0
- package/dist/types/elements/SwcLoop.d.ts +20 -0
- package/dist/types/elements/SwcLoop.d.ts.map +1 -0
- package/dist/types/elements/SwcSubTemplates.d.ts +13 -0
- package/dist/types/elements/SwcSubTemplates.d.ts.map +1 -0
- package/dist/types/elements/index.d.ts +7 -0
- package/dist/types/elements/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +8 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/Utils.d.ts +16 -10
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +1226 -149
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +10 -3
- package/src/decorators/addEventListener.ts +1 -0
- package/src/decorators/appendChild.ts +42 -0
- package/src/decorators/elementDefine.ts +225 -71
- package/src/decorators/index.ts +2 -1
- package/src/decorators/{innerHtml.ts → onConnectedInnerHtml.ts} +7 -6
- package/src/decorators/query.ts +32 -2
- package/src/decorators/queryAll.ts +32 -2
- package/src/decorators/replaceChildren.ts +35 -0
- package/src/elements/SwcAppEngine.ts +2 -1
- package/src/elements/SwcAsync.ts +163 -0
- package/src/elements/SwcChoose.ts +127 -0
- package/src/elements/SwcIf.ts +134 -0
- package/src/elements/SwcLoop.ts +215 -0
- package/src/elements/SwcSubTemplates.ts +19 -0
- package/src/elements/index.ts +8 -3
- package/src/index.ts +5 -2
- package/src/types.ts +9 -1
- package/src/utils/Utils.ts +86 -36
- package/dist/cjs/decorators/innerHtml.js.map +0 -7
- package/dist/esm/decorators/innerHtml.js.map +0 -7
- package/dist/types/decorators/innerHtml.d.ts +0 -12
- package/dist/types/decorators/innerHtml.d.ts.map +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
|
|
2
|
+
import { getElementConfig } from './elementDefine';
|
|
3
|
+
import { SwcUtils } from '../utils/Utils';
|
|
2
4
|
|
|
3
5
|
export interface QueryAllOptions {
|
|
4
6
|
root?: 'light' | 'shadow' | 'all' | 'auto';
|
|
@@ -14,8 +16,6 @@ export const QUERY_ALL_METADATA_KEY = Symbol('simple-web-component:query-all');
|
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* @queryAll decorator to inject a list of elements into a class property.
|
|
17
|
-
* Usage: @queryAll('.items') list!: NodeListOf<HTMLElement>;
|
|
18
|
-
* Usage: @queryAll('li', { root: 'shadow' }) list!: HTMLElement[];
|
|
19
19
|
*/
|
|
20
20
|
export function queryAll(selector: string, options: QueryAllOptions = {}): PropertyDecorator {
|
|
21
21
|
return (target: Object, propertyKey: string | symbol, descriptor?: never): void => {
|
|
@@ -33,7 +33,21 @@ export function queryAll(selector: string, options: QueryAllOptions = {}): Prope
|
|
|
33
33
|
|
|
34
34
|
Object.defineProperty(target, propertyKey, {
|
|
35
35
|
get(this: HTMLElement) {
|
|
36
|
+
// --- Special Selectors: HostSet ---
|
|
37
|
+
const hostSet = SwcUtils.getHostSet(this);
|
|
38
|
+
if (selector === ':hosts') return hostSet.$hosts;
|
|
39
|
+
if (selector === ':appHosts') return hostSet.$appHosts;
|
|
40
|
+
|
|
41
|
+
// --- Special Selectors: Env ---
|
|
42
|
+
const config = getElementConfig(this);
|
|
43
|
+
const win = config?.window || window;
|
|
44
|
+
const doc = win.document;
|
|
45
|
+
|
|
46
|
+
if (selector === ':window') return [win];
|
|
47
|
+
if (selector === ':document') return [doc];
|
|
36
48
|
if (!selector || selector === ':host') return [this];
|
|
49
|
+
|
|
50
|
+
// --- Standard Selectors ---
|
|
37
51
|
const r = options.root || 'auto';
|
|
38
52
|
|
|
39
53
|
if (r === 'shadow') {
|
|
@@ -51,6 +65,22 @@ export function queryAll(selector: string, options: QueryAllOptions = {}): Prope
|
|
|
51
65
|
const root = this.shadowRoot || this;
|
|
52
66
|
return root.querySelectorAll(selector);
|
|
53
67
|
},
|
|
68
|
+
set(this: HTMLElement, nv: any) {
|
|
69
|
+
if (nv === null || nv === undefined || (Array.isArray(nv) && nv.length === 0)) {
|
|
70
|
+
const r = options.root || 'auto';
|
|
71
|
+
let targets: (Element | Node)[] = [];
|
|
72
|
+
if (r === 'shadow') targets = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
|
|
73
|
+
else if (r === 'light') targets = Array.from(this.querySelectorAll(selector));
|
|
74
|
+
else if (r === 'all') {
|
|
75
|
+
const sNodes = this.shadowRoot ? Array.from(this.shadowRoot.querySelectorAll(selector)) : [];
|
|
76
|
+
const lNodes = Array.from(this.querySelectorAll(selector));
|
|
77
|
+
targets = [...sNodes, ...lNodes];
|
|
78
|
+
} else {
|
|
79
|
+
targets = Array.from((this.shadowRoot || this).querySelectorAll(selector));
|
|
80
|
+
}
|
|
81
|
+
targets.forEach(t => (t as Element).remove());
|
|
82
|
+
}
|
|
83
|
+
},
|
|
54
84
|
enumerable: true,
|
|
55
85
|
configurable: true
|
|
56
86
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
|
|
2
|
+
|
|
3
|
+
export const REPLACE_CHILDREN_METADATA_KEY = Symbol('simple-web-component:replace-children');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @replaceChildren decorator to surgically replace children of a target element.
|
|
7
|
+
* Usage: @replaceChildren('#container') renderPart() { return '<div>New Content</div>'; }
|
|
8
|
+
*/
|
|
9
|
+
export function replaceChildren(selector: string): MethodDecorator {
|
|
10
|
+
return (target: Object, propertyKey: string | symbol) => {
|
|
11
|
+
const constructor = target.constructor;
|
|
12
|
+
let meta = ReflectUtils.getOwnMetadata(REPLACE_CHILDREN_METADATA_KEY, constructor) as Map<string | symbol, string>;
|
|
13
|
+
if (!meta) {
|
|
14
|
+
meta = new Map<string | symbol, string>();
|
|
15
|
+
ReflectUtils.defineMetadata(REPLACE_CHILDREN_METADATA_KEY, meta, constructor);
|
|
16
|
+
}
|
|
17
|
+
meta.set(propertyKey, selector);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const getReplaceChildrenMetadata = (target: any): Map<string | symbol, string> | undefined => {
|
|
22
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
23
|
+
return ReflectUtils.getMetadata(REPLACE_CHILDREN_METADATA_KEY, constructor);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const findAllReplaceChildrenMetadata = (target: any): Map<string | symbol, string> => {
|
|
27
|
+
const result = new Map<string | symbol, string>();
|
|
28
|
+
const maps = ReflectUtils.findAllMetadata<Map<string | symbol, string>>(REPLACE_CHILDREN_METADATA_KEY, target);
|
|
29
|
+
maps.forEach(map => {
|
|
30
|
+
if (map instanceof Map) {
|
|
31
|
+
map.forEach((v, k) => result.set(k, v));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
@@ -6,6 +6,7 @@ import { SimOption } from '@dooboostore/simple-boot/SimOption';
|
|
|
6
6
|
import { Router, RouterEventType } from '@dooboostore/core-web/routers/Router';
|
|
7
7
|
import { Subscription } from '@dooboostore/core/message/Subscription';
|
|
8
8
|
import { ConstructorType, Optional } from '@dooboostore/core/types';
|
|
9
|
+
import { FunctionUtils } from '@dooboostore/core/function/FunctionUtils';
|
|
9
10
|
|
|
10
11
|
export type SwcConfigType = {
|
|
11
12
|
rootRouter: ConstructorType<any>;
|
|
@@ -35,7 +36,7 @@ export class SwcAppEngine {
|
|
|
35
36
|
if (!configStr) return;
|
|
36
37
|
|
|
37
38
|
try {
|
|
38
|
-
const userConfig: SwcAttributeConfigType =
|
|
39
|
+
const userConfig: SwcAttributeConfigType = FunctionUtils.executeReturn({ script: configStr, context: this.host });
|
|
39
40
|
if (userConfig && userConfig.rootRouter) {
|
|
40
41
|
const _config: SwcConfigType = {
|
|
41
42
|
routeType: 'element',
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { elementDefine } from '../decorators/elementDefine';
|
|
2
|
+
import { changedAttribute } from '../decorators/changedAttribute';
|
|
3
|
+
import { SwcUtils } from '../utils/Utils';
|
|
4
|
+
import { FunctionUtils } from '@dooboostore/core/function/FunctionUtils';
|
|
5
|
+
import { SwcLoading, SwcError, SwcSuccess, SwcDefault } from './SwcSubTemplates';
|
|
6
|
+
|
|
7
|
+
@elementDefine({ name: 'swc-async', extends: 'template' })
|
|
8
|
+
export class SwcAsync extends HTMLTemplateElement {
|
|
9
|
+
private _nodes: Node[] = [];
|
|
10
|
+
private _currentPromise: Promise<any> | null = null;
|
|
11
|
+
private _value: any = null;
|
|
12
|
+
|
|
13
|
+
get value(): any {
|
|
14
|
+
return this._value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set value(nv: any) {
|
|
18
|
+
if (nv instanceof Promise) {
|
|
19
|
+
this.handlePromise(nv);
|
|
20
|
+
} else {
|
|
21
|
+
this._value = nv;
|
|
22
|
+
this.render(nv === null ? 'default' : 'success', nv);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@changedAttribute('on-get-value')
|
|
27
|
+
private refresh(newValue?: string | null) {
|
|
28
|
+
const script = newValue !== undefined ? newValue : this.getAttribute('on-get-value');
|
|
29
|
+
if (!script) {
|
|
30
|
+
this.value = null; // Triggers default render
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!this.parentElement) return;
|
|
34
|
+
|
|
35
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
36
|
+
try {
|
|
37
|
+
const result = FunctionUtils.executeReturn({
|
|
38
|
+
script,
|
|
39
|
+
context: this,
|
|
40
|
+
args: helperHostSet
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (result instanceof Promise) {
|
|
44
|
+
this.handlePromise(result);
|
|
45
|
+
} else {
|
|
46
|
+
this.value = result;
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
this.render('error', e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async handlePromise(promise: Promise<any>) {
|
|
54
|
+
this._currentPromise = promise;
|
|
55
|
+
this.render('loading');
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const result = await promise;
|
|
59
|
+
if (this._currentPromise !== promise) return;
|
|
60
|
+
this._value = result;
|
|
61
|
+
this.render('success', result);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
if (this._currentPromise !== promise) return;
|
|
64
|
+
this.render('error', e);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private render(state: 'loading' | 'error' | 'success' | 'default', data?: any) {
|
|
69
|
+
this.cleanup();
|
|
70
|
+
if (!this.parentElement) return;
|
|
71
|
+
|
|
72
|
+
let fragment: DocumentFragment;
|
|
73
|
+
const ctx: any = {
|
|
74
|
+
$nodes: [],
|
|
75
|
+
$elements: [],
|
|
76
|
+
$state: state,
|
|
77
|
+
$value: null,
|
|
78
|
+
$error: null
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (state === 'default') {
|
|
82
|
+
const t = this.content.querySelector('template[is="swc-default"]') as HTMLTemplateElement;
|
|
83
|
+
fragment = t ? (t.content.cloneNode(true) as DocumentFragment) : document.createDocumentFragment();
|
|
84
|
+
} else if (state === 'loading') {
|
|
85
|
+
const t = this.content.querySelector('template[is="swc-loading"]') as HTMLTemplateElement;
|
|
86
|
+
fragment = t ? (t.content.cloneNode(true) as DocumentFragment) : document.createDocumentFragment();
|
|
87
|
+
} else if (state === 'error') {
|
|
88
|
+
const t = this.content.querySelector('template[is="swc-error"]') as HTMLTemplateElement;
|
|
89
|
+
ctx.$error = data;
|
|
90
|
+
fragment = t ? (t.content.cloneNode(true) as DocumentFragment) : document.createDocumentFragment();
|
|
91
|
+
} else {
|
|
92
|
+
// Success
|
|
93
|
+
const t = this.content.querySelector('template[is="swc-success"]') as HTMLTemplateElement;
|
|
94
|
+
ctx.$value = data;
|
|
95
|
+
if (t) {
|
|
96
|
+
fragment = t.content.cloneNode(true) as DocumentFragment;
|
|
97
|
+
} else {
|
|
98
|
+
const clone = this.content.cloneNode(true) as DocumentFragment;
|
|
99
|
+
Array.from(clone.querySelectorAll('template[is="swc-loading"], template[is="swc-error"], template[is="swc-success"], template[is="swc-default"]')).forEach(tmp => tmp.remove());
|
|
100
|
+
fragment = clone;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.mount(fragment, ctx);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private mount(fragment: DocumentFragment, ctx: any) {
|
|
108
|
+
const nodes = Array.from(fragment.childNodes);
|
|
109
|
+
const elements = nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
110
|
+
|
|
111
|
+
Object.assign(ctx, {
|
|
112
|
+
$nodes: nodes,
|
|
113
|
+
$elements: elements,
|
|
114
|
+
$firstNode: nodes[0],
|
|
115
|
+
$lastNode: nodes[nodes.length - 1],
|
|
116
|
+
$firstElement: elements[0],
|
|
117
|
+
$lastElement: elements[elements.length - 1]
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Execution Callbacks
|
|
121
|
+
this._executeCallback('on-clone-nodes', ctx);
|
|
122
|
+
nodes.forEach((node, nodeIndex) => {
|
|
123
|
+
if (node instanceof HTMLElement) {
|
|
124
|
+
(node as any).__swc_host = this;
|
|
125
|
+
}
|
|
126
|
+
this._executeCallback('on-clone-node', {
|
|
127
|
+
...ctx,
|
|
128
|
+
$node: node,
|
|
129
|
+
$nodeIndex: nodeIndex,
|
|
130
|
+
$isElement: node.nodeType === 1
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
this._nodes = nodes;
|
|
135
|
+
this.parentElement?.insertBefore(fragment, this.nextSibling);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private _executeCallback(attrName: string, extraArgs: Record<string, any>) {
|
|
139
|
+
const script = this.getAttribute(attrName);
|
|
140
|
+
if (!script) return;
|
|
141
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
142
|
+
try {
|
|
143
|
+
FunctionUtils.execute({ script, context: this, args: { ...helperHostSet, ...extraArgs } });
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.error(`[SwcAsync] Error in ${attrName}:`, e);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private cleanup() {
|
|
150
|
+
this._nodes.forEach(n => {
|
|
151
|
+
if (n.parentElement) n.parentElement.removeChild(n);
|
|
152
|
+
});
|
|
153
|
+
this._nodes = [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
connectedCallback() {
|
|
157
|
+
this.refresh();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
disconnectedCallback() {
|
|
161
|
+
this.cleanup();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { elementDefine } from '../decorators/elementDefine';
|
|
2
|
+
import { changedAttribute } from '../decorators/changedAttribute';
|
|
3
|
+
import { SwcUtils } from '../utils/Utils';
|
|
4
|
+
import { FunctionUtils } from '@dooboostore/core/function/FunctionUtils';
|
|
5
|
+
import { SwcWhen, SwcOtherwise } from './SwcSubTemplates';
|
|
6
|
+
|
|
7
|
+
@elementDefine({ name: 'swc-choose', extends: 'template' })
|
|
8
|
+
export class SwcChoose extends HTMLTemplateElement {
|
|
9
|
+
private _nodes: Node[] = [];
|
|
10
|
+
private _value: any = null;
|
|
11
|
+
|
|
12
|
+
get value(): any {
|
|
13
|
+
return this._value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
set value(nv: any) {
|
|
17
|
+
this._value = nv;
|
|
18
|
+
this.render();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private _executeCallback(attrName: string, extraArgs: Record<string, any>) {
|
|
22
|
+
const script = this.getAttribute(attrName);
|
|
23
|
+
if (!script) return;
|
|
24
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
25
|
+
try {
|
|
26
|
+
FunctionUtils.execute({ script, context: this, args: { ...helperHostSet, ...extraArgs } });
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error(`[SwcChoose] Error in ${attrName}:`, e);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@changedAttribute('on-get-value')
|
|
33
|
+
private refresh(newValue?: string | null) {
|
|
34
|
+
const script = newValue !== undefined ? newValue : this.getAttribute('on-get-value');
|
|
35
|
+
if (!script) {
|
|
36
|
+
this.value = null;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (!this.parentElement) return;
|
|
40
|
+
|
|
41
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
42
|
+
try {
|
|
43
|
+
const result = FunctionUtils.executeReturn({
|
|
44
|
+
script,
|
|
45
|
+
context: this,
|
|
46
|
+
args: helperHostSet
|
|
47
|
+
});
|
|
48
|
+
this.value = result;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.error('[SwcChoose] Error in on-get-value:', e);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private render() {
|
|
55
|
+
this.cleanup();
|
|
56
|
+
if (!this.parentElement) return;
|
|
57
|
+
|
|
58
|
+
const templates = Array.from(this.content.querySelectorAll('template'));
|
|
59
|
+
let selected: HTMLTemplateElement | null = null;
|
|
60
|
+
let otherwise: HTMLTemplateElement | null = null;
|
|
61
|
+
let defaultTmp: HTMLTemplateElement | null = null;
|
|
62
|
+
|
|
63
|
+
for (const t of templates) {
|
|
64
|
+
const is = t.getAttribute('is');
|
|
65
|
+
if (is === 'swc-when') {
|
|
66
|
+
const whenVal = t.getAttribute('value');
|
|
67
|
+
if (String(whenVal) === String(this._value)) {
|
|
68
|
+
selected = t;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
} else if (is === 'swc-otherwise') {
|
|
72
|
+
otherwise = t;
|
|
73
|
+
} else if (is === 'swc-default') {
|
|
74
|
+
defaultTmp = t;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const targetTemplate = (this._value == null ? defaultTmp : selected) || otherwise || defaultTmp;
|
|
79
|
+
if (targetTemplate) {
|
|
80
|
+
const clone = targetTemplate.content.cloneNode(true) as DocumentFragment;
|
|
81
|
+
const nodes = Array.from(clone.childNodes);
|
|
82
|
+
const elements = nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
83
|
+
|
|
84
|
+
const ctx = {
|
|
85
|
+
$value: this._value,
|
|
86
|
+
$nodes: nodes,
|
|
87
|
+
$elements: elements,
|
|
88
|
+
$firstNode: nodes[0],
|
|
89
|
+
$lastNode: nodes[nodes.length - 1],
|
|
90
|
+
$firstElement: elements[0],
|
|
91
|
+
$lastElement: elements[elements.length - 1]
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Execution Callbacks
|
|
95
|
+
this._executeCallback('on-clone-nodes', ctx);
|
|
96
|
+
nodes.forEach((node, nodeIndex) => {
|
|
97
|
+
if (node instanceof HTMLElement) {
|
|
98
|
+
(node as any).__swc_host = this;
|
|
99
|
+
}
|
|
100
|
+
this._executeCallback('on-clone-node', {
|
|
101
|
+
...ctx,
|
|
102
|
+
$node: node,
|
|
103
|
+
$nodeIndex: nodeIndex,
|
|
104
|
+
$isElement: node.nodeType === 1
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
this._nodes = nodes;
|
|
109
|
+
this.parentElement.insertBefore(clone, this.nextSibling);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private cleanup() {
|
|
114
|
+
this._nodes.forEach(n => {
|
|
115
|
+
if (n.parentElement) n.parentElement.removeChild(n);
|
|
116
|
+
});
|
|
117
|
+
this._nodes = [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
connectedCallback() {
|
|
121
|
+
this.refresh();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
disconnectedCallback() {
|
|
125
|
+
this.cleanup();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { elementDefine } from '../decorators/elementDefine';
|
|
2
|
+
import { changedAttribute } from '../decorators/changedAttribute';
|
|
3
|
+
import { SwcUtils } from '../utils/Utils';
|
|
4
|
+
import { FunctionUtils } from '@dooboostore/core/function/FunctionUtils';
|
|
5
|
+
|
|
6
|
+
@elementDefine({ name: 'swc-if', extends: 'template' })
|
|
7
|
+
export class SwcIf extends HTMLTemplateElement {
|
|
8
|
+
private _nodes: Node[] = [];
|
|
9
|
+
private _value: any = null;
|
|
10
|
+
|
|
11
|
+
get value(): any {
|
|
12
|
+
return this._value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
set value(nv: any) {
|
|
16
|
+
this._value = nv;
|
|
17
|
+
this.render();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private _getTarget(): Element | DocumentFragment | null {
|
|
21
|
+
const script = this.getAttribute('on-get-portal');
|
|
22
|
+
if (!script) return null;
|
|
23
|
+
try {
|
|
24
|
+
const res = FunctionUtils.executeReturn({
|
|
25
|
+
script,
|
|
26
|
+
context: this,
|
|
27
|
+
args: SwcUtils.getHelperAndHostSet(window, this)
|
|
28
|
+
});
|
|
29
|
+
if (typeof res === 'string') return document.querySelector(res);
|
|
30
|
+
if (res instanceof Node) return res as any;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error('[SwcIf] Portal target error:', e);
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private _executeCallback(attrName: string, extraArgs: Record<string, any>) {
|
|
38
|
+
const script = this.getAttribute(attrName);
|
|
39
|
+
if (!script) return;
|
|
40
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
41
|
+
try {
|
|
42
|
+
FunctionUtils.execute({ script, context: this, args: { ...helperHostSet, ...extraArgs } });
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error(`[SwcIf] Error in ${attrName}:`, e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@changedAttribute('on-get-value')
|
|
49
|
+
private refresh(newValue?: string | null) {
|
|
50
|
+
const script = newValue !== undefined ? newValue : this.getAttribute('on-get-value');
|
|
51
|
+
if (!script) {
|
|
52
|
+
this.value = null;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!this.parentElement) return;
|
|
56
|
+
|
|
57
|
+
const helperHostSet = SwcUtils.getHelperAndHostSet(window, this);
|
|
58
|
+
try {
|
|
59
|
+
const result = FunctionUtils.executeReturn({
|
|
60
|
+
script,
|
|
61
|
+
context: this,
|
|
62
|
+
args: helperHostSet
|
|
63
|
+
});
|
|
64
|
+
this.value = result;
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.error('[SwcIf] Error in on-get-value:', e);
|
|
67
|
+
this.value = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private render() {
|
|
72
|
+
this.cleanup();
|
|
73
|
+
if (!this.parentElement) return;
|
|
74
|
+
|
|
75
|
+
let fragment: DocumentFragment | null = null;
|
|
76
|
+
const ctx: any = { $value: this._value, $nodes: [], $elements: [] };
|
|
77
|
+
|
|
78
|
+
if (this._value) {
|
|
79
|
+
const clone = this.content.cloneNode(true) as DocumentFragment;
|
|
80
|
+
Array.from(clone.querySelectorAll('template[is="swc-default"]')).forEach(t => t.remove());
|
|
81
|
+
fragment = clone;
|
|
82
|
+
} else {
|
|
83
|
+
const t = this.content.querySelector('template[is="swc-default"]') as HTMLTemplateElement;
|
|
84
|
+
if (t) fragment = t.content.cloneNode(true) as DocumentFragment;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (fragment) {
|
|
88
|
+
this.mount(fragment, ctx);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private mount(fragment: DocumentFragment, ctx: any) {
|
|
93
|
+
const nodes = Array.from(fragment.childNodes);
|
|
94
|
+
const elements = nodes.filter(n => n.nodeType === 1) as HTMLElement[];
|
|
95
|
+
|
|
96
|
+
Object.assign(ctx, {
|
|
97
|
+
$nodes: nodes,
|
|
98
|
+
$elements: elements,
|
|
99
|
+
$firstNode: nodes[0],
|
|
100
|
+
$lastNode: nodes[nodes.length - 1],
|
|
101
|
+
$firstElement: elements[0],
|
|
102
|
+
$lastElement: elements[elements.length - 1]
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
this._executeCallback('on-clone-nodes', ctx);
|
|
106
|
+
nodes.forEach((node, nodeIndex) => {
|
|
107
|
+
if (node instanceof HTMLElement) (node as any).__swc_host = this;
|
|
108
|
+
this._executeCallback('on-clone-node', { ...ctx, $node: node, $nodeIndex: nodeIndex, $isElement: node.nodeType === 1 });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
this._nodes = nodes;
|
|
112
|
+
const target = this._getTarget();
|
|
113
|
+
if (target) {
|
|
114
|
+
target.appendChild(fragment);
|
|
115
|
+
} else {
|
|
116
|
+
this.parentElement?.insertBefore(fragment, this.nextSibling);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private cleanup() {
|
|
121
|
+
this._nodes.forEach(n => {
|
|
122
|
+
if (n.parentElement) n.parentElement.removeChild(n);
|
|
123
|
+
});
|
|
124
|
+
this._nodes = [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
connectedCallback() {
|
|
128
|
+
this.refresh();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
disconnectedCallback() {
|
|
132
|
+
this.cleanup();
|
|
133
|
+
}
|
|
134
|
+
}
|