glass-easel 0.1.0
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 +40 -0
- package/dist/glass_easel.all.d.ts +1 -0
- package/dist/glass_easel.all.js +2 -0
- package/dist/glass_easel.all.js.map +1 -0
- package/dist/glass_easel.domlike.global.d.ts +1 -0
- package/dist/glass_easel.domlike.global.js +2 -0
- package/dist/glass_easel.domlike.global.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/src/backend/backend_protocol.d.ts +119 -0
- package/dist/types/src/backend/backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts +90 -0
- package/dist/types/src/backend/composed_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts +76 -0
- package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/backend/mode.d.ts +46 -0
- package/dist/types/src/backend/mode.d.ts.map +1 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts +30 -0
- package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +1 -0
- package/dist/types/src/behavior.d.ts +428 -0
- package/dist/types/src/behavior.d.ts.map +1 -0
- package/dist/types/src/class_list.d.ts +79 -0
- package/dist/types/src/class_list.d.ts.map +1 -0
- package/dist/types/src/component.d.ts +291 -0
- package/dist/types/src/component.d.ts.map +1 -0
- package/dist/types/src/component_params.d.ts +239 -0
- package/dist/types/src/component_params.d.ts.map +1 -0
- package/dist/types/src/component_space.d.ts +164 -0
- package/dist/types/src/component_space.d.ts.map +1 -0
- package/dist/types/src/data_path.d.ts +5 -0
- package/dist/types/src/data_path.d.ts.map +1 -0
- package/dist/types/src/data_proxy.d.ts +107 -0
- package/dist/types/src/data_proxy.d.ts.map +1 -0
- package/dist/types/src/data_utils.d.ts +3 -0
- package/dist/types/src/data_utils.d.ts.map +1 -0
- package/dist/types/src/element.d.ts +275 -0
- package/dist/types/src/element.d.ts.map +1 -0
- package/dist/types/src/element_iterator.d.ts +43 -0
- package/dist/types/src/element_iterator.d.ts.map +1 -0
- package/dist/types/src/event.d.ts +104 -0
- package/dist/types/src/event.d.ts.map +1 -0
- package/dist/types/src/external_shadow_tree.d.ts +20 -0
- package/dist/types/src/external_shadow_tree.d.ts.map +1 -0
- package/dist/types/src/func_arr.d.ts +39 -0
- package/dist/types/src/func_arr.d.ts.map +1 -0
- package/dist/types/src/global_options.d.ts +111 -0
- package/dist/types/src/global_options.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +43 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/mutation_observer.d.ts +79 -0
- package/dist/types/src/mutation_observer.d.ts.map +1 -0
- package/dist/types/src/native_node.d.ts +8 -0
- package/dist/types/src/native_node.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +49 -0
- package/dist/types/src/node.d.ts.map +1 -0
- package/dist/types/src/relation.d.ts +47 -0
- package/dist/types/src/relation.d.ts.map +1 -0
- package/dist/types/src/render.d.ts +3 -0
- package/dist/types/src/render.d.ts.map +1 -0
- package/dist/types/src/selector.d.ts +32 -0
- package/dist/types/src/selector.d.ts.map +1 -0
- package/dist/types/src/shadow_root.d.ts +136 -0
- package/dist/types/src/shadow_root.d.ts.map +1 -0
- package/dist/types/src/template_engine.d.ts +18 -0
- package/dist/types/src/template_engine.d.ts.map +1 -0
- package/dist/types/src/text_node.d.ts +32 -0
- package/dist/types/src/text_node.d.ts.map +1 -0
- package/dist/types/src/tmpl/index.d.ts +18 -0
- package/dist/types/src/tmpl/index.d.ts.map +1 -0
- package/dist/types/src/tmpl/native_rendering.d.ts +45 -0
- package/dist/types/src/tmpl/native_rendering.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +80 -0
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +1 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +50 -0
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +1 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts +19 -0
- package/dist/types/src/tmpl/range_list_diff.d.ts.map +1 -0
- package/dist/types/src/trait_behaviors.d.ts +38 -0
- package/dist/types/src/trait_behaviors.d.ts.map +1 -0
- package/dist/types/src/virtual_node.d.ts +10 -0
- package/dist/types/src/virtual_node.d.ts.map +1 -0
- package/dist/types/tests/backend/domlike.test.d.ts +2 -0
- package/dist/types/tests/backend/domlike.test.d.ts.map +1 -0
- package/dist/types/tests/base/env.d.ts +29 -0
- package/dist/types/tests/base/env.d.ts.map +1 -0
- package/dist/types/tests/base/match.d.ts +9 -0
- package/dist/types/tests/base/match.d.ts.map +1 -0
- package/dist/types/tests/core/backend.test.d.ts +2 -0
- package/dist/types/tests/core/backend.test.d.ts.map +1 -0
- package/dist/types/tests/core/behavior.test.d.ts +2 -0
- package/dist/types/tests/core/behavior.test.d.ts.map +1 -0
- package/dist/types/tests/core/component_space.test.d.ts +2 -0
- package/dist/types/tests/core/component_space.test.d.ts.map +1 -0
- package/dist/types/tests/core/data_update.test.d.ts +2 -0
- package/dist/types/tests/core/data_update.test.d.ts.map +1 -0
- package/dist/types/tests/core/misc.test.d.ts +2 -0
- package/dist/types/tests/core/misc.test.d.ts.map +1 -0
- package/dist/types/tests/core/placeholder.test.d.ts +2 -0
- package/dist/types/tests/core/placeholder.test.d.ts.map +1 -0
- package/dist/types/tests/core/slot.test.d.ts +2 -0
- package/dist/types/tests/core/slot.test.d.ts.map +1 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts +2 -0
- package/dist/types/tests/core/trait_behaviors.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts +2 -0
- package/dist/types/tests/tmpl/binding_map.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/event.test.d.ts +2 -0
- package/dist/types/tests/tmpl/event.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/expression.test.d.ts +2 -0
- package/dist/types/tests/tmpl/expression.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts +2 -0
- package/dist/types/tests/tmpl/lvalue.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts +2 -0
- package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +1 -0
- package/dist/types/tests/tmpl/structure.test.d.ts +2 -0
- package/dist/types/tests/tmpl/structure.test.d.ts.map +1 -0
- package/dist/types/tests/types/chaining.test.d.ts +2 -0
- package/dist/types/tests/types/chaining.test.d.ts.map +1 -0
- package/dist/types/tests/types/createElement.test.d.ts +2 -0
- package/dist/types/tests/types/createElement.test.d.ts.map +1 -0
- package/dist/types/tests/types/definition.test.d.ts +2 -0
- package/dist/types/tests/types/definition.test.d.ts.map +1 -0
- package/guide/zh_CN/advanced/binding_map_update.md +32 -0
- package/guide/zh_CN/advanced/build_args.md +28 -0
- package/guide/zh_CN/advanced/component_filter.md +70 -0
- package/guide/zh_CN/advanced/component_space.md +124 -0
- package/guide/zh_CN/advanced/custom_backend.md +53 -0
- package/guide/zh_CN/advanced/error_listener.md +32 -0
- package/guide/zh_CN/advanced/external_component.md +73 -0
- package/guide/zh_CN/advanced/template_engine.md +61 -0
- package/guide/zh_CN/appendix/backend_protocol.md +501 -0
- package/guide/zh_CN/appendix/list_diff_algorithm.md +406 -0
- package/guide/zh_CN/basic/beginning.md +94 -0
- package/guide/zh_CN/basic/component.md +156 -0
- package/guide/zh_CN/basic/event.md +169 -0
- package/guide/zh_CN/basic/lifetime.md +66 -0
- package/guide/zh_CN/basic/method.md +62 -0
- package/guide/zh_CN/basic/template.md +135 -0
- package/guide/zh_CN/data_management/advanced_update.md +170 -0
- package/guide/zh_CN/data_management/data_deep_copy.md +157 -0
- package/guide/zh_CN/data_management/data_observer.md +154 -0
- package/guide/zh_CN/data_management/property_early_init.md +31 -0
- package/guide/zh_CN/data_management/pure_data_pattern.md +21 -0
- package/guide/zh_CN/index.md +93 -0
- package/guide/zh_CN/interaction/behavior.md +52 -0
- package/guide/zh_CN/interaction/component_path.md +37 -0
- package/guide/zh_CN/interaction/generic.md +73 -0
- package/guide/zh_CN/interaction/placeholder.md +40 -0
- package/guide/zh_CN/interaction/relation.md +151 -0
- package/guide/zh_CN/interaction/slot.md +137 -0
- package/guide/zh_CN/interaction/template_import.md +94 -0
- package/guide/zh_CN/interaction/trait_behavior.md +117 -0
- package/guide/zh_CN/styling/external_class.md +46 -0
- package/guide/zh_CN/styling/style_isolation.md +54 -0
- package/guide/zh_CN/styling/virtual_host.md +52 -0
- package/guide/zh_CN/tree/element_iterator.md +54 -0
- package/guide/zh_CN/tree/mutation_observer.md +52 -0
- package/guide/zh_CN/tree/node_tree.md +142 -0
- package/guide/zh_CN/tree/node_tree_modification.md +78 -0
- package/guide/zh_CN/tree/selector.md +66 -0
- package/jest.config.js +6 -0
- package/jest.dts.config.js +9 -0
- package/jest.unit.config.js +14 -0
- package/package.json +28 -0
- package/src/backend/backend_protocol.ts +313 -0
- package/src/backend/composed_backend_protocol.ts +252 -0
- package/src/backend/domlike_backend_protocol.ts +370 -0
- package/src/backend/mode.ts +51 -0
- package/src/backend/suggested_backend_protocol.ts +83 -0
- package/src/behavior.ts +1655 -0
- package/src/bootstrap_dom_dev.js +22 -0
- package/src/class_list.ts +376 -0
- package/src/component.ts +1309 -0
- package/src/component_params.ts +461 -0
- package/src/component_space.ts +547 -0
- package/src/data_path.ts +225 -0
- package/src/data_proxy.ts +670 -0
- package/src/data_utils.ts +50 -0
- package/src/element.ts +1966 -0
- package/src/element_iterator.ts +158 -0
- package/src/event.ts +401 -0
- package/src/external_shadow_tree.ts +27 -0
- package/src/func_arr.ts +198 -0
- package/src/global_options.ts +242 -0
- package/src/index.ts +187 -0
- package/src/mutation_observer.ts +252 -0
- package/src/native_node.ts +74 -0
- package/src/node.ts +174 -0
- package/src/relation.ts +380 -0
- package/src/render.ts +25 -0
- package/src/selector.ts +218 -0
- package/src/shadow_root.ts +766 -0
- package/src/template_engine.ts +45 -0
- package/src/text_node.ts +149 -0
- package/src/tmpl/index.ts +199 -0
- package/src/tmpl/native_rendering.ts +175 -0
- package/src/tmpl/proc_gen_wrapper.ts +954 -0
- package/src/tmpl/proc_gen_wrapper_dom.ts +230 -0
- package/src/tmpl/range_list_diff.ts +443 -0
- package/src/trait_behaviors.ts +51 -0
- package/src/virtual_node.ts +51 -0
- package/tests/backend/domlike.test.ts +254 -0
- package/tests/base/env.ts +78 -0
- package/tests/base/match.ts +185 -0
- package/tests/core/backend.test.ts +144 -0
- package/tests/core/behavior.test.ts +546 -0
- package/tests/core/component_space.test.ts +212 -0
- package/tests/core/data_update.test.ts +461 -0
- package/tests/core/misc.test.ts +339 -0
- package/tests/core/placeholder.test.ts +180 -0
- package/tests/core/slot.test.ts +1495 -0
- package/tests/core/trait_behaviors.test.ts +153 -0
- package/tests/legacy/README.md +3 -0
- package/tests/legacy/behavior.test.js +293 -0
- package/tests/legacy/component.test.js +1247 -0
- package/tests/legacy/data_path.test.js +149 -0
- package/tests/legacy/data_proxy.test.js +759 -0
- package/tests/legacy/element_iterator.test.js +148 -0
- package/tests/legacy/event.test.js +849 -0
- package/tests/legacy/external.test.js +510 -0
- package/tests/legacy/extra_info.test.js +109 -0
- package/tests/legacy/generics.test.js +176 -0
- package/tests/legacy/mutation_observer.test.js +210 -0
- package/tests/legacy/relation.test.js +517 -0
- package/tests/legacy/selector.test.js +263 -0
- package/tests/legacy/slot.test.js +915 -0
- package/tests/legacy/virtual.test.js +394 -0
- package/tests/tmpl/binding_map.test.ts +208 -0
- package/tests/tmpl/event.test.ts +206 -0
- package/tests/tmpl/expression.test.ts +429 -0
- package/tests/tmpl/lvalue.test.ts +160 -0
- package/tests/tmpl/native_rendering.test.ts +155 -0
- package/tests/tmpl/structure.test.ts +998 -0
- package/tests/types/chaining.test.ts +614 -0
- package/tests/types/createElement.test.ts +82 -0
- package/tests/types/definition.test.ts +442 -0
- package/tsconfig.json +11 -0
- package/webpack.config.js +270 -0
package/src/component.ts
ADDED
|
@@ -0,0 +1,1309 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
2
|
+
|
|
3
|
+
import * as backend from './backend/backend_protocol'
|
|
4
|
+
import * as composedBackend from './backend/composed_backend_protocol'
|
|
5
|
+
import * as domlikeBackend from './backend/domlike_backend_protocol'
|
|
6
|
+
import {
|
|
7
|
+
FuncArr,
|
|
8
|
+
GeneralFuncType,
|
|
9
|
+
triggerWarning,
|
|
10
|
+
} from './func_arr'
|
|
11
|
+
import {
|
|
12
|
+
Element,
|
|
13
|
+
} from './element'
|
|
14
|
+
import {
|
|
15
|
+
globalOptions,
|
|
16
|
+
normalizeComponentOptions,
|
|
17
|
+
NormalizedComponentOptions,
|
|
18
|
+
getDefaultComponentSpace,
|
|
19
|
+
getDefaultBackendContext,
|
|
20
|
+
} from './global_options'
|
|
21
|
+
import {
|
|
22
|
+
ShadowRoot,
|
|
23
|
+
} from './shadow_root'
|
|
24
|
+
import {
|
|
25
|
+
ComponentInstance,
|
|
26
|
+
ComponentParams,
|
|
27
|
+
DataList,
|
|
28
|
+
PropertyList,
|
|
29
|
+
MethodList,
|
|
30
|
+
GeneralComponentInstance,
|
|
31
|
+
DataWithPropertyValues,
|
|
32
|
+
RelationParams,
|
|
33
|
+
TraitRelationParams,
|
|
34
|
+
ComponentMethod,
|
|
35
|
+
TaggedMethod,
|
|
36
|
+
METHOD_TAG,
|
|
37
|
+
DeepReadonly,
|
|
38
|
+
GetFromDataPath,
|
|
39
|
+
SetDataSetter,
|
|
40
|
+
} from './component_params'
|
|
41
|
+
import {
|
|
42
|
+
Behavior,
|
|
43
|
+
GeneralBehavior,
|
|
44
|
+
ComponentDefinitionWithPlaceholder,
|
|
45
|
+
RelationHandler,
|
|
46
|
+
normalizeRelation,
|
|
47
|
+
BuilderContext,
|
|
48
|
+
} from './behavior'
|
|
49
|
+
import {
|
|
50
|
+
ComponentSpace,
|
|
51
|
+
} from './component_space'
|
|
52
|
+
import {
|
|
53
|
+
simpleDeepCopy,
|
|
54
|
+
} from './data_utils'
|
|
55
|
+
import {
|
|
56
|
+
DataGroup,
|
|
57
|
+
DataGroupObserverTree,
|
|
58
|
+
DataValue,
|
|
59
|
+
DeepCopyStrategy,
|
|
60
|
+
getDeepCopyStrategy,
|
|
61
|
+
} from './data_proxy'
|
|
62
|
+
import {
|
|
63
|
+
Relation,
|
|
64
|
+
generateRelationDefinitionGroup,
|
|
65
|
+
RelationDefinitionGroup,
|
|
66
|
+
} from './relation'
|
|
67
|
+
import {
|
|
68
|
+
Template,
|
|
69
|
+
TemplateEngine,
|
|
70
|
+
} from './template_engine'
|
|
71
|
+
import {
|
|
72
|
+
ClassList,
|
|
73
|
+
} from './class_list'
|
|
74
|
+
import {
|
|
75
|
+
GeneralBackendContext,
|
|
76
|
+
GeneralBackendElement,
|
|
77
|
+
} from './node'
|
|
78
|
+
import {
|
|
79
|
+
DataPath,
|
|
80
|
+
parseSinglePath,
|
|
81
|
+
parseMultiPaths,
|
|
82
|
+
} from './data_path'
|
|
83
|
+
import {
|
|
84
|
+
ExternalShadowRoot,
|
|
85
|
+
} from './external_shadow_tree'
|
|
86
|
+
import {
|
|
87
|
+
BM,
|
|
88
|
+
BackendMode,
|
|
89
|
+
} from './backend/mode'
|
|
90
|
+
import {
|
|
91
|
+
EventListener,
|
|
92
|
+
} from './event'
|
|
93
|
+
import { TraitBehavior, TraitGroup } from './trait_behaviors'
|
|
94
|
+
|
|
95
|
+
export const convertGenerics = (
|
|
96
|
+
compDef: GeneralComponentDefinition,
|
|
97
|
+
space: ComponentSpace,
|
|
98
|
+
owner?: GeneralComponent,
|
|
99
|
+
genericTargets?: { [key: string]: string | ComponentDefinitionWithPlaceholder },
|
|
100
|
+
): { [key: string]: ComponentDefinitionWithPlaceholder } | null => {
|
|
101
|
+
const hostUsing = owner?._$behavior._$using
|
|
102
|
+
const hostGenericImpls = owner?._$genericImpls
|
|
103
|
+
if (!compDef._$detail) compDef.prepare()
|
|
104
|
+
const childBeh = compDef.behavior
|
|
105
|
+
let genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | null
|
|
106
|
+
const generics = childBeh._$generics
|
|
107
|
+
if (generics) {
|
|
108
|
+
const genericDefaults = childBeh._$genericDefaults!
|
|
109
|
+
genericImpls = Object.create(null) as { [key: string]: ComponentDefinitionWithPlaceholder }
|
|
110
|
+
for (let i = 0; i < generics.length; i += 1) {
|
|
111
|
+
const key = generics[i]!
|
|
112
|
+
if (genericTargets && Object.prototype.hasOwnProperty.call(genericTargets, key)) {
|
|
113
|
+
const target = genericTargets[key]!
|
|
114
|
+
if (typeof target === 'string') {
|
|
115
|
+
if (hostUsing?.[target]) {
|
|
116
|
+
genericImpls[key] = hostUsing[target]!
|
|
117
|
+
} else if (hostGenericImpls && hostGenericImpls[target]) {
|
|
118
|
+
genericImpls[key] = hostGenericImpls[target]!
|
|
119
|
+
} else {
|
|
120
|
+
const comp = space.getComponentByUrlWithoutDefault(target, '')
|
|
121
|
+
if (comp) {
|
|
122
|
+
genericImpls[key] = {
|
|
123
|
+
final: comp,
|
|
124
|
+
placeholder: null,
|
|
125
|
+
waiting: null,
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
triggerWarning(`Generic "${key}" value "${target}" is not valid (on component "${compDef.is}").`)
|
|
129
|
+
const defaultComp = space.getDefaultComponent()
|
|
130
|
+
if (!defaultComp) {
|
|
131
|
+
throw new Error(`Cannot find default component for generic "${key}" (on component "${compDef.is}")`)
|
|
132
|
+
}
|
|
133
|
+
genericImpls[key] = {
|
|
134
|
+
final: defaultComp,
|
|
135
|
+
placeholder: null,
|
|
136
|
+
waiting: null,
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
genericImpls[key] = target
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
const defaultComp = genericDefaults[key] || space.getDefaultComponent()
|
|
145
|
+
if (!defaultComp) {
|
|
146
|
+
throw new Error(`Cannot find default component for generic "${key}" (on component "${compDef.is}")`)
|
|
147
|
+
}
|
|
148
|
+
genericImpls[key] = {
|
|
149
|
+
final: defaultComp,
|
|
150
|
+
placeholder: null,
|
|
151
|
+
waiting: null,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
genericImpls = null
|
|
157
|
+
}
|
|
158
|
+
return genericImpls
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const resolvePlaceholder = (
|
|
162
|
+
placeholder: string,
|
|
163
|
+
space: ComponentSpace,
|
|
164
|
+
behavior: GeneralBehavior,
|
|
165
|
+
genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | null,
|
|
166
|
+
): GeneralComponentDefinition => {
|
|
167
|
+
const using = behavior._$using
|
|
168
|
+
const usingTarget = using[placeholder] || (genericImpls && genericImpls[placeholder])
|
|
169
|
+
let ret: GeneralComponentDefinition | null = null
|
|
170
|
+
if (usingTarget) {
|
|
171
|
+
if (usingTarget.placeholder === null) {
|
|
172
|
+
ret = usingTarget.final
|
|
173
|
+
} else {
|
|
174
|
+
triggerWarning(`Placeholder on generic implementation is not valid (on component "${behavior.is}")`)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (ret) return ret
|
|
178
|
+
const defaultComp = space.getDefaultComponent()
|
|
179
|
+
if (!defaultComp) {
|
|
180
|
+
throw new Error(`Cannot find default component for placeholder target "${placeholder}" (on component "${behavior.is}")`)
|
|
181
|
+
}
|
|
182
|
+
return defaultComp
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type Lifetimes = {
|
|
186
|
+
created: () => void,
|
|
187
|
+
attached: () => void,
|
|
188
|
+
moved: () => void,
|
|
189
|
+
detached: () => void,
|
|
190
|
+
ready: () => void,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type LifetimeFuncs = {
|
|
194
|
+
[name in keyof Lifetimes]?: FuncArr<Lifetimes[name]>
|
|
195
|
+
} & Record<string, FuncArr<GeneralFuncType>>
|
|
196
|
+
|
|
197
|
+
export type PageLifetimeFuncs = {
|
|
198
|
+
[name: string]: FuncArr<GeneralFuncType>,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
type ComponentDefinitionDetail<
|
|
202
|
+
TData extends DataList,
|
|
203
|
+
TProperty extends PropertyList,
|
|
204
|
+
TMethod extends MethodList,
|
|
205
|
+
> = {
|
|
206
|
+
proto: ComponentInstProto<TData, TProperty, TMethod>
|
|
207
|
+
template: Template
|
|
208
|
+
dataGroupObserverTree: DataGroupObserverTree
|
|
209
|
+
dataDeepCopy: DeepCopyStrategy
|
|
210
|
+
propertyPassingDeepCopy: DeepCopyStrategy
|
|
211
|
+
relationDefinitionGroup: RelationDefinitionGroup | null
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export class ComponentDefinition<
|
|
215
|
+
TData extends DataList,
|
|
216
|
+
TProperty extends PropertyList,
|
|
217
|
+
TMethod extends MethodList,
|
|
218
|
+
> {
|
|
219
|
+
is: string
|
|
220
|
+
behavior: Behavior<TData, TProperty, TMethod, any>
|
|
221
|
+
/** @internal */
|
|
222
|
+
_$detail: ComponentDefinitionDetail<TData, TProperty, TMethod> | null
|
|
223
|
+
/** @internal */
|
|
224
|
+
_$options: NormalizedComponentOptions
|
|
225
|
+
/** @internal */
|
|
226
|
+
private _$templateEngine: TemplateEngine
|
|
227
|
+
|
|
228
|
+
/** @internal */
|
|
229
|
+
constructor(
|
|
230
|
+
behavior: Behavior<TData, TProperty, TMethod, any>,
|
|
231
|
+
) {
|
|
232
|
+
this.behavior = behavior
|
|
233
|
+
this.is = this.behavior.is
|
|
234
|
+
this._$detail = null
|
|
235
|
+
this._$options = normalizeComponentOptions(
|
|
236
|
+
behavior._$options,
|
|
237
|
+
behavior.ownerSpace.getComponentOptions(),
|
|
238
|
+
)
|
|
239
|
+
const templateEngine = this._$options.templateEngine
|
|
240
|
+
this._$templateEngine = templateEngine
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
general(): GeneralComponentDefinition {
|
|
244
|
+
return this as unknown as GeneralComponentDefinition
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Get the normalized component options */
|
|
248
|
+
getComponentOptions(): NormalizedComponentOptions {
|
|
249
|
+
return this._$options
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* List all component dependencies (recursively)
|
|
254
|
+
*
|
|
255
|
+
* This method will prepare the underlying behavior.
|
|
256
|
+
* The caller component is not included in the result.
|
|
257
|
+
*/
|
|
258
|
+
getComponentDependencies(): Set<GeneralComponentDefinition> {
|
|
259
|
+
return this.behavior.getComponentDependencies()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
isPrepared(): boolean {
|
|
263
|
+
return !!this._$detail
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
prepare() {
|
|
267
|
+
if (this._$detail) return
|
|
268
|
+
this.behavior.prepare()
|
|
269
|
+
const behavior = this.behavior
|
|
270
|
+
const options = this._$options
|
|
271
|
+
const propSetters = {} as {
|
|
272
|
+
[key: string]: {
|
|
273
|
+
enumerable: boolean,
|
|
274
|
+
get: (this: Component<TData, TProperty, TMethod>) => unknown,
|
|
275
|
+
set: (this: Component<TData, TProperty, TMethod>, v: unknown) => void,
|
|
276
|
+
} | {
|
|
277
|
+
enumerable: boolean,
|
|
278
|
+
value: (...args: unknown[]) => unknown,
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// add properties to component prototype if needed
|
|
283
|
+
if (options.writeFieldsToNode) {
|
|
284
|
+
const keys = Object.keys(behavior._$propertyMap)
|
|
285
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
286
|
+
const propName = keys[i]!
|
|
287
|
+
propSetters[propName] = {
|
|
288
|
+
enumerable: true,
|
|
289
|
+
get() {
|
|
290
|
+
return this._$dataGroup.data[propName]
|
|
291
|
+
},
|
|
292
|
+
set(v: DataValue) {
|
|
293
|
+
const dataGroup = this._$dataGroup
|
|
294
|
+
dataGroup.replaceDataOnPath([propName], v)
|
|
295
|
+
dataGroup.applyDataUpdates()
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const methodKeys = Object.keys(behavior._$methodMap)
|
|
300
|
+
for (let i = 0; i < methodKeys.length; i += 1) {
|
|
301
|
+
const methodName = methodKeys[i]!
|
|
302
|
+
propSetters[methodName] = {
|
|
303
|
+
enumerable: true,
|
|
304
|
+
value: behavior._$methodMap[methodName]!,
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// create prototype
|
|
310
|
+
const protoFunc = function ComponentInst() { /* empty */ }
|
|
311
|
+
protoFunc.prototype = Object.create(Component.prototype, propSetters) as
|
|
312
|
+
ComponentInstProto<TData, TProperty, TMethod>
|
|
313
|
+
const proto = protoFunc.prototype
|
|
314
|
+
proto._$behavior = behavior
|
|
315
|
+
proto._$definition = this
|
|
316
|
+
proto._$methodMap = behavior._$methodMap
|
|
317
|
+
|
|
318
|
+
// init other helpers
|
|
319
|
+
const dataGroupObserverTree = behavior._$generateObserverTree()
|
|
320
|
+
proto._$lifetimeFuncs = behavior._$getAllLifetimeFuncs()
|
|
321
|
+
proto._$pageLifetimeFuncs = behavior._$getAllPageLifetimeFuncs()
|
|
322
|
+
const relationDefinitionGroup = generateRelationDefinitionGroup(behavior._$relationMap)
|
|
323
|
+
const dataDeepCopy = getDeepCopyStrategy(options.dataDeepCopy)
|
|
324
|
+
const propertyPassingDeepCopy = getDeepCopyStrategy(options.propertyPassingDeepCopy)
|
|
325
|
+
|
|
326
|
+
// call template engine
|
|
327
|
+
const template = this._$templateEngine.create(behavior as unknown as GeneralBehavior, options)
|
|
328
|
+
|
|
329
|
+
this._$detail = {
|
|
330
|
+
proto,
|
|
331
|
+
template,
|
|
332
|
+
dataGroupObserverTree,
|
|
333
|
+
dataDeepCopy,
|
|
334
|
+
propertyPassingDeepCopy,
|
|
335
|
+
relationDefinitionGroup,
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let componentInstanceIdInc = 1
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* A node that has a shadow tree attached to it
|
|
344
|
+
*/
|
|
345
|
+
export class Component<
|
|
346
|
+
TData extends DataList,
|
|
347
|
+
TProperty extends PropertyList,
|
|
348
|
+
TMethod extends MethodList,
|
|
349
|
+
> extends Element {
|
|
350
|
+
/** @internal */
|
|
351
|
+
_$behavior: Behavior<TData, TProperty, TMethod, any>
|
|
352
|
+
/** @internal */
|
|
353
|
+
_$definition: ComponentDefinition<TData, TProperty, TMethod>
|
|
354
|
+
/** @internal */
|
|
355
|
+
_$lifetimeFuncs: LifetimeFuncs
|
|
356
|
+
/** @internal */
|
|
357
|
+
_$pageLifetimeFuncs: PageLifetimeFuncs
|
|
358
|
+
/** @internal */
|
|
359
|
+
_$methodMap: MethodList
|
|
360
|
+
/** @internal */
|
|
361
|
+
_$genericImpls: { [name: string]: ComponentDefinitionWithPlaceholder } | null
|
|
362
|
+
/** @internal */
|
|
363
|
+
_$dataGroup: DataGroup<TData, TProperty, TMethod>
|
|
364
|
+
/** @internal */
|
|
365
|
+
_$external: boolean
|
|
366
|
+
shadowRoot: ShadowRoot | ExternalShadowRoot
|
|
367
|
+
/** @internal */
|
|
368
|
+
_$relation: Relation | null
|
|
369
|
+
/** @internal */
|
|
370
|
+
_$idPrefix: string
|
|
371
|
+
/** @internal */
|
|
372
|
+
_$componentInstanceId: number | undefined
|
|
373
|
+
tagName: string
|
|
374
|
+
/** @internal */
|
|
375
|
+
private _$traitGroup: TraitGroup
|
|
376
|
+
/** @internal */
|
|
377
|
+
private _$methodCaller: ComponentInstance<TData, TProperty, TMethod>
|
|
378
|
+
|
|
379
|
+
constructor() {
|
|
380
|
+
throw new Error('Element cannot be constructed directly')
|
|
381
|
+
// eslint-disable-next-line no-unreachable
|
|
382
|
+
super()
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
general(): GeneralComponent {
|
|
386
|
+
return this as unknown as GeneralComponent
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Cast a general component node to the instance of the specified component
|
|
391
|
+
*
|
|
392
|
+
* Returns `null` if the component node is not the instance of the specified component.
|
|
393
|
+
*/
|
|
394
|
+
override asInstanceOf<
|
|
395
|
+
UData extends DataList,
|
|
396
|
+
UProperty extends PropertyList,
|
|
397
|
+
UMethod extends MethodList,
|
|
398
|
+
>(
|
|
399
|
+
componentDefinition: ComponentDefinition<UData, UProperty, UMethod>,
|
|
400
|
+
): ComponentInstance<UData, UProperty, UMethod> | null {
|
|
401
|
+
if (this._$behavior as any !== componentDefinition.behavior) {
|
|
402
|
+
return null
|
|
403
|
+
}
|
|
404
|
+
return this as unknown as ComponentInstance<UData, UProperty, UMethod>
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
static register<
|
|
408
|
+
TData extends DataList,
|
|
409
|
+
TProperty extends PropertyList,
|
|
410
|
+
TMethod extends MethodList,
|
|
411
|
+
>(
|
|
412
|
+
def: ComponentParams<TData, TProperty, TMethod> &
|
|
413
|
+
ThisType<ComponentInstance<TData, TProperty, TMethod>>,
|
|
414
|
+
space?: ComponentSpace,
|
|
415
|
+
): ComponentDefinition<TData, TProperty, TMethod> {
|
|
416
|
+
return (space || getDefaultComponentSpace()).defineComponent(def)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** @internal */
|
|
420
|
+
static _$tagMethod<Fn extends ComponentMethod>(func: Fn): TaggedMethod<Fn> {
|
|
421
|
+
const taggedMethod = func as unknown as TaggedMethod<Fn>
|
|
422
|
+
(taggedMethod as unknown as { [tag: symbol]: true })[METHOD_TAG] = true
|
|
423
|
+
return taggedMethod
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** @internal */
|
|
427
|
+
static _$isTaggedMethod(func: unknown): func is TaggedMethod<ComponentMethod> {
|
|
428
|
+
return typeof func === 'function' && !!(func as unknown as { [tag: symbol]: true })[METHOD_TAG]
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** @internal */
|
|
432
|
+
static _$advancedCreate<
|
|
433
|
+
TData extends DataList,
|
|
434
|
+
TProperty extends PropertyList,
|
|
435
|
+
TMethod extends MethodList,
|
|
436
|
+
>(
|
|
437
|
+
tagName: string,
|
|
438
|
+
def: ComponentDefinition<TData, TProperty, TMethod>,
|
|
439
|
+
owner: ShadowRoot | null,
|
|
440
|
+
backendContext: GeneralBackendContext | null,
|
|
441
|
+
genericImpls: { [name: string]: ComponentDefinitionWithPlaceholder } | null,
|
|
442
|
+
placeholderHandler: (() => void) | undefined,
|
|
443
|
+
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
|
|
444
|
+
): ComponentInstance<TData, TProperty, TMethod> {
|
|
445
|
+
if (!def._$detail) def.prepare()
|
|
446
|
+
const {
|
|
447
|
+
proto,
|
|
448
|
+
template,
|
|
449
|
+
dataDeepCopy,
|
|
450
|
+
propertyPassingDeepCopy,
|
|
451
|
+
relationDefinitionGroup,
|
|
452
|
+
} = def._$detail!
|
|
453
|
+
let dataGroupObserverTree = def._$detail!.dataGroupObserverTree
|
|
454
|
+
const options = def._$options
|
|
455
|
+
const behavior = def.behavior
|
|
456
|
+
const nodeTreeContext: GeneralBackendContext = owner
|
|
457
|
+
? owner._$nodeTreeContext
|
|
458
|
+
: backendContext || globalOptions.backendContext || getDefaultBackendContext()
|
|
459
|
+
const external = options.externalComponent
|
|
460
|
+
const propEarlyInit = options.propertyEarlyInit
|
|
461
|
+
const writeExtraInfoToAttr = globalOptions.writeExtraInfoToAttr
|
|
462
|
+
|
|
463
|
+
// initialize component instance object
|
|
464
|
+
const comp = Object.create(proto) as
|
|
465
|
+
ComponentInstance<TData, TProperty, TMethod>
|
|
466
|
+
comp._$genericImpls = genericImpls
|
|
467
|
+
comp._$placeholderHandler = placeholderHandler
|
|
468
|
+
comp._$external = external
|
|
469
|
+
comp.tagName = tagName
|
|
470
|
+
comp._$methodCaller = comp
|
|
471
|
+
|
|
472
|
+
// create backend element
|
|
473
|
+
let backendElement: GeneralBackendElement | null
|
|
474
|
+
if (options.virtualHost) {
|
|
475
|
+
backendElement = null
|
|
476
|
+
comp._$initialize(true, null, owner, nodeTreeContext)
|
|
477
|
+
if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
|
|
478
|
+
if (owner) {
|
|
479
|
+
const backend = owner._$backendShadowRoot
|
|
480
|
+
backendElement = backend?.createComponent(tagName, true) || null
|
|
481
|
+
} else {
|
|
482
|
+
const sr = (nodeTreeContext as backend.Context).getRootNode().getShadowRoot()
|
|
483
|
+
if (!sr) throw new Error('Failed getting backend shadow tree')
|
|
484
|
+
backendElement = sr.createComponent(tagName, false) || null
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
} else if (owner) {
|
|
488
|
+
if (BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike)) {
|
|
489
|
+
backendElement = (owner._$nodeTreeContext as domlikeBackend.Context)
|
|
490
|
+
.document.createElement(tagName)
|
|
491
|
+
} else if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
|
|
492
|
+
const backend = owner._$backendShadowRoot
|
|
493
|
+
backendElement = backend?.createComponent(tagName, false) || null
|
|
494
|
+
} else {
|
|
495
|
+
const backend = owner._$nodeTreeContext as composedBackend.Context
|
|
496
|
+
backendElement = backend.createElement(tagName)
|
|
497
|
+
}
|
|
498
|
+
comp._$initialize(false, backendElement, owner, nodeTreeContext)
|
|
499
|
+
} else {
|
|
500
|
+
if (BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike)) {
|
|
501
|
+
backendElement = (nodeTreeContext as domlikeBackend.Context)
|
|
502
|
+
.document.createElement(tagName)
|
|
503
|
+
} else if (BM.SHADOW || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Shadow)) {
|
|
504
|
+
const sr = (nodeTreeContext as backend.Context).getRootNode().getShadowRoot()
|
|
505
|
+
if (!sr) throw new Error('Failed getting backend shadow tree')
|
|
506
|
+
backendElement = sr.createComponent(tagName, false) || null
|
|
507
|
+
} else {
|
|
508
|
+
backendElement = (nodeTreeContext as composedBackend.Context).createElement(tagName) || null
|
|
509
|
+
}
|
|
510
|
+
comp._$initialize(false, backendElement, owner, nodeTreeContext)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// init class list
|
|
514
|
+
const externalClassAlias = {} as { [externalName: string]: string[] | null }
|
|
515
|
+
if (behavior._$externalClasses) {
|
|
516
|
+
const externalClasses = behavior._$externalClasses
|
|
517
|
+
for (let i = 0; i < externalClasses.length; i += 1) {
|
|
518
|
+
externalClassAlias[externalClasses[i]!] = null
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
comp.classList = new ClassList(comp, externalClassAlias)
|
|
522
|
+
if (owner && backendElement) {
|
|
523
|
+
const styleScope = owner.getHostNode()._$definition._$options.styleScope
|
|
524
|
+
if (styleScope) {
|
|
525
|
+
if (!(BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike))) {
|
|
526
|
+
(backendElement as backend.Element | composedBackend.Element).setStyleScope(styleScope)
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (writeExtraInfoToAttr) {
|
|
530
|
+
const prefix = owner.getHostNode()
|
|
531
|
+
._$behavior.ownerSpace?.styleScopeManager.queryName(styleScope)
|
|
532
|
+
if (prefix) {
|
|
533
|
+
backendElement.setAttribute('exparser:info-class-prefix', `${prefix}--`)
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// associate in backend
|
|
539
|
+
if (!(BM.DOMLIKE || (BM.DYNAMIC && nodeTreeContext.mode === BackendMode.Domlike))) {
|
|
540
|
+
if (backendElement) {
|
|
541
|
+
(backendElement as backend.Element | composedBackend.Element).associateValue(comp)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// write attr
|
|
546
|
+
if (writeExtraInfoToAttr && backendElement) {
|
|
547
|
+
const componentInstanceId = componentInstanceIdInc
|
|
548
|
+
componentInstanceIdInc += 1
|
|
549
|
+
comp._$componentInstanceId = componentInstanceId
|
|
550
|
+
backendElement.setAttribute('exparser:info-component-id', componentInstanceId)
|
|
551
|
+
}
|
|
552
|
+
comp._$idPrefix = options.idPrefixGenerator ? options.idPrefixGenerator.call(comp as unknown as GeneralComponentInstance) : ''
|
|
553
|
+
|
|
554
|
+
// combine initial data
|
|
555
|
+
const staticData = behavior._$staticData
|
|
556
|
+
const dataGenFuncs = behavior._$data
|
|
557
|
+
let data: DataList
|
|
558
|
+
if (staticData === undefined) {
|
|
559
|
+
if (dataGenFuncs.length === 1) {
|
|
560
|
+
const f = dataGenFuncs[0]!
|
|
561
|
+
data = f()
|
|
562
|
+
} else {
|
|
563
|
+
data = {}
|
|
564
|
+
for (let i = 0; i < dataGenFuncs.length; i += 1) {
|
|
565
|
+
const f = dataGenFuncs[i]!
|
|
566
|
+
Object.assign(data, f())
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
data = simpleDeepCopy(staticData)
|
|
571
|
+
for (let i = 0; i < dataGenFuncs.length; i += 1) {
|
|
572
|
+
const f = dataGenFuncs[i]!
|
|
573
|
+
Object.assign(data, f())
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// init relations
|
|
578
|
+
const relation = comp._$relation = new Relation(
|
|
579
|
+
comp as unknown as GeneralComponentInstance,
|
|
580
|
+
relationDefinitionGroup,
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
// init trait group
|
|
584
|
+
comp._$traitGroup = new TraitGroup()
|
|
585
|
+
const traitBehaviors = behavior._$traitBehaviors
|
|
586
|
+
if (traitBehaviors !== undefined) {
|
|
587
|
+
for (let i = 0; i < traitBehaviors.length; i += 1) {
|
|
588
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
589
|
+
const { traitBehavior, impl } = traitBehaviors[i]!
|
|
590
|
+
comp._$traitGroup.implement(traitBehavior, impl)
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// call method caller init
|
|
595
|
+
if (behavior._$methodCallerInit) {
|
|
596
|
+
const methodCaller = behavior._$methodCallerInit.call(comp)
|
|
597
|
+
comp._$methodCaller = methodCaller
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// call init functions
|
|
601
|
+
let initDone = false
|
|
602
|
+
function relationInit(def: RelationParams): RelationHandler<unknown, never>
|
|
603
|
+
function relationInit<TOut extends { [x: string]: unknown }>(
|
|
604
|
+
def: TraitRelationParams<TOut>,
|
|
605
|
+
): RelationHandler<unknown, TOut>
|
|
606
|
+
function relationInit<TOut extends { [x: string]: unknown }>(
|
|
607
|
+
def: RelationParams | TraitRelationParams<TOut>,
|
|
608
|
+
): RelationHandler<unknown, unknown> {
|
|
609
|
+
if (initDone) throw new Error('Cannot execute init-time functions after initialization')
|
|
610
|
+
const target = def.target
|
|
611
|
+
const normalizedRel = normalizeRelation(behavior.is, 'undefined', def)
|
|
612
|
+
let key: symbol
|
|
613
|
+
if (normalizedRel) {
|
|
614
|
+
key = relation.add(normalizedRel)
|
|
615
|
+
} else {
|
|
616
|
+
key = Symbol('invalid')
|
|
617
|
+
}
|
|
618
|
+
const list = () => {
|
|
619
|
+
const targetNodes = relation.getLinkedTargets(key)
|
|
620
|
+
return targetNodes.map((x) => x.getMethodCaller())
|
|
621
|
+
}
|
|
622
|
+
const listAsTrait = target instanceof TraitBehavior ? () => {
|
|
623
|
+
const targetNodes = relation.getLinkedTargets(key)
|
|
624
|
+
return targetNodes.map((x: GeneralComponent) => x.traitBehavior(target))
|
|
625
|
+
} : undefined
|
|
626
|
+
return { list, listAsTrait } as any
|
|
627
|
+
}
|
|
628
|
+
if (behavior._$init.length > 0) {
|
|
629
|
+
let cowObserver = true
|
|
630
|
+
let cowLifetime = true
|
|
631
|
+
let cowPageLifetime = true
|
|
632
|
+
let cowMethodMap = true
|
|
633
|
+
const methodCaller = comp.getMethodCaller()
|
|
634
|
+
const builderContext: BuilderContext<any, any, any> = {
|
|
635
|
+
self: methodCaller,
|
|
636
|
+
data,
|
|
637
|
+
setData: comp.setData.bind(comp) as (newData: { [x: string]: unknown }) => void,
|
|
638
|
+
implement: <TIn extends { [x: string]: unknown }>(
|
|
639
|
+
traitBehavior: TraitBehavior<TIn, { [x: string]: unknown }>,
|
|
640
|
+
impl: TIn,
|
|
641
|
+
): void => {
|
|
642
|
+
if (initDone) throw new Error('Cannot execute init-time functions after initialization')
|
|
643
|
+
comp._$traitGroup.implement(traitBehavior, impl)
|
|
644
|
+
},
|
|
645
|
+
relation: relationInit,
|
|
646
|
+
observer: (dataPaths: string | readonly string[], func: (...args: any[]) => void): void => {
|
|
647
|
+
if (initDone) throw new Error('Cannot execute init-time functions after initialization')
|
|
648
|
+
if (cowObserver) {
|
|
649
|
+
cowObserver = false
|
|
650
|
+
dataGroupObserverTree = dataGroupObserverTree.cloneSub()
|
|
651
|
+
}
|
|
652
|
+
dataGroupObserverTree.addObserver(func, parseMultiPaths(dataPaths as string | string[]))
|
|
653
|
+
},
|
|
654
|
+
lifetime: (name: string, func: (...args: unknown[]) => void): void => {
|
|
655
|
+
if (initDone) throw new Error('Cannot execute init-time functions after initialization')
|
|
656
|
+
if (cowLifetime) {
|
|
657
|
+
cowLifetime = false
|
|
658
|
+
comp._$lifetimeFuncs = behavior._$getAllLifetimeFuncs()
|
|
659
|
+
}
|
|
660
|
+
const fag = comp._$lifetimeFuncs
|
|
661
|
+
if (fag[name]) {
|
|
662
|
+
fag[name]!.add(func)
|
|
663
|
+
} else {
|
|
664
|
+
const fa = fag[name] = new FuncArr()
|
|
665
|
+
fa.add(func)
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
pageLifetime: (name: string, func: (...args: unknown[]) => void): void => {
|
|
669
|
+
if (initDone) throw new Error('Cannot execute init-time functions after initialization')
|
|
670
|
+
if (cowPageLifetime) {
|
|
671
|
+
cowPageLifetime = false
|
|
672
|
+
comp._$pageLifetimeFuncs = behavior._$getAllPageLifetimeFuncs()
|
|
673
|
+
}
|
|
674
|
+
const fag = comp._$pageLifetimeFuncs
|
|
675
|
+
if (fag[name]) {
|
|
676
|
+
fag[name]!.add(func)
|
|
677
|
+
} else {
|
|
678
|
+
const fa = fag[name] = new FuncArr()
|
|
679
|
+
fa.add(func)
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
method: <Fn extends ComponentMethod>(func: Fn) => Component._$tagMethod(func),
|
|
683
|
+
listener: <T>(func: EventListener<T>) => Component._$tagMethod(func),
|
|
684
|
+
}
|
|
685
|
+
const initFuncs = behavior._$init
|
|
686
|
+
for (let i = 0; i < initFuncs.length; i += 1) {
|
|
687
|
+
const init = initFuncs[i]!
|
|
688
|
+
const exported = init.call(methodCaller, builderContext) as
|
|
689
|
+
{ [x: string]: unknown } | undefined
|
|
690
|
+
if (exported) {
|
|
691
|
+
const exportedKeys = Object.keys(exported)
|
|
692
|
+
for (let j = 0; j < exportedKeys.length; j += 1) {
|
|
693
|
+
const exportedKey = exportedKeys[j]!
|
|
694
|
+
const exportItem: unknown = exported[exportedKey]
|
|
695
|
+
if (Component._$isTaggedMethod(exportItem)) {
|
|
696
|
+
if (cowMethodMap) {
|
|
697
|
+
cowMethodMap = false
|
|
698
|
+
comp._$methodMap = Object.create(comp._$methodMap) as MethodList
|
|
699
|
+
}
|
|
700
|
+
comp._$methodMap[exportedKey] = exportItem
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
initDone = true
|
|
707
|
+
|
|
708
|
+
// init data
|
|
709
|
+
const tmplInst = template.createInstance(
|
|
710
|
+
comp as unknown as GeneralComponentInstance,
|
|
711
|
+
)
|
|
712
|
+
const shadowRoot = tmplInst.shadowRoot
|
|
713
|
+
comp.shadowRoot = shadowRoot
|
|
714
|
+
const dataGroup = new DataGroup(
|
|
715
|
+
comp,
|
|
716
|
+
data as DataWithPropertyValues<TData, TProperty>,
|
|
717
|
+
options.pureDataPattern || null,
|
|
718
|
+
dataDeepCopy,
|
|
719
|
+
propertyPassingDeepCopy,
|
|
720
|
+
options.reflectToAttributes,
|
|
721
|
+
dataGroupObserverTree,
|
|
722
|
+
)
|
|
723
|
+
comp._$dataGroup = dataGroup
|
|
724
|
+
|
|
725
|
+
// init template with init data
|
|
726
|
+
if (propEarlyInit && initPropValues !== undefined) initPropValues(comp)
|
|
727
|
+
tmplInst.initValues(
|
|
728
|
+
dataGroup.innerData || dataGroup.data,
|
|
729
|
+
)
|
|
730
|
+
dataGroup.setUpdateListener(
|
|
731
|
+
tmplInst.updateValues.bind(tmplInst),
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
// bind behavior listeners
|
|
735
|
+
const listeners = behavior._$listeners
|
|
736
|
+
if (listeners !== undefined) {
|
|
737
|
+
for (let i = 0; i < listeners.length; i += 1) {
|
|
738
|
+
const { id, ev, listener: gf } = listeners[i]!
|
|
739
|
+
const listener = gf as EventListener<any>
|
|
740
|
+
if (id === 'this') {
|
|
741
|
+
comp.addListener(ev, (ev) => listener.call(comp._$methodCaller, ev))
|
|
742
|
+
} else if (!external) {
|
|
743
|
+
const sr = shadowRoot as ShadowRoot
|
|
744
|
+
const elem = id ? sr.getElementById(id) : sr
|
|
745
|
+
if (elem) {
|
|
746
|
+
elem.addListener(ev, (ev) => listener.call(comp._$methodCaller, ev))
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
const sr = shadowRoot as ExternalShadowRoot
|
|
750
|
+
const elem = id ? sr.getIdMap()[id] : sr.root
|
|
751
|
+
if (elem) {
|
|
752
|
+
sr.setListener(elem, ev, (ev) => listener.call(comp._$methodCaller, ev))
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// trigger created lifetimes
|
|
759
|
+
comp._$lifetimeFuncs.created?.call(
|
|
760
|
+
comp._$methodCaller as any,
|
|
761
|
+
[],
|
|
762
|
+
comp as unknown as GeneralComponent,
|
|
763
|
+
)
|
|
764
|
+
if (!propEarlyInit && initPropValues !== undefined) initPropValues(comp)
|
|
765
|
+
|
|
766
|
+
return comp
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
static createWithGenericsAndContext<
|
|
770
|
+
TData extends DataList,
|
|
771
|
+
TProperty extends PropertyList,
|
|
772
|
+
TMethod extends MethodList,
|
|
773
|
+
>(
|
|
774
|
+
tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
|
|
775
|
+
componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
|
|
776
|
+
genericTargets: { [name: string]: GeneralComponentDefinition } | null,
|
|
777
|
+
backendContext: GeneralBackendContext | null,
|
|
778
|
+
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
|
|
779
|
+
): ComponentInstance<TData, TProperty, TMethod> {
|
|
780
|
+
const collectGenericImpls = (def: GeneralComponentDefinition) => {
|
|
781
|
+
const space = def.behavior.ownerSpace
|
|
782
|
+
let genericImpls: { [key: string]: ComponentDefinitionWithPlaceholder } | undefined
|
|
783
|
+
if (genericTargets) {
|
|
784
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
785
|
+
genericImpls = Object.create(null)
|
|
786
|
+
Object.entries(genericTargets).forEach(([key, g]) => {
|
|
787
|
+
genericImpls![key] = {
|
|
788
|
+
final: g,
|
|
789
|
+
placeholder: null,
|
|
790
|
+
waiting: null,
|
|
791
|
+
}
|
|
792
|
+
})
|
|
793
|
+
}
|
|
794
|
+
return convertGenerics(def, space, undefined, genericImpls)
|
|
795
|
+
}
|
|
796
|
+
if (componentDefinition) {
|
|
797
|
+
return Component._$advancedCreate(
|
|
798
|
+
String(tagName),
|
|
799
|
+
componentDefinition,
|
|
800
|
+
null,
|
|
801
|
+
backendContext,
|
|
802
|
+
collectGenericImpls(componentDefinition as unknown as GeneralComponentDefinition),
|
|
803
|
+
undefined,
|
|
804
|
+
initPropValues,
|
|
805
|
+
)
|
|
806
|
+
}
|
|
807
|
+
if (tagName instanceof ComponentDefinition) {
|
|
808
|
+
return Component._$advancedCreate(
|
|
809
|
+
tagName.is,
|
|
810
|
+
tagName,
|
|
811
|
+
null,
|
|
812
|
+
backendContext,
|
|
813
|
+
collectGenericImpls(tagName as unknown as GeneralComponentDefinition),
|
|
814
|
+
undefined,
|
|
815
|
+
)
|
|
816
|
+
}
|
|
817
|
+
const compDef = getDefaultComponentSpace().getComponentByUrl(tagName, '')
|
|
818
|
+
return Component._$advancedCreate(
|
|
819
|
+
tagName,
|
|
820
|
+
compDef,
|
|
821
|
+
null,
|
|
822
|
+
backendContext,
|
|
823
|
+
collectGenericImpls(compDef),
|
|
824
|
+
undefined,
|
|
825
|
+
) as unknown as ComponentInstance<TData, TProperty, TMethod>
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
static createWithGenerics<
|
|
829
|
+
TData extends DataList,
|
|
830
|
+
TProperty extends PropertyList,
|
|
831
|
+
TMethod extends MethodList,
|
|
832
|
+
>(
|
|
833
|
+
tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
|
|
834
|
+
componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
|
|
835
|
+
genericImpls: { [name: string]: GeneralComponentDefinition } | null,
|
|
836
|
+
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
|
|
837
|
+
): ComponentInstance<TData, TProperty, TMethod> {
|
|
838
|
+
return Component.createWithGenericsAndContext(
|
|
839
|
+
tagName,
|
|
840
|
+
componentDefinition,
|
|
841
|
+
genericImpls,
|
|
842
|
+
null,
|
|
843
|
+
initPropValues,
|
|
844
|
+
)
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
static createWithContext<
|
|
848
|
+
TData extends DataList,
|
|
849
|
+
TProperty extends PropertyList,
|
|
850
|
+
TMethod extends MethodList,
|
|
851
|
+
>(
|
|
852
|
+
tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
|
|
853
|
+
componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
|
|
854
|
+
backendContext: GeneralBackendContext | null,
|
|
855
|
+
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
|
|
856
|
+
): ComponentInstance<TData, TProperty, TMethod> {
|
|
857
|
+
return Component.createWithGenericsAndContext(
|
|
858
|
+
tagName,
|
|
859
|
+
componentDefinition,
|
|
860
|
+
null,
|
|
861
|
+
backendContext,
|
|
862
|
+
initPropValues,
|
|
863
|
+
)
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
static create<
|
|
867
|
+
TData extends DataList,
|
|
868
|
+
TProperty extends PropertyList,
|
|
869
|
+
TMethod extends MethodList,
|
|
870
|
+
>(
|
|
871
|
+
tagName: string | ComponentDefinition<TData, TProperty, TMethod>,
|
|
872
|
+
componentDefinition: ComponentDefinition<TData, TProperty, TMethod> | null,
|
|
873
|
+
initPropValues?: (comp: ComponentInstance<TData, TProperty, TMethod>) => void,
|
|
874
|
+
): ComponentInstance<TData, TProperty, TMethod> {
|
|
875
|
+
return Component.createWithGenericsAndContext(
|
|
876
|
+
tagName,
|
|
877
|
+
componentDefinition,
|
|
878
|
+
null,
|
|
879
|
+
null,
|
|
880
|
+
initPropValues,
|
|
881
|
+
)
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
get is(): string {
|
|
885
|
+
return this._$definition.is
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
get properties(): DeepReadonly<DataWithPropertyValues<TData, TProperty>> {
|
|
889
|
+
return this._$dataGroup.data as any
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
get data(): DeepReadonly<DataWithPropertyValues<TData, TProperty>> {
|
|
893
|
+
return this._$dataGroup.data as any
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
set data(newData: Partial<DataWithPropertyValues<TData, TProperty>>) {
|
|
897
|
+
const dataGroup = this._$dataGroup
|
|
898
|
+
Object.entries(newData).forEach(([key, value]) => dataGroup.replaceDataOnPath([key], value))
|
|
899
|
+
dataGroup.applyDataUpdates()
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
get $(): { [id: string]: Element } | { [id: string]: GeneralBackendElement } {
|
|
903
|
+
if (this._$external) {
|
|
904
|
+
return (this.shadowRoot as ExternalShadowRoot).getIdMap()
|
|
905
|
+
}
|
|
906
|
+
return (this.shadowRoot as ShadowRoot)._$getIdMap()
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Returns the shadow root element
|
|
911
|
+
*
|
|
912
|
+
* Returns `null` for external components.
|
|
913
|
+
*/
|
|
914
|
+
getShadowRoot(): ShadowRoot | null {
|
|
915
|
+
if (this._$external) {
|
|
916
|
+
return null
|
|
917
|
+
}
|
|
918
|
+
return this.shadowRoot as ShadowRoot
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
static listProperties<
|
|
922
|
+
TData extends DataList,
|
|
923
|
+
TProperty extends PropertyList,
|
|
924
|
+
TMethod extends MethodList,
|
|
925
|
+
>(
|
|
926
|
+
comp: ComponentInstance<TData, TProperty, TMethod>,
|
|
927
|
+
): string[] {
|
|
928
|
+
return Object.keys(comp._$behavior._$propertyMap)
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
static hasProperty<
|
|
932
|
+
TData extends DataList,
|
|
933
|
+
TProperty extends PropertyList,
|
|
934
|
+
TMethod extends MethodList,
|
|
935
|
+
>(comp: Component<TData, TProperty, TMethod>, propName: string): boolean {
|
|
936
|
+
return !!comp._$behavior._$propertyMap[propName]
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/** List methods by the component definition (backward compatibility) */
|
|
940
|
+
static getMethodsFromDef<
|
|
941
|
+
TData extends DataList,
|
|
942
|
+
TProperty extends PropertyList,
|
|
943
|
+
TMethod extends MethodList,
|
|
944
|
+
>(
|
|
945
|
+
compDef: ComponentDefinition<TData, TProperty, TMethod>,
|
|
946
|
+
): { [name: string]: GeneralFuncType } {
|
|
947
|
+
return compDef.behavior._$methodMap
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/** Get a method */
|
|
951
|
+
static getMethod<
|
|
952
|
+
TData extends DataList,
|
|
953
|
+
TProperty extends PropertyList,
|
|
954
|
+
TMethod extends MethodList,
|
|
955
|
+
>(
|
|
956
|
+
comp: Component<TData, TProperty, TMethod>,
|
|
957
|
+
methodName: string,
|
|
958
|
+
): GeneralFuncType | undefined {
|
|
959
|
+
return comp._$behavior._$methodMap[methodName]
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Get the corresponding component definition
|
|
964
|
+
*/
|
|
965
|
+
getComponentDefinition(): ComponentDefinition<TData, TProperty, TMethod> {
|
|
966
|
+
return this._$definition
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Get the options of the component
|
|
971
|
+
*/
|
|
972
|
+
getComponentOptions(): NormalizedComponentOptions {
|
|
973
|
+
return this._$definition._$options
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Check whether the `other` behavior is a dependent behavior or a implemented trait behavior
|
|
978
|
+
*/
|
|
979
|
+
hasBehavior(other: string | GeneralBehavior | TraitBehavior<any, any>): boolean {
|
|
980
|
+
if (other instanceof TraitBehavior) {
|
|
981
|
+
return this._$traitGroup.get(other) !== undefined
|
|
982
|
+
}
|
|
983
|
+
return this._$behavior.hasBehavior(other)
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/** Get the root behavior of the component */
|
|
987
|
+
getRootBehavior(): Behavior<TData, TProperty, TMethod, any> {
|
|
988
|
+
return this._$behavior
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Get the trait behavior implementation of the component
|
|
993
|
+
*
|
|
994
|
+
* Returns `undefined` if the specified trait behavior is not implemented.
|
|
995
|
+
*/
|
|
996
|
+
traitBehavior<TOut extends { [x: string]: any }>(
|
|
997
|
+
traitBehavior: TraitBehavior<any, TOut>,
|
|
998
|
+
): TOut | undefined {
|
|
999
|
+
return this._$traitGroup.get(traitBehavior)
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Set the caller (a.k.a. `this` ) of event callbacks and life-time callbacks
|
|
1004
|
+
*
|
|
1005
|
+
* By default, the caller is the component instance itself.
|
|
1006
|
+
* Use this method to override this behavior.
|
|
1007
|
+
*/
|
|
1008
|
+
setMethodCaller(caller: ComponentInstance<TData, TProperty, TMethod>) {
|
|
1009
|
+
this._$methodCaller = caller
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Get the current caller set by `setMethodCaller`
|
|
1014
|
+
*/
|
|
1015
|
+
getMethodCaller(): ComponentInstance<TData, TProperty, TMethod> {
|
|
1016
|
+
return this._$methodCaller
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Triggers a life-time callback on an element
|
|
1021
|
+
*
|
|
1022
|
+
* Normally external life-times should only be triggered by template engine.
|
|
1023
|
+
* Most cases should take a common method instead.
|
|
1024
|
+
*/
|
|
1025
|
+
triggerLifetime(name: string, args: Parameters<GeneralFuncType>) {
|
|
1026
|
+
const f = this._$lifetimeFuncs[name]
|
|
1027
|
+
if (f) f.call(this._$methodCaller as any, args)
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* @internal
|
|
1032
|
+
* @deprecated Rename to `triggerLifetime`
|
|
1033
|
+
*/
|
|
1034
|
+
triggerLifeTime(name: string, args: Parameters<GeneralFuncType>) {
|
|
1035
|
+
return this.triggerLifetime(name, args)
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Triggers a page-life-time callback on an element
|
|
1040
|
+
*/
|
|
1041
|
+
triggerPageLifetime(name: string, args: Parameters<GeneralFuncType>) {
|
|
1042
|
+
const rec = (node: Element) => {
|
|
1043
|
+
if (node instanceof Component) {
|
|
1044
|
+
if (node._$pageLifetimeFuncs) {
|
|
1045
|
+
const f = node._$pageLifetimeFuncs[name]
|
|
1046
|
+
if (f) f.call(node._$methodCaller, args)
|
|
1047
|
+
}
|
|
1048
|
+
if (!node._$external) rec(node.shadowRoot as ShadowRoot)
|
|
1049
|
+
}
|
|
1050
|
+
const children = node.childNodes
|
|
1051
|
+
for (let i = 0; i < children.length; i += 1) {
|
|
1052
|
+
const child = children[i]
|
|
1053
|
+
if (child instanceof Element) {
|
|
1054
|
+
rec(child)
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
rec(this)
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* @internal
|
|
1063
|
+
* @deprecated Rename to `triggerPageLifetime`
|
|
1064
|
+
*/
|
|
1065
|
+
triggerPageLifeTime(name: string, args: Parameters<GeneralFuncType>) {
|
|
1066
|
+
return this.triggerPageLifetime(name, args)
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Get the target elements of a relation
|
|
1071
|
+
*/
|
|
1072
|
+
getRelationNodes(relationKey: string): GeneralComponent[] {
|
|
1073
|
+
return this._$relation?.getLinkedTargets(relationKey) || ([] as GeneralComponent[])
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/** Check the existence of an external class */
|
|
1077
|
+
hasExternalClass(name: string): boolean {
|
|
1078
|
+
return (this.classList as ClassList)._$hasAlias(name)
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/** Update an external class value */
|
|
1082
|
+
setExternalClass(name: string, target: string) {
|
|
1083
|
+
const cl = (this.classList as ClassList)
|
|
1084
|
+
cl._$setAlias(name, target)
|
|
1085
|
+
cl._$spreadAliasUpdate()
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/** Schedule an update for an external class value */
|
|
1089
|
+
scheduleExternalClassChange(name: string, target: string) {
|
|
1090
|
+
const cl = (this.classList as ClassList)
|
|
1091
|
+
cl._$setAlias(name, target)
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/** Update multiple external class values */
|
|
1095
|
+
applyExternalClassChanges() {
|
|
1096
|
+
(this.classList as ClassList)._$spreadAliasUpdate()
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/** Check a field is excluded by pureDataPattern or not */
|
|
1100
|
+
isInnerDataExcluded(fieldName: string): boolean {
|
|
1101
|
+
return this._$definition._$options.pureDataPattern?.test(fieldName) || false
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
static getInnerData<
|
|
1105
|
+
TData extends DataList,
|
|
1106
|
+
TProperty extends PropertyList,
|
|
1107
|
+
TMethod extends MethodList,
|
|
1108
|
+
>(
|
|
1109
|
+
comp: Component<TData, TProperty, TMethod>,
|
|
1110
|
+
): { [key: string]: DataValue } | null {
|
|
1111
|
+
return comp._$dataGroup.innerData
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
static getDataProxy<
|
|
1115
|
+
TData extends DataList,
|
|
1116
|
+
TProperty extends PropertyList,
|
|
1117
|
+
TMethod extends MethodList,
|
|
1118
|
+
>(
|
|
1119
|
+
comp: Component<TData, TProperty, TMethod>,
|
|
1120
|
+
): DataGroup<TData, TProperty, TMethod> {
|
|
1121
|
+
return comp._$dataGroup
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
static replaceWholeData<
|
|
1125
|
+
TData extends DataList,
|
|
1126
|
+
TProperty extends PropertyList,
|
|
1127
|
+
TMethod extends MethodList,
|
|
1128
|
+
>(
|
|
1129
|
+
comp: Component<TData, TProperty, TMethod>,
|
|
1130
|
+
newData: DataWithPropertyValues<TData, TProperty>,
|
|
1131
|
+
) {
|
|
1132
|
+
comp._$dataGroup.replaceWholeData(newData)
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Schedule a data update on a single specified path
|
|
1137
|
+
*
|
|
1138
|
+
* The data update will not be applied until next `setData` or `applyDataUpdates` call.
|
|
1139
|
+
* All data observers will not be triggered immediately before applied.
|
|
1140
|
+
* Reads of the data will get the unchanged value before applied.
|
|
1141
|
+
*/
|
|
1142
|
+
replaceDataOnPath<
|
|
1143
|
+
T extends DataPath,
|
|
1144
|
+
>(
|
|
1145
|
+
path: readonly [...T],
|
|
1146
|
+
data: GetFromDataPath<DataWithPropertyValues<TData, TProperty>, T>,
|
|
1147
|
+
): void;
|
|
1148
|
+
replaceDataOnPath(path: DataPath, data: unknown) {
|
|
1149
|
+
const dataProxy = this._$dataGroup
|
|
1150
|
+
if (dataProxy === undefined) {
|
|
1151
|
+
throw new Error('Cannot update data before component created')
|
|
1152
|
+
}
|
|
1153
|
+
dataProxy.replaceDataOnPath(path, data)
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Schedule an array update
|
|
1158
|
+
*
|
|
1159
|
+
* The behavior is like `Array.prototype.slice` .
|
|
1160
|
+
* Break the array before the `index`-th item, delete `del` items, and insert some items here.
|
|
1161
|
+
* If `index` is undefined, negative, or larger than the length of the array,
|
|
1162
|
+
* no items will be deleted and new items will be appended to the end of the array.
|
|
1163
|
+
* The data update will not be applied until next `setData` or `applyDataUpdates` call.
|
|
1164
|
+
* All data observers will not be triggered immediately before applied.
|
|
1165
|
+
* Reads of the data will get the unchanged value before applied.
|
|
1166
|
+
*/
|
|
1167
|
+
spliceArrayDataOnPath<
|
|
1168
|
+
T extends DataPath,
|
|
1169
|
+
>(
|
|
1170
|
+
path: readonly [...T],
|
|
1171
|
+
index: GetFromDataPath<
|
|
1172
|
+
DataWithPropertyValues<TData, TProperty>,
|
|
1173
|
+
T
|
|
1174
|
+
> extends any[] ? number | undefined : never,
|
|
1175
|
+
del: GetFromDataPath<
|
|
1176
|
+
DataWithPropertyValues<TData, TProperty>,
|
|
1177
|
+
T
|
|
1178
|
+
> extends any[] ? number | undefined : never,
|
|
1179
|
+
inserts: GetFromDataPath<
|
|
1180
|
+
DataWithPropertyValues<TData, TProperty>,
|
|
1181
|
+
T
|
|
1182
|
+
> extends (infer I)[] ? I[] : never
|
|
1183
|
+
): void;
|
|
1184
|
+
spliceArrayDataOnPath(
|
|
1185
|
+
path: DataPath,
|
|
1186
|
+
index: number | undefined,
|
|
1187
|
+
del: number | undefined,
|
|
1188
|
+
inserts: unknown[],
|
|
1189
|
+
) {
|
|
1190
|
+
const dataProxy = this._$dataGroup
|
|
1191
|
+
if (dataProxy === undefined) {
|
|
1192
|
+
throw new Error('Cannot update data before component created')
|
|
1193
|
+
}
|
|
1194
|
+
dataProxy.spliceArrayDataOnPath(path, index, del, inserts)
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Check whether there are pending changes or not
|
|
1199
|
+
*/
|
|
1200
|
+
hasPendingChanges(): boolean {
|
|
1201
|
+
const dataProxy = this._$dataGroup
|
|
1202
|
+
if (dataProxy === undefined) return false
|
|
1203
|
+
return dataProxy.getChanges().length > 0
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* Apply all scheduled updates immediately
|
|
1208
|
+
*
|
|
1209
|
+
* Inside observers, it is generally not .
|
|
1210
|
+
*/
|
|
1211
|
+
applyDataUpdates() {
|
|
1212
|
+
const dataProxy = this._$dataGroup
|
|
1213
|
+
if (dataProxy === undefined) {
|
|
1214
|
+
throw new Error('Cannot update data before component created')
|
|
1215
|
+
}
|
|
1216
|
+
dataProxy.applyDataUpdates()
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Pending all data updates in the callback, and apply updates after callback returns
|
|
1221
|
+
*
|
|
1222
|
+
* This function helps grouping several `replaceDataOnPath` or `spliceArrayDataOnPath` calls,
|
|
1223
|
+
* and then apply them at the end of the callback.
|
|
1224
|
+
* `setData` and `applyDataUpdates` calls inside the callback still apply updates immediately.
|
|
1225
|
+
*/
|
|
1226
|
+
groupUpdates<T>(callback: () => T): T {
|
|
1227
|
+
const dataProxy = this._$dataGroup
|
|
1228
|
+
if (dataProxy === undefined) {
|
|
1229
|
+
throw new Error('Cannot update data before component created')
|
|
1230
|
+
}
|
|
1231
|
+
const ret = callback()
|
|
1232
|
+
dataProxy.applyDataUpdates()
|
|
1233
|
+
return ret
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Schedule a classic data updates
|
|
1238
|
+
*
|
|
1239
|
+
* The data update will not be applied until next `setData` or `applyDataUpdates` call.
|
|
1240
|
+
* When called inside observers, the data update will be applied when observer ends.
|
|
1241
|
+
* All data observers will not be triggered immediately before applied.
|
|
1242
|
+
* Reads of the data will get the unchanged value before applied.
|
|
1243
|
+
*/
|
|
1244
|
+
updateData(newData: Partial<SetDataSetter<DataWithPropertyValues<TData, TProperty>>>): void
|
|
1245
|
+
updateData(newData: Record<string, any>): void {
|
|
1246
|
+
const dataProxy = this._$dataGroup
|
|
1247
|
+
if (dataProxy === undefined) {
|
|
1248
|
+
throw new Error('Cannot update data before component created')
|
|
1249
|
+
}
|
|
1250
|
+
const keys = Object.keys(newData)
|
|
1251
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1252
|
+
const key = keys[i]!
|
|
1253
|
+
const p = parseSinglePath(key)
|
|
1254
|
+
if (p) {
|
|
1255
|
+
dataProxy.replaceDataOnPath(p, newData[key])
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Do a classic data updates
|
|
1262
|
+
*
|
|
1263
|
+
* This method apply updates immediately, so there is no async callback.
|
|
1264
|
+
* When called inside observers, the data update will not be applied to templates.
|
|
1265
|
+
* Inside observers, it is recommended to use `updateData` instead.
|
|
1266
|
+
*/
|
|
1267
|
+
setData(newData: Partial<SetDataSetter<DataWithPropertyValues<TData, TProperty>>>): void
|
|
1268
|
+
setData(newData: Record<string, any>): void {
|
|
1269
|
+
const dataProxy = this._$dataGroup
|
|
1270
|
+
if (dataProxy === undefined) {
|
|
1271
|
+
throw new Error('Cannot update data before component created')
|
|
1272
|
+
}
|
|
1273
|
+
const keys = Object.keys(newData)
|
|
1274
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1275
|
+
const key = keys[i]!
|
|
1276
|
+
const p = parseSinglePath(key)
|
|
1277
|
+
if (p) {
|
|
1278
|
+
dataProxy.replaceDataOnPath(p, newData[key])
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
dataProxy.applyDataUpdates()
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
export type GeneralComponentDefinition = ComponentDefinition<
|
|
1286
|
+
Record<string, any>,
|
|
1287
|
+
Record<string, any>,
|
|
1288
|
+
Record<string, any>
|
|
1289
|
+
>
|
|
1290
|
+
|
|
1291
|
+
export type GeneralComponent = Component<
|
|
1292
|
+
Record<string, any>,
|
|
1293
|
+
Record<string, any>,
|
|
1294
|
+
Record<string, any>
|
|
1295
|
+
>
|
|
1296
|
+
|
|
1297
|
+
type ComponentInstProto<
|
|
1298
|
+
TData extends DataList,
|
|
1299
|
+
TProperty extends PropertyList,
|
|
1300
|
+
TMethod extends MethodList,
|
|
1301
|
+
> = Component<TData, TProperty, TMethod> & {
|
|
1302
|
+
_$behavior: Behavior<TData, TProperty, TMethod, any>
|
|
1303
|
+
_$definition: ComponentDefinition<TData, TProperty, TMethod>
|
|
1304
|
+
_$lifetimeFuncs: LifetimeFuncs
|
|
1305
|
+
_$pageLifetimeFuncs: PageLifetimeFuncs
|
|
1306
|
+
_$methodMap: MethodList
|
|
1307
|
+
} & {
|
|
1308
|
+
[key: string]: any
|
|
1309
|
+
}
|