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
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
import {
|
|
2
|
+
safeCallback,
|
|
3
|
+
triggerWarning,
|
|
4
|
+
} from './func_arr'
|
|
5
|
+
import {
|
|
6
|
+
convertValueToType,
|
|
7
|
+
PropertyDefinition,
|
|
8
|
+
} from './behavior'
|
|
9
|
+
import {
|
|
10
|
+
deepCopy,
|
|
11
|
+
simpleDeepCopy,
|
|
12
|
+
} from './data_utils'
|
|
13
|
+
import {
|
|
14
|
+
DataPath,
|
|
15
|
+
MultiPaths,
|
|
16
|
+
} from './data_path'
|
|
17
|
+
import {
|
|
18
|
+
DeepCopyKind,
|
|
19
|
+
} from './global_options'
|
|
20
|
+
import {
|
|
21
|
+
MutationObserverTarget,
|
|
22
|
+
} from './mutation_observer'
|
|
23
|
+
import {
|
|
24
|
+
GeneralComponentInstance,
|
|
25
|
+
DataList,
|
|
26
|
+
PropertyList,
|
|
27
|
+
MethodList,
|
|
28
|
+
ComponentInstance,
|
|
29
|
+
DataWithPropertyValues,
|
|
30
|
+
} from './component_params'
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
33
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty
|
|
34
|
+
|
|
35
|
+
export const enum DeepCopyStrategy {
|
|
36
|
+
None,
|
|
37
|
+
Simple,
|
|
38
|
+
SimpleWithRecursion,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type DataValue = unknown
|
|
42
|
+
|
|
43
|
+
export type DataObserver = (...values: unknown[]) => void
|
|
44
|
+
|
|
45
|
+
export type DataChange = DataReplace | DataSplice
|
|
46
|
+
// for replace
|
|
47
|
+
export type DataReplace = [DataPath, DataValue, undefined, undefined]
|
|
48
|
+
// for splice, numbers are index, removal count
|
|
49
|
+
export type DataSplice = [DataPath, DataValue[], number, number]
|
|
50
|
+
|
|
51
|
+
export type PropertyChange = {
|
|
52
|
+
propName: string,
|
|
53
|
+
prop: PropertyDefinition,
|
|
54
|
+
oldValue: unknown,
|
|
55
|
+
newValue: unknown,
|
|
56
|
+
skipModelListener: boolean,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type DataUpdateCallback = (
|
|
60
|
+
data: { [name: string]: DataValue },
|
|
61
|
+
combinedChanges: DataChange[],
|
|
62
|
+
) => void
|
|
63
|
+
|
|
64
|
+
export type ModelBindingListener = (value: DataValue) => void
|
|
65
|
+
|
|
66
|
+
type ObserverNode = {
|
|
67
|
+
listener?: number[],
|
|
68
|
+
wildcard?: number[],
|
|
69
|
+
sub: { [name: string]: ObserverNode },
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class DataGroupObserverTree {
|
|
73
|
+
propFields: { [name: string]: PropertyDefinition }
|
|
74
|
+
observerTree: ObserverNode = { sub: {} }
|
|
75
|
+
observers: DataObserverWithPath[] = []
|
|
76
|
+
|
|
77
|
+
constructor(propFields: { [name: string]: PropertyDefinition }) {
|
|
78
|
+
this.propFields = propFields
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
cloneSub(): DataGroupObserverTree {
|
|
82
|
+
const ret = new DataGroupObserverTree(this.propFields)
|
|
83
|
+
if (this.observers.length > 0) {
|
|
84
|
+
ret.observerTree = simpleDeepCopy(this.observerTree)
|
|
85
|
+
ret.observers = this.observers.slice()
|
|
86
|
+
}
|
|
87
|
+
return ret
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
addObserver(func: DataObserver, dataPath: MultiPaths) {
|
|
91
|
+
const id = this.observers.length
|
|
92
|
+
this.observers.push({
|
|
93
|
+
path: dataPath,
|
|
94
|
+
f: func,
|
|
95
|
+
})
|
|
96
|
+
for (let i = 0; i < dataPath.length; i += 1) {
|
|
97
|
+
const singlePath = dataPath[i]!
|
|
98
|
+
let cur = this.observerTree
|
|
99
|
+
let wildcard = false
|
|
100
|
+
for (let j = 0; j < singlePath.length; j += 1) {
|
|
101
|
+
const pathSlice = singlePath[j]!
|
|
102
|
+
if (pathSlice === '**') {
|
|
103
|
+
wildcard = true
|
|
104
|
+
break
|
|
105
|
+
}
|
|
106
|
+
if (!cur.sub[pathSlice]) cur.sub[pathSlice] = { sub: {} }
|
|
107
|
+
cur = cur.sub[pathSlice]!
|
|
108
|
+
}
|
|
109
|
+
if (wildcard) {
|
|
110
|
+
if (!cur.wildcard) cur.wildcard = [id]
|
|
111
|
+
else cur.wildcard.push(id)
|
|
112
|
+
} else {
|
|
113
|
+
if (!cur.listener) cur.listener = [id]
|
|
114
|
+
else cur.listener.push(id)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const callObserver = <
|
|
121
|
+
TData extends DataList,
|
|
122
|
+
TProperty extends PropertyList,
|
|
123
|
+
TMethod extends MethodList,
|
|
124
|
+
>(
|
|
125
|
+
comp: ComponentInstance<TData, TProperty, TMethod>,
|
|
126
|
+
data: { [key: string]: DataValue },
|
|
127
|
+
path: MultiPaths,
|
|
128
|
+
f: DataObserver,
|
|
129
|
+
) => {
|
|
130
|
+
const args: unknown[] = new Array(path.length)
|
|
131
|
+
for (let i = 0; i < path.length; i += 1) {
|
|
132
|
+
const singlePath = path[i]!
|
|
133
|
+
let cur: DataValue = data
|
|
134
|
+
for (let j = 0; j < singlePath.length; j += 1) {
|
|
135
|
+
const slice = singlePath[j]!
|
|
136
|
+
if (slice === '**') break
|
|
137
|
+
if (typeof cur === 'object' && cur !== null) {
|
|
138
|
+
cur = (cur as { [name: string]: DataValue })[slice]
|
|
139
|
+
} else {
|
|
140
|
+
cur = undefined
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
args[i] = cur
|
|
145
|
+
}
|
|
146
|
+
safeCallback(
|
|
147
|
+
'Data Observer',
|
|
148
|
+
f,
|
|
149
|
+
comp.getMethodCaller() as any,
|
|
150
|
+
args,
|
|
151
|
+
comp as unknown as GeneralComponentInstance || undefined,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const dfsMarkTriggerBitOnPath = (
|
|
156
|
+
node: ObserverNode,
|
|
157
|
+
observerStatus: boolean[],
|
|
158
|
+
) => {
|
|
159
|
+
if (node.listener) {
|
|
160
|
+
for (let i = 0; i < node.listener.length; i += 1) {
|
|
161
|
+
const observerId = node.listener[i]!
|
|
162
|
+
observerStatus[observerId] = true
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (node.wildcard) {
|
|
166
|
+
for (let i = 0; i < node.wildcard.length; i += 1) {
|
|
167
|
+
const observerId = node.wildcard[i]!
|
|
168
|
+
observerStatus[observerId] = true
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const keys = Object.keys(node.sub)
|
|
172
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
173
|
+
const k = keys[i]!
|
|
174
|
+
dfsMarkTriggerBitOnPath(node.sub[k]!, observerStatus)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const markTriggerBitOnPath = (
|
|
179
|
+
root: ObserverNode,
|
|
180
|
+
observerStatus: boolean[],
|
|
181
|
+
singlePath: DataPath,
|
|
182
|
+
) => {
|
|
183
|
+
let cur: ObserverNode = root
|
|
184
|
+
let found = true
|
|
185
|
+
for (let i = 0; i < singlePath.length; i += 1) {
|
|
186
|
+
const slice = singlePath[i]!
|
|
187
|
+
if (cur.wildcard) {
|
|
188
|
+
const arr = cur.wildcard
|
|
189
|
+
for (let i = 0; i < arr.length; i += 1) {
|
|
190
|
+
const observerId = arr[i]!
|
|
191
|
+
observerStatus[observerId] = true
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!hasOwnProperty.call(cur.sub, slice)) {
|
|
195
|
+
found = false
|
|
196
|
+
break
|
|
197
|
+
}
|
|
198
|
+
cur = cur.sub[slice]!
|
|
199
|
+
}
|
|
200
|
+
if (found) dfsMarkTriggerBitOnPath(cur, observerStatus)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
type DataObserverWithPath = { path: MultiPaths, f: DataObserver }
|
|
204
|
+
|
|
205
|
+
const triggerAndCleanTriggerBit = <
|
|
206
|
+
TData extends DataList,
|
|
207
|
+
TProperty extends PropertyList,
|
|
208
|
+
TMethod extends MethodList,
|
|
209
|
+
>(
|
|
210
|
+
observers: DataObserverWithPath[],
|
|
211
|
+
observerStatus: boolean[],
|
|
212
|
+
comp: ComponentInstance<TData, TProperty, TMethod> | null,
|
|
213
|
+
data: { [key: string]: DataValue },
|
|
214
|
+
) => {
|
|
215
|
+
for (let i = 0; i < observers.length; i += 1) {
|
|
216
|
+
const { path, f } = observers[i]!
|
|
217
|
+
const status = observerStatus[i]
|
|
218
|
+
if (status) {
|
|
219
|
+
observerStatus[i] = false
|
|
220
|
+
if (comp) callObserver(comp, data, path, f)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const getDeepCopyStrategy = (level: DeepCopyKind) => {
|
|
226
|
+
if (level === DeepCopyKind.Simple) return DeepCopyStrategy.Simple
|
|
227
|
+
if (level === DeepCopyKind.SimpleWithRecursion) return DeepCopyStrategy.SimpleWithRecursion
|
|
228
|
+
return DeepCopyStrategy.None
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** A data wrapper for data operations such as `setData` */
|
|
232
|
+
export class DataGroup<
|
|
233
|
+
TData extends DataList,
|
|
234
|
+
TProperty extends PropertyList,
|
|
235
|
+
TMethod extends MethodList,
|
|
236
|
+
> {
|
|
237
|
+
data: DataWithPropertyValues<TData, TProperty>
|
|
238
|
+
innerData: { [key: string]: DataValue } | null
|
|
239
|
+
private _$comp: ComponentInstance<TData, TProperty, TMethod> | null
|
|
240
|
+
private _$pureDataPattern: RegExp | null
|
|
241
|
+
private _$dataDeepCopy: DeepCopyStrategy
|
|
242
|
+
private _$propertyPassingDeepCopy: DeepCopyStrategy
|
|
243
|
+
private _$reflectToAttributes: boolean
|
|
244
|
+
private _$propFields: { [name: string]: PropertyDefinition }
|
|
245
|
+
private _$observerTree: ObserverNode
|
|
246
|
+
private _$observers: DataObserverWithPath[]
|
|
247
|
+
private _$observerStatus: boolean[]
|
|
248
|
+
private _$modelBindingListener: { [name: string]: ModelBindingListener } | null = null
|
|
249
|
+
private _$updateListener?: DataUpdateCallback
|
|
250
|
+
private _$pendingChanges: DataChange[] = []
|
|
251
|
+
private _$doingUpdates: {
|
|
252
|
+
prop: PropertyChange[],
|
|
253
|
+
combined: DataChange[],
|
|
254
|
+
count: number,
|
|
255
|
+
} | null = null
|
|
256
|
+
|
|
257
|
+
private _$generateInnerData(data: { [key: string]: DataValue }) {
|
|
258
|
+
const pureDataPattern = this._$pureDataPattern
|
|
259
|
+
const dataDeepCopy = this._$dataDeepCopy
|
|
260
|
+
if (pureDataPattern || dataDeepCopy !== DeepCopyStrategy.None) {
|
|
261
|
+
const innerData = {} as { [key: string]: DataValue }
|
|
262
|
+
const keys = Object.keys(data)
|
|
263
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
264
|
+
const k = keys[i]!
|
|
265
|
+
const v = data[k]!
|
|
266
|
+
if (pureDataPattern && pureDataPattern.test(k)) continue
|
|
267
|
+
if (dataDeepCopy === DeepCopyStrategy.None) {
|
|
268
|
+
innerData[k] = v
|
|
269
|
+
} else if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
270
|
+
innerData[k] = deepCopy(v, true)
|
|
271
|
+
} else {
|
|
272
|
+
innerData[k] = simpleDeepCopy(v)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return innerData
|
|
276
|
+
}
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
constructor(
|
|
281
|
+
associatedComponent: ComponentInstance<TData, TProperty, TMethod>
|
|
282
|
+
| null,
|
|
283
|
+
data: DataWithPropertyValues<TData, TProperty>,
|
|
284
|
+
pureDataPattern: RegExp | null,
|
|
285
|
+
dataDeepCopy: DeepCopyStrategy,
|
|
286
|
+
propertyPassingDeepCopy: DeepCopyStrategy,
|
|
287
|
+
reflectToAttributes: boolean,
|
|
288
|
+
observerTree: DataGroupObserverTree,
|
|
289
|
+
) {
|
|
290
|
+
this._$comp = associatedComponent
|
|
291
|
+
this.data = data
|
|
292
|
+
this._$pureDataPattern = pureDataPattern
|
|
293
|
+
this._$dataDeepCopy = dataDeepCopy
|
|
294
|
+
this._$propertyPassingDeepCopy = propertyPassingDeepCopy
|
|
295
|
+
this._$reflectToAttributes = reflectToAttributes && !!associatedComponent
|
|
296
|
+
this._$propFields = observerTree.propFields
|
|
297
|
+
this._$observerTree = observerTree.observerTree
|
|
298
|
+
this._$observers = observerTree.observers
|
|
299
|
+
this._$observerStatus = new Array(observerTree.observers.length) as boolean[]
|
|
300
|
+
this.innerData = this._$generateInnerData(data)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Create a simple data group */
|
|
304
|
+
static create(data: { [key: string]: DataValue }) {
|
|
305
|
+
return new DataGroup(
|
|
306
|
+
null,
|
|
307
|
+
data as any,
|
|
308
|
+
null,
|
|
309
|
+
DeepCopyStrategy.None,
|
|
310
|
+
DeepCopyStrategy.None,
|
|
311
|
+
false,
|
|
312
|
+
new DataGroupObserverTree({}),
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Set a callback for every grouped update */
|
|
317
|
+
setUpdateListener(updateListener: DataUpdateCallback) {
|
|
318
|
+
this._$updateListener = updateListener
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Replace the underlying data */
|
|
322
|
+
replaceWholeData(data: DataWithPropertyValues<TData, TProperty>) {
|
|
323
|
+
this.data = data
|
|
324
|
+
this.innerData = this._$generateInnerData(data)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Add a new common data change to queue */
|
|
328
|
+
replaceDataOnPath(path: DataPath, newData: DataValue) {
|
|
329
|
+
this._$pendingChanges.push([path, newData, undefined, undefined])
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Add a new array splice operation to queue */
|
|
333
|
+
spliceArrayDataOnPath(
|
|
334
|
+
path: DataPath,
|
|
335
|
+
index: number | undefined,
|
|
336
|
+
del: number | undefined,
|
|
337
|
+
inserts: DataValue[],
|
|
338
|
+
) {
|
|
339
|
+
if (!Array.isArray(inserts)) {
|
|
340
|
+
triggerWarning(`The splice insertion must be a string (on path "${path.join('.')}"). The change is ignored.`)
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
this._$pendingChanges.push([path, inserts, index ?? -1, del || 0])
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Add a new property change to queue
|
|
348
|
+
*
|
|
349
|
+
* (Generally designed for template engines.)
|
|
350
|
+
* If the `propName` is a property,
|
|
351
|
+
* the `newData` will be deep-copied according to the `propertyPassingDeepCopy` configuration.
|
|
352
|
+
* Otherwise, it returns false.
|
|
353
|
+
*/
|
|
354
|
+
replaceProperty(propName: string, newData: DataValue): boolean {
|
|
355
|
+
let data = newData
|
|
356
|
+
if (!this._$propFields[propName]) return false
|
|
357
|
+
if (this._$propertyPassingDeepCopy !== DeepCopyStrategy.None) {
|
|
358
|
+
if (this._$propertyPassingDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
359
|
+
data = deepCopy(newData, true)
|
|
360
|
+
} else {
|
|
361
|
+
data = simpleDeepCopy(newData)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
this._$pendingChanges.push([[propName], data, undefined, undefined])
|
|
365
|
+
return true
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Discard changes in queue and generate a new queue with specified changes */
|
|
369
|
+
setChanges(changes: DataChange[]) {
|
|
370
|
+
this._$pendingChanges = changes
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** Get the data change queue */
|
|
374
|
+
getChanges(): DataChange[] {
|
|
375
|
+
return this._$pendingChanges
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Set a callback when a specified property changes
|
|
380
|
+
*
|
|
381
|
+
* (Generally designed for template engines.)
|
|
382
|
+
*/
|
|
383
|
+
setModelBindingListener(propName: string, listener: ModelBindingListener) {
|
|
384
|
+
if (this._$modelBindingListener) {
|
|
385
|
+
this._$modelBindingListener[propName] = listener
|
|
386
|
+
} else {
|
|
387
|
+
const map = this._$modelBindingListener = Object.create(null) as
|
|
388
|
+
{ [name: string]: ModelBindingListener }
|
|
389
|
+
map[propName] = listener
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** Apply all changes in queue */
|
|
394
|
+
applyDataUpdates(skipModelListener = false) {
|
|
395
|
+
const propFields = this._$propFields
|
|
396
|
+
const comp = this._$comp
|
|
397
|
+
const pureDataPattern = this._$pureDataPattern
|
|
398
|
+
const dataDeepCopy = this._$dataDeepCopy
|
|
399
|
+
|
|
400
|
+
// handling chained updates if observers are used
|
|
401
|
+
const isChainedUpdates = !!this._$doingUpdates
|
|
402
|
+
let combinedChanges: DataChange[]
|
|
403
|
+
let propChanges: PropertyChange[]
|
|
404
|
+
if (this._$observers.length > 0) {
|
|
405
|
+
if (this._$doingUpdates) {
|
|
406
|
+
combinedChanges = this._$doingUpdates.combined
|
|
407
|
+
propChanges = this._$doingUpdates.prop
|
|
408
|
+
} else {
|
|
409
|
+
this._$doingUpdates = {
|
|
410
|
+
prop: [] as PropertyChange[],
|
|
411
|
+
combined: [] as DataChange[],
|
|
412
|
+
count: 0,
|
|
413
|
+
}
|
|
414
|
+
combinedChanges = this._$doingUpdates.combined
|
|
415
|
+
propChanges = this._$doingUpdates.prop
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
combinedChanges = []
|
|
419
|
+
propChanges = []
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// find all changes
|
|
423
|
+
const changes = this._$pendingChanges
|
|
424
|
+
this._$pendingChanges = []
|
|
425
|
+
|
|
426
|
+
// apply changes and collect changing information
|
|
427
|
+
for (let i = 0; i < changes.length; i += 1) {
|
|
428
|
+
const change = changes[i]!
|
|
429
|
+
const [path, newData, spliceIndex, spliceDel] = change
|
|
430
|
+
const isSplice = spliceDel !== undefined
|
|
431
|
+
const propName = String(path[0])
|
|
432
|
+
const excluded = pureDataPattern ? pureDataPattern.test(propName) : false
|
|
433
|
+
const prop: PropertyDefinition | undefined = propFields[propName]
|
|
434
|
+
if (prop && path.length === 1) {
|
|
435
|
+
// do update for 1-level fields
|
|
436
|
+
const oldData: unknown = this.data[propName]
|
|
437
|
+
let normalizedSpliceIndex: number | undefined
|
|
438
|
+
let filteredData: DataValue
|
|
439
|
+
if (isSplice) {
|
|
440
|
+
if (Array.isArray(oldData)) {
|
|
441
|
+
const c = change as DataSplice
|
|
442
|
+
normalizedSpliceIndex = spliceIndex! >= 0 && spliceIndex! < oldData.length
|
|
443
|
+
? spliceIndex!
|
|
444
|
+
: oldData.length
|
|
445
|
+
c[2] = normalizedSpliceIndex
|
|
446
|
+
oldData.splice(normalizedSpliceIndex, spliceDel, ...(newData as typeof oldData))
|
|
447
|
+
} else {
|
|
448
|
+
triggerWarning(`An array splice change cannot be applied to a non-array value (on path "${path.join('.')}"). The change is ignored.`)
|
|
449
|
+
}
|
|
450
|
+
filteredData = oldData
|
|
451
|
+
} else {
|
|
452
|
+
filteredData = convertValueToType(newData, propName, prop)
|
|
453
|
+
}
|
|
454
|
+
if (!excluded) {
|
|
455
|
+
if (this.innerData) {
|
|
456
|
+
let innerNewData: unknown
|
|
457
|
+
if (dataDeepCopy === DeepCopyStrategy.None) {
|
|
458
|
+
change[1] = innerNewData = filteredData
|
|
459
|
+
} else if (normalizedSpliceIndex !== undefined) {
|
|
460
|
+
innerNewData = this.innerData[propName] as DataValue[]
|
|
461
|
+
let inserts: DataValue[]
|
|
462
|
+
if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
463
|
+
change[1] = inserts = deepCopy(newData as unknown[], true)
|
|
464
|
+
} else {
|
|
465
|
+
change[1] = inserts = simpleDeepCopy(newData as unknown[])
|
|
466
|
+
}
|
|
467
|
+
(innerNewData as DataValue[]).splice(normalizedSpliceIndex, spliceDel!, ...inserts)
|
|
468
|
+
} else if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
469
|
+
change[1] = innerNewData = deepCopy(filteredData, true)
|
|
470
|
+
} else {
|
|
471
|
+
change[1] = innerNewData = simpleDeepCopy(filteredData)
|
|
472
|
+
}
|
|
473
|
+
this.innerData[propName] = innerNewData
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
(this.data as DataList)[propName] = filteredData
|
|
477
|
+
if (this._$reflectToAttributes) {
|
|
478
|
+
const be = comp!.getBackendElement()
|
|
479
|
+
if (be) {
|
|
480
|
+
let attrValue = filteredData
|
|
481
|
+
if (prop.reflectIdPrefix) {
|
|
482
|
+
const owner = comp!.ownerShadowRoot
|
|
483
|
+
if (owner) {
|
|
484
|
+
const idPrefix = owner.getHostNode()._$idPrefix
|
|
485
|
+
if (idPrefix) {
|
|
486
|
+
attrValue = `${idPrefix}--${filteredData as string}`
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const attrName = propName.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)
|
|
491
|
+
const type = typeof attrValue
|
|
492
|
+
if (type === 'boolean') {
|
|
493
|
+
if (filteredData) be.setAttribute(attrName, '')
|
|
494
|
+
else be.removeAttribute(attrName)
|
|
495
|
+
} else if (type === 'object') {
|
|
496
|
+
be.setAttribute(attrName, JSON.stringify(attrValue))
|
|
497
|
+
} else {
|
|
498
|
+
be.setAttribute(attrName, attrValue)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
if (!excluded && oldData !== filteredData) {
|
|
503
|
+
propChanges.push({
|
|
504
|
+
propName,
|
|
505
|
+
prop,
|
|
506
|
+
oldValue: oldData,
|
|
507
|
+
newValue: filteredData,
|
|
508
|
+
skipModelListener,
|
|
509
|
+
})
|
|
510
|
+
}
|
|
511
|
+
} else {
|
|
512
|
+
// do update for multi-level fields
|
|
513
|
+
let curData: { [key: string]: unknown } | unknown[] = this.data
|
|
514
|
+
let curSlice: string | number = propName
|
|
515
|
+
for (let i = 1; i < path.length; i += 1) {
|
|
516
|
+
const nextSlice = path[i]!
|
|
517
|
+
if (Number.isFinite(nextSlice)) {
|
|
518
|
+
if (
|
|
519
|
+
!hasOwnProperty.call(curData, curSlice)
|
|
520
|
+
|| !Array.isArray((curData as { [key: string]: unknown })[curSlice as string])
|
|
521
|
+
) {
|
|
522
|
+
(curData as { [key: string]: unknown })[curSlice as string] = []
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
if (
|
|
526
|
+
!hasOwnProperty.call(curData, curSlice)
|
|
527
|
+
|| (curData as { [key: string]: unknown })[curSlice as string] === null
|
|
528
|
+
|| typeof (curData as { [key: string]: unknown })[curSlice as string] !== 'object'
|
|
529
|
+
|| Array.isArray((curData as { [key: string]: unknown })[curSlice as string])
|
|
530
|
+
) {
|
|
531
|
+
(curData as { [key: string]: unknown })[curSlice as string] = {}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
curData = (curData as { [key: string]: unknown })[curSlice as string] as
|
|
535
|
+
{ [key: string]: unknown } | unknown[]
|
|
536
|
+
curSlice = nextSlice
|
|
537
|
+
}
|
|
538
|
+
let normalizedSpliceIndex: number | undefined
|
|
539
|
+
if (isSplice) {
|
|
540
|
+
const oldData = (curData as DataList)[curSlice as string]
|
|
541
|
+
if (Array.isArray(oldData)) {
|
|
542
|
+
const c = change as DataSplice
|
|
543
|
+
normalizedSpliceIndex = spliceIndex! >= 0 && spliceIndex! < oldData.length
|
|
544
|
+
? spliceIndex!
|
|
545
|
+
: oldData.length
|
|
546
|
+
c[2] = normalizedSpliceIndex
|
|
547
|
+
oldData.splice(normalizedSpliceIndex, spliceDel, ...(newData as typeof oldData))
|
|
548
|
+
} else {
|
|
549
|
+
triggerWarning(`An array splice change cannot be applied to a non-array value (on path "${path.join('.')}"). The change is ignored.`)
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
(curData as DataList)[curSlice as string] = newData
|
|
553
|
+
}
|
|
554
|
+
if (!excluded && this.innerData) {
|
|
555
|
+
curData = this.innerData
|
|
556
|
+
curSlice = propName
|
|
557
|
+
for (let i = 1; i < path.length; i += 1) {
|
|
558
|
+
const nextSlice = path[i]!
|
|
559
|
+
if (Number.isFinite(nextSlice)) {
|
|
560
|
+
if (
|
|
561
|
+
!hasOwnProperty.call(curData, curSlice)
|
|
562
|
+
|| !Array.isArray((curData as { [key: string]: unknown })[curSlice as string])
|
|
563
|
+
) {
|
|
564
|
+
(curData as { [key: string]: unknown })[curSlice as string] = []
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
if (
|
|
568
|
+
!hasOwnProperty.call(curData, curSlice)
|
|
569
|
+
|| (curData as { [key: string]: unknown })[curSlice as string] === null
|
|
570
|
+
|| typeof (curData as { [key: string]: unknown })[curSlice as string] !== 'object'
|
|
571
|
+
|| Array.isArray((curData as { [key: string]: unknown })[curSlice as string])
|
|
572
|
+
) {
|
|
573
|
+
(curData as { [key: string]: unknown })[curSlice as string] = {}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
curData = (curData as { [key: string]: unknown })[curSlice as string] as
|
|
577
|
+
{ [key: string]: unknown } | unknown[]
|
|
578
|
+
curSlice = nextSlice
|
|
579
|
+
}
|
|
580
|
+
let innerNewData: unknown
|
|
581
|
+
if (dataDeepCopy === DeepCopyStrategy.None) {
|
|
582
|
+
change[1] = innerNewData = newData
|
|
583
|
+
} else if (normalizedSpliceIndex !== undefined) {
|
|
584
|
+
innerNewData = (curData as { [key: string]: unknown })[curSlice as string] as
|
|
585
|
+
DataValue[]
|
|
586
|
+
let inserts: DataValue[]
|
|
587
|
+
if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
588
|
+
change[1] = inserts = deepCopy(newData as unknown[], true)
|
|
589
|
+
} else {
|
|
590
|
+
change[1] = inserts = simpleDeepCopy(newData as unknown[])
|
|
591
|
+
}
|
|
592
|
+
(innerNewData as DataValue[]).splice(normalizedSpliceIndex, spliceDel!, ...inserts)
|
|
593
|
+
} else if (dataDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
|
|
594
|
+
change[1] = innerNewData = deepCopy(newData, true)
|
|
595
|
+
} else {
|
|
596
|
+
change[1] = innerNewData = simpleDeepCopy(newData)
|
|
597
|
+
}
|
|
598
|
+
(curData as { [key: string]: unknown })[curSlice as string] = innerNewData
|
|
599
|
+
}
|
|
600
|
+
if (!excluded && prop) {
|
|
601
|
+
// NOTE for prop observers, oldVal will be undefined when doing a sub-path update
|
|
602
|
+
propChanges.push({
|
|
603
|
+
propName,
|
|
604
|
+
prop,
|
|
605
|
+
oldValue: undefined,
|
|
606
|
+
newValue: newData,
|
|
607
|
+
skipModelListener: skipModelListener || false,
|
|
608
|
+
})
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
markTriggerBitOnPath(this._$observerTree, this._$observerStatus, path)
|
|
612
|
+
if (!excluded) {
|
|
613
|
+
combinedChanges.push(change)
|
|
614
|
+
}
|
|
615
|
+
if (this._$doingUpdates) {
|
|
616
|
+
this._$doingUpdates.count += 1
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// trigger data observers
|
|
621
|
+
if (isChainedUpdates) return
|
|
622
|
+
if (this._$doingUpdates) {
|
|
623
|
+
let changesCount: number
|
|
624
|
+
do {
|
|
625
|
+
changesCount = this._$doingUpdates.count
|
|
626
|
+
triggerAndCleanTriggerBit(this._$observers, this._$observerStatus, comp, this.data)
|
|
627
|
+
} while (changesCount !== this._$doingUpdates.count)
|
|
628
|
+
this._$doingUpdates = null
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// tell template engine what changed
|
|
632
|
+
this._$updateListener?.(
|
|
633
|
+
this.innerData || this.data,
|
|
634
|
+
combinedChanges,
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
// trigger prop observers (to simulating legacy behaviors)
|
|
638
|
+
if (comp) {
|
|
639
|
+
for (let i = 0; i < propChanges.length; i += 1) {
|
|
640
|
+
const {
|
|
641
|
+
propName,
|
|
642
|
+
prop,
|
|
643
|
+
oldValue,
|
|
644
|
+
newValue,
|
|
645
|
+
skipModelListener,
|
|
646
|
+
} = propChanges[i]!
|
|
647
|
+
if (!skipModelListener && this._$modelBindingListener) {
|
|
648
|
+
const listener = this._$modelBindingListener[propName]
|
|
649
|
+
if (listener) listener(newValue)
|
|
650
|
+
}
|
|
651
|
+
if (prop.observer) {
|
|
652
|
+
safeCallback('Property Observer', prop.observer, comp.getMethodCaller() as any, [newValue, oldValue], comp as unknown as GeneralComponentInstance)
|
|
653
|
+
}
|
|
654
|
+
if (comp._$mutationObserverTarget) {
|
|
655
|
+
MutationObserverTarget.callAttrObservers(comp, {
|
|
656
|
+
type: 'properties',
|
|
657
|
+
target: comp,
|
|
658
|
+
propertyName: propName,
|
|
659
|
+
})
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
export type GeneralDataGroup = DataGroup<
|
|
667
|
+
DataList,
|
|
668
|
+
PropertyList,
|
|
669
|
+
MethodList
|
|
670
|
+
>
|