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,230 @@
|
|
|
1
|
+
/* eslint-disable class-methods-use-this */
|
|
2
|
+
/* global document */
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
DataValue,
|
|
6
|
+
Node,
|
|
7
|
+
ShadowedEvent,
|
|
8
|
+
GeneralBackendElement,
|
|
9
|
+
} from '..'
|
|
10
|
+
import {
|
|
11
|
+
DataPath,
|
|
12
|
+
} from '../data_path'
|
|
13
|
+
import { RangeListManager } from './range_list_diff'
|
|
14
|
+
import {
|
|
15
|
+
ProcGen,
|
|
16
|
+
BindingMapGen,
|
|
17
|
+
UpdatePathTreeRoot,
|
|
18
|
+
dataValueToString,
|
|
19
|
+
ProcGenWrapper,
|
|
20
|
+
} from './proc_gen_wrapper'
|
|
21
|
+
import type {
|
|
22
|
+
GlassEaselTemplateDOMInstance,
|
|
23
|
+
} from './native_rendering'
|
|
24
|
+
|
|
25
|
+
type TmplArgs = {
|
|
26
|
+
key?: number | string,
|
|
27
|
+
keyList?: RangeListManager,
|
|
28
|
+
scopeData?: unknown, // for wx:scope-data
|
|
29
|
+
dynEvListeners?: {
|
|
30
|
+
[name: string]: (ev: ShadowedEvent<unknown>) => boolean | undefined,
|
|
31
|
+
},
|
|
32
|
+
index?: number,
|
|
33
|
+
slotProps?: Record<string, [DataValue, DataPath | null, boolean]>,
|
|
34
|
+
slotPropsUpdatePathTree?: Record<string, UpdatePathTreeRoot>,
|
|
35
|
+
}
|
|
36
|
+
export type TmplNode = Node & { _$wxTmplArgs?: TmplArgs }
|
|
37
|
+
|
|
38
|
+
const noop = () => { /* empty */ }
|
|
39
|
+
|
|
40
|
+
export type DefineChildren = (
|
|
41
|
+
isCreation: boolean,
|
|
42
|
+
defineTextNode: DefineTextNode,
|
|
43
|
+
defineElement: DefineElement,
|
|
44
|
+
defineIfGroup: typeof noop,
|
|
45
|
+
defineForLoop: typeof noop,
|
|
46
|
+
defineSlot: DefineSlot,
|
|
47
|
+
definePureVirtualNode: DefinePureVirtualNode,
|
|
48
|
+
) => void
|
|
49
|
+
|
|
50
|
+
type DefineTextNode = (
|
|
51
|
+
text: string | undefined,
|
|
52
|
+
textInit?: (elem: Text) => void,
|
|
53
|
+
) => void
|
|
54
|
+
|
|
55
|
+
type DefineElement = (
|
|
56
|
+
tag: string,
|
|
57
|
+
genericImpls: { [key: string]: string },
|
|
58
|
+
propertyInit: (elem: HTMLElement, isCreation: boolean) => void,
|
|
59
|
+
children: DefineChildren,
|
|
60
|
+
slot: string | undefined,
|
|
61
|
+
) => void
|
|
62
|
+
|
|
63
|
+
type DefineSlot = () => void
|
|
64
|
+
|
|
65
|
+
type DefinePureVirtualNode = (
|
|
66
|
+
children: DefineChildren,
|
|
67
|
+
slot: string | undefined,
|
|
68
|
+
) => void
|
|
69
|
+
|
|
70
|
+
export class ProcGenWrapperDom {
|
|
71
|
+
shadowRoot: GlassEaselTemplateDOMInstance
|
|
72
|
+
procGen: ProcGen
|
|
73
|
+
|
|
74
|
+
constructor(
|
|
75
|
+
shadowRoot: GlassEaselTemplateDOMInstance,
|
|
76
|
+
procGen: ProcGen,
|
|
77
|
+
) {
|
|
78
|
+
this.shadowRoot = shadowRoot
|
|
79
|
+
this.procGen = procGen
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
create(data: DataValue): { [field: string]: BindingMapGen[] } | undefined {
|
|
83
|
+
const { shadowRoot, procGen } = this
|
|
84
|
+
const children = procGen(this as unknown as ProcGenWrapper, true, data, undefined)
|
|
85
|
+
this.handleChildrenCreation(
|
|
86
|
+
children.C as unknown as DefineChildren,
|
|
87
|
+
shadowRoot.shadowRootElement as HTMLElement,
|
|
88
|
+
)
|
|
89
|
+
return children.B
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
bindingMapUpdate(
|
|
93
|
+
field: string,
|
|
94
|
+
data: DataValue,
|
|
95
|
+
bindingMapGenList: { [field: string]: BindingMapGen[] },
|
|
96
|
+
): void {
|
|
97
|
+
const updaters = bindingMapGenList[field]
|
|
98
|
+
if (updaters === undefined) return
|
|
99
|
+
for (let i = 0; i < updaters.length; i += 1) {
|
|
100
|
+
const bindingMapGen = updaters[i]!
|
|
101
|
+
bindingMapGen(
|
|
102
|
+
data,
|
|
103
|
+
() => { /* empty */ },
|
|
104
|
+
(elem: unknown, v: string) => {
|
|
105
|
+
(elem as Text).textContent = v
|
|
106
|
+
},
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
handleChildrenCreation(children: DefineChildren, parentNode: HTMLElement): void {
|
|
112
|
+
let slotMergeable = true
|
|
113
|
+
let slotMerged = false
|
|
114
|
+
const appendSlot = () => {
|
|
115
|
+
slotMergeable = false
|
|
116
|
+
slotMerged = false
|
|
117
|
+
const elem = document.createElement('virtual')
|
|
118
|
+
parentNode.appendChild(elem)
|
|
119
|
+
this.shadowRoot.slot = elem as unknown as GeneralBackendElement
|
|
120
|
+
}
|
|
121
|
+
children(
|
|
122
|
+
true,
|
|
123
|
+
// text node
|
|
124
|
+
(textContent: string | undefined, textInit?: (elem: Text) => void) => {
|
|
125
|
+
if (slotMerged) appendSlot()
|
|
126
|
+
else slotMergeable = false
|
|
127
|
+
const elem = document.createTextNode(textContent || '')
|
|
128
|
+
if (textInit) textInit(elem)
|
|
129
|
+
parentNode.appendChild(elem)
|
|
130
|
+
},
|
|
131
|
+
// component or native node
|
|
132
|
+
(
|
|
133
|
+
tagName: string,
|
|
134
|
+
genericImpls: { [key: string]: string },
|
|
135
|
+
propertyInit: (elem: HTMLElement, isCreation: boolean) => void,
|
|
136
|
+
children: DefineChildren,
|
|
137
|
+
) => {
|
|
138
|
+
if (slotMerged) appendSlot()
|
|
139
|
+
else slotMergeable = false
|
|
140
|
+
const elem = document.createElement(tagName)
|
|
141
|
+
propertyInit(elem, true)
|
|
142
|
+
this.handleChildrenCreation(children, elem)
|
|
143
|
+
parentNode.appendChild(elem)
|
|
144
|
+
},
|
|
145
|
+
// wx:if node or template-is node
|
|
146
|
+
noop,
|
|
147
|
+
// wx:for node
|
|
148
|
+
noop,
|
|
149
|
+
// slot node
|
|
150
|
+
() => {
|
|
151
|
+
if (slotMergeable) {
|
|
152
|
+
slotMerged = true
|
|
153
|
+
this.shadowRoot.slot = parentNode as unknown as GeneralBackendElement
|
|
154
|
+
} else {
|
|
155
|
+
appendSlot()
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
// other virtual node
|
|
159
|
+
(
|
|
160
|
+
children: DefineChildren,
|
|
161
|
+
) => {
|
|
162
|
+
if (slotMerged) appendSlot()
|
|
163
|
+
else slotMergeable = false
|
|
164
|
+
const elem = document.createElement('virtual')
|
|
165
|
+
this.handleChildrenCreation(children, elem)
|
|
166
|
+
parentNode.appendChild(elem)
|
|
167
|
+
},
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// set slot
|
|
172
|
+
s() {
|
|
173
|
+
noop()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// set id
|
|
177
|
+
i(elem: HTMLElement, v: string) {
|
|
178
|
+
this.shadowRoot.idMap[v] = elem
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// set class or external classes named `class`
|
|
182
|
+
c(elem: HTMLElement, v: string) {
|
|
183
|
+
elem.setAttribute('class', v)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// set style or property named `style`
|
|
187
|
+
y(elem: HTMLElement, v: string) {
|
|
188
|
+
elem.setAttribute('style', v)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// set dataset
|
|
192
|
+
d(elem: HTMLElement, name: string, v: unknown) {
|
|
193
|
+
elem.dataset[name] = dataValueToString(v)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// set mark
|
|
197
|
+
m() {
|
|
198
|
+
noop()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// set event handler
|
|
202
|
+
v(
|
|
203
|
+
elem: HTMLElement,
|
|
204
|
+
evName: string,
|
|
205
|
+
v: string,
|
|
206
|
+
final: boolean,
|
|
207
|
+
) {
|
|
208
|
+
this.shadowRoot.setListener(elem as unknown as GeneralBackendElement, evName, (ev) => {
|
|
209
|
+
const handler = this.shadowRoot.template.methods[v]
|
|
210
|
+
const ret = handler?.(ev) as unknown
|
|
211
|
+
if (final) return false
|
|
212
|
+
return ret
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// set scope-data
|
|
217
|
+
sd() {
|
|
218
|
+
noop()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// update a property or external class of a component, or an attribute of a native node
|
|
222
|
+
r(elem: HTMLElement, name: string, v: unknown) {
|
|
223
|
+
if (typeof v === 'boolean') {
|
|
224
|
+
if (v) elem.setAttribute(name, '')
|
|
225
|
+
else elem.removeAttribute(name)
|
|
226
|
+
} else {
|
|
227
|
+
elem.setAttribute(name, dataValueToString(v))
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Element,
|
|
3
|
+
VirtualNode,
|
|
4
|
+
} from '..'
|
|
5
|
+
import {
|
|
6
|
+
DataValue,
|
|
7
|
+
} from '../data_proxy'
|
|
8
|
+
import { UpdatePathTreeNode, UpdatePathTreeRoot } from './proc_gen_wrapper'
|
|
9
|
+
import { triggerWarning } from '../func_arr'
|
|
10
|
+
|
|
11
|
+
export class RangeListManager {
|
|
12
|
+
keyName: string | null
|
|
13
|
+
rawKeys!: string[]
|
|
14
|
+
keyMap!: { [key: string]: number }
|
|
15
|
+
sharedKeyMap!: { [key: string]: number[] } | undefined
|
|
16
|
+
items!: DataValue[]
|
|
17
|
+
indexes!: (string | number)[] | null
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
keyName: string | null,
|
|
21
|
+
dataList: DataValue,
|
|
22
|
+
elem: Element,
|
|
23
|
+
newListItem: (
|
|
24
|
+
item: DataValue,
|
|
25
|
+
index: number | string,
|
|
26
|
+
) => VirtualNode,
|
|
27
|
+
) {
|
|
28
|
+
this.keyName = keyName
|
|
29
|
+
this.updateKeys(dataList)
|
|
30
|
+
const items = this.items
|
|
31
|
+
const indexes = this.indexes
|
|
32
|
+
const children: VirtualNode[] = []
|
|
33
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
34
|
+
const item = items[i]!
|
|
35
|
+
const index = indexes === null ? i : indexes[i]!
|
|
36
|
+
children.push(newListItem(item, index))
|
|
37
|
+
}
|
|
38
|
+
elem.insertChildren(children, -1)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
updateKeys(dataList: DataValue) {
|
|
42
|
+
// collect the list depending on the the type of the data list
|
|
43
|
+
let items: DataValue[]
|
|
44
|
+
let indexes: (string | number)[] | null
|
|
45
|
+
if (Array.isArray(dataList)) {
|
|
46
|
+
items = dataList
|
|
47
|
+
indexes = null
|
|
48
|
+
} else if (typeof dataList === 'object' && dataList !== null) {
|
|
49
|
+
const k = Object.keys(dataList)
|
|
50
|
+
items = new Array<DataValue>(k.length)
|
|
51
|
+
indexes = new Array<string>(k.length)
|
|
52
|
+
for (let i = 0; i < k.length; i += 1) {
|
|
53
|
+
const key = k[i]!
|
|
54
|
+
const item = (dataList as { [key: string]: unknown })[key]
|
|
55
|
+
items[i] = item
|
|
56
|
+
indexes[i] = key
|
|
57
|
+
}
|
|
58
|
+
} else if (typeof dataList === 'string') {
|
|
59
|
+
triggerWarning('Use string as for-list is generally for testing. Each character is treated as an item.')
|
|
60
|
+
items = new Array<string>(dataList.length)
|
|
61
|
+
indexes = null
|
|
62
|
+
for (let i = 0; i < dataList.length; i += 1) {
|
|
63
|
+
items[i] = dataList[i]!
|
|
64
|
+
}
|
|
65
|
+
} else if (typeof dataList === 'number') {
|
|
66
|
+
triggerWarning('Use number as for-list is generally for testing. The number is used as the repeated times of the item.')
|
|
67
|
+
items = new Array<string>(dataList)
|
|
68
|
+
indexes = null
|
|
69
|
+
for (let i = 0; i < dataList; i += 1) {
|
|
70
|
+
items[i] = i
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
triggerWarning('The for-list data is invalid. Use empty array instead.')
|
|
74
|
+
items = []
|
|
75
|
+
indexes = null
|
|
76
|
+
}
|
|
77
|
+
this.items = items
|
|
78
|
+
this.indexes = indexes
|
|
79
|
+
|
|
80
|
+
// generate keys and key indexes map for the list
|
|
81
|
+
const keyName = this.keyName
|
|
82
|
+
const rawKeys = new Array<string>(items.length)
|
|
83
|
+
const keyMap = Object.create(null) as { [key: string]: number }
|
|
84
|
+
let sharedKeyMap: { [key: string]: number[] } | undefined
|
|
85
|
+
if (keyName !== null) {
|
|
86
|
+
// firstly, find all unique keys and shared keys
|
|
87
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
88
|
+
const item = items[i]! as { [k: string]: unknown } | undefined
|
|
89
|
+
const rawKeyField = keyName === '*this' ? item : item?.[keyName]
|
|
90
|
+
const rawKey = rawKeyField !== undefined && rawKeyField !== null ? String(rawKeyField) : ''
|
|
91
|
+
rawKeys[i] = rawKey
|
|
92
|
+
if (keyMap[rawKey] !== undefined) {
|
|
93
|
+
if (!sharedKeyMap) {
|
|
94
|
+
sharedKeyMap = Object.create(null) as { [key: string]: number[] }
|
|
95
|
+
}
|
|
96
|
+
sharedKeyMap[rawKey] = [keyMap[rawKey]!, i]
|
|
97
|
+
delete keyMap[rawKey]
|
|
98
|
+
} else {
|
|
99
|
+
keyMap[rawKey] = i
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// convert shared keys to unique keys
|
|
103
|
+
if (sharedKeyMap) {
|
|
104
|
+
const keys = Object.keys(sharedKeyMap)
|
|
105
|
+
triggerWarning(`Some keys are not unique while list updates: "${keys.join('", "')}".`)
|
|
106
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
107
|
+
const key = keys[i]!
|
|
108
|
+
const items = sharedKeyMap[key]!
|
|
109
|
+
let inc = 0
|
|
110
|
+
for (let j = 0; j < items.length; j += 1) {
|
|
111
|
+
const index = items[j]!
|
|
112
|
+
while (keyMap[`${key}--${inc}`] !== undefined) inc += 1
|
|
113
|
+
const k = `${key}--${inc}`
|
|
114
|
+
keyMap[k] = index
|
|
115
|
+
rawKeys[index] = k
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.rawKeys = rawKeys
|
|
121
|
+
this.keyMap = keyMap
|
|
122
|
+
this.sharedKeyMap = sharedKeyMap
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
diff(
|
|
126
|
+
dataList: DataValue[],
|
|
127
|
+
oriUpdatePathTree: UpdatePathTreeRoot,
|
|
128
|
+
elem: Element,
|
|
129
|
+
newListItem: (
|
|
130
|
+
item: DataValue,
|
|
131
|
+
index: string | number,
|
|
132
|
+
) => VirtualNode,
|
|
133
|
+
updateListItem: (
|
|
134
|
+
item: DataValue,
|
|
135
|
+
index: string | number,
|
|
136
|
+
updatePathTree: UpdatePathTreeRoot,
|
|
137
|
+
indexChanged: boolean,
|
|
138
|
+
node: VirtualNode,
|
|
139
|
+
) => void,
|
|
140
|
+
) {
|
|
141
|
+
// generate new list for comparison
|
|
142
|
+
const oldRawKeys = this.rawKeys
|
|
143
|
+
const oldKeyMap = this.keyMap
|
|
144
|
+
const oldSharedKeyMap = this.sharedKeyMap
|
|
145
|
+
const oldIndexes = this.indexes
|
|
146
|
+
this.updateKeys(dataList)
|
|
147
|
+
const newRawKeys = this.rawKeys
|
|
148
|
+
const newSharedKeyMap = this.sharedKeyMap
|
|
149
|
+
const items = this.items
|
|
150
|
+
const indexes = this.indexes
|
|
151
|
+
const keyName = this.keyName
|
|
152
|
+
|
|
153
|
+
// transform the update path tree if needed:
|
|
154
|
+
// if the list has been splice-updated, or a key is updated,
|
|
155
|
+
// all items with old-list shared keys or new-list shared keys should be marked;
|
|
156
|
+
// and items with key updates should be marked
|
|
157
|
+
let allowFastComparison: boolean
|
|
158
|
+
let updatePathTree: UpdatePathTreeRoot
|
|
159
|
+
if (oriUpdatePathTree === true) {
|
|
160
|
+
updatePathTree = true
|
|
161
|
+
allowFastComparison = keyName === null
|
|
162
|
+
} else if (oriUpdatePathTree === undefined) {
|
|
163
|
+
updatePathTree = oriUpdatePathTree
|
|
164
|
+
allowFastComparison = true
|
|
165
|
+
} else if (keyName === null) {
|
|
166
|
+
updatePathTree = true
|
|
167
|
+
allowFastComparison = true
|
|
168
|
+
} else {
|
|
169
|
+
let needUpdate = false
|
|
170
|
+
if (Array.isArray(oriUpdatePathTree)) {
|
|
171
|
+
needUpdate = true
|
|
172
|
+
} else {
|
|
173
|
+
const keys = Object.keys(oriUpdatePathTree)
|
|
174
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
175
|
+
const k = keys[i]!
|
|
176
|
+
const subTree = (oriUpdatePathTree as { [s: string]: UpdatePathTreeNode })[k]! as
|
|
177
|
+
{ [s: string]: UpdatePathTreeNode } | undefined | true
|
|
178
|
+
if (subTree === true || (keyName === '*this' ? subTree : subTree?.[keyName])) {
|
|
179
|
+
needUpdate = true
|
|
180
|
+
break
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (needUpdate) {
|
|
185
|
+
updatePathTree = new Array(newRawKeys.length)
|
|
186
|
+
for (let i = 0; i < newRawKeys.length; i += 1) {
|
|
187
|
+
const k = newRawKeys[i]!
|
|
188
|
+
if (oldSharedKeyMap?.[k] !== undefined || newSharedKeyMap?.[k] !== undefined) {
|
|
189
|
+
updatePathTree[i] = true
|
|
190
|
+
} else {
|
|
191
|
+
const subTree = (oriUpdatePathTree as { [s: string]: UpdatePathTreeNode })[i] as
|
|
192
|
+
{ [s: string]: UpdatePathTreeNode } | undefined | true
|
|
193
|
+
if (subTree === undefined) {
|
|
194
|
+
// empty
|
|
195
|
+
} else if (subTree === true || (keyName === '*this' ? subTree : subTree?.[keyName])) {
|
|
196
|
+
updatePathTree[i] = true
|
|
197
|
+
} else {
|
|
198
|
+
updatePathTree[i] = subTree
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
allowFastComparison = false
|
|
203
|
+
} else {
|
|
204
|
+
updatePathTree = oriUpdatePathTree
|
|
205
|
+
allowFastComparison = false
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// if there is no key, or nothing in the old list range is updated
|
|
210
|
+
if (allowFastComparison) {
|
|
211
|
+
// transform the update path tree if needed:
|
|
212
|
+
// if the list has been splice-updated, then mark the whole list
|
|
213
|
+
let updatePathTree: UpdatePathTreeRoot
|
|
214
|
+
if (Array.isArray(oriUpdatePathTree)) updatePathTree = true
|
|
215
|
+
else updatePathTree = oriUpdatePathTree
|
|
216
|
+
|
|
217
|
+
// simply match them one-by-one
|
|
218
|
+
let i = 0
|
|
219
|
+
while (i < oldRawKeys.length && i < newRawKeys.length) {
|
|
220
|
+
const item = items[i]!
|
|
221
|
+
const index = indexes === null ? i : indexes[i]!
|
|
222
|
+
const oldIndex = oldIndexes === null ? i : oldIndexes[i]!
|
|
223
|
+
const u = updatePathTree === true || updatePathTree === undefined
|
|
224
|
+
? updatePathTree
|
|
225
|
+
: updatePathTree[i]
|
|
226
|
+
updateListItem(item, index, u, index !== oldIndex, elem.childNodes[i]! as VirtualNode)
|
|
227
|
+
i += 1
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// if the old list has extra items, remove them;
|
|
231
|
+
// if the new list has extra items, append them
|
|
232
|
+
if (i < oldRawKeys.length) {
|
|
233
|
+
elem.removeChildren(i, oldRawKeys.length - i)
|
|
234
|
+
} else if (i < newRawKeys.length) {
|
|
235
|
+
const children: VirtualNode[] = []
|
|
236
|
+
for (; i < newRawKeys.length; i += 1) {
|
|
237
|
+
const item = items[i]!
|
|
238
|
+
const index = indexes === null ? i : indexes[i]!
|
|
239
|
+
children.push(newListItem(item, index))
|
|
240
|
+
}
|
|
241
|
+
elem.insertChildren(children, -1)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// in order to find out which nodes are stable (a.k.a. not needed to be moved),
|
|
248
|
+
// here uses a classic LCS (longest-common-subsequence) algorithm for list with distinct items,
|
|
249
|
+
// which is O(N*logN) at worst
|
|
250
|
+
// (the `minIndexByLen[i]` is the minimum old-list index when LCS length is `i` )
|
|
251
|
+
const minIndexByLen: number[] = []
|
|
252
|
+
const minIndexByLenIndexes: number[] = []
|
|
253
|
+
const minIndexPrev = new Array<number>(newRawKeys.length)
|
|
254
|
+
const oldPosList = new Array<number>(newRawKeys.length)
|
|
255
|
+
let prevOldIndex = -1
|
|
256
|
+
let prevMinIndexByLenIndex = -1
|
|
257
|
+
for (let i = 0; i < newRawKeys.length; i += 1) {
|
|
258
|
+
const rawKey = newRawKeys[i]!
|
|
259
|
+
|
|
260
|
+
// the new-list current item is likely to be the same as the one in old-list;
|
|
261
|
+
// if that, simply use it -
|
|
262
|
+
// this will help to decrease the overhead in common cases (O(N) in best case)
|
|
263
|
+
if (oldRawKeys[prevOldIndex + 1] === rawKey) {
|
|
264
|
+
prevOldIndex += 1
|
|
265
|
+
prevMinIndexByLenIndex += 1
|
|
266
|
+
minIndexByLen[prevMinIndexByLenIndex] = prevOldIndex
|
|
267
|
+
minIndexByLenIndexes[prevMinIndexByLenIndex] = i
|
|
268
|
+
minIndexPrev[i] = prevMinIndexByLenIndex > 0
|
|
269
|
+
? minIndexByLenIndexes[prevMinIndexByLenIndex - 1]!
|
|
270
|
+
: -1
|
|
271
|
+
oldPosList[i] = prevOldIndex
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Skip new items
|
|
276
|
+
const oldIndex = oldKeyMap[rawKey]
|
|
277
|
+
if (oldIndex === undefined) {
|
|
278
|
+
oldPosList[i] = -1
|
|
279
|
+
continue
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// find the old-list index for the key of the current item
|
|
283
|
+
let bottom = 0
|
|
284
|
+
let top = minIndexByLen.length
|
|
285
|
+
while (bottom < top) {
|
|
286
|
+
const mid = Math.floor((bottom + top) / 2)
|
|
287
|
+
if (oldIndex < minIndexByLen[mid]!) top = mid
|
|
288
|
+
else bottom = mid + 1
|
|
289
|
+
}
|
|
290
|
+
minIndexByLen[top] = oldIndex
|
|
291
|
+
minIndexByLenIndexes[top] = i
|
|
292
|
+
minIndexPrev[i] = top > 0 ? minIndexByLenIndexes[top - 1]! : -1
|
|
293
|
+
oldPosList[i] = oldIndex
|
|
294
|
+
prevOldIndex = oldIndex
|
|
295
|
+
prevMinIndexByLenIndex = top
|
|
296
|
+
}
|
|
297
|
+
const lcsLen = minIndexByLenIndexes.length
|
|
298
|
+
|
|
299
|
+
// if LCS is the whole list, then the list is not changed -
|
|
300
|
+
// simply match each item one-by-one
|
|
301
|
+
if (lcsLen === newRawKeys.length && lcsLen === oldRawKeys.length) {
|
|
302
|
+
let i = 0
|
|
303
|
+
while (i < oldRawKeys.length && i < newRawKeys.length) {
|
|
304
|
+
const item = items[i]!
|
|
305
|
+
const index = indexes === null ? i : indexes[i]!
|
|
306
|
+
const oldIndex = oldIndexes === null ? i : oldIndexes[i]!
|
|
307
|
+
const u: UpdatePathTreeRoot = updatePathTree === true || updatePathTree === undefined
|
|
308
|
+
? updatePathTree
|
|
309
|
+
: (updatePathTree as UpdatePathTreeNode[])[i]
|
|
310
|
+
updateListItem(item, index, u, index !== oldIndex, elem.childNodes[i]! as VirtualNode)
|
|
311
|
+
i += 1
|
|
312
|
+
}
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// search the unused `minIndexPrev` items to get the LCS item list
|
|
317
|
+
// ( `minIndexByLen` is reused as the LCS array, since they must have the same length)
|
|
318
|
+
let prevLcsIndex = lcsLen > 0 ? minIndexByLenIndexes[lcsLen - 1]! : -1
|
|
319
|
+
let curLcsArrIndex = lcsLen
|
|
320
|
+
while (prevLcsIndex !== -1) {
|
|
321
|
+
curLcsArrIndex -= 1
|
|
322
|
+
minIndexByLen[curLcsArrIndex] = prevLcsIndex
|
|
323
|
+
prevLcsIndex = minIndexPrev[prevLcsIndex]!
|
|
324
|
+
}
|
|
325
|
+
const lcsArr = minIndexByLen
|
|
326
|
+
|
|
327
|
+
// decide what operation to be used with each item
|
|
328
|
+
const enum OpKind {
|
|
329
|
+
Stable = 0,
|
|
330
|
+
ForwardMove,
|
|
331
|
+
BackwardMove,
|
|
332
|
+
}
|
|
333
|
+
const oldListOp = new Array(oldRawKeys.length) as (OpKind | undefined)[]
|
|
334
|
+
const changedItems = new Array(newRawKeys.length) as (VirtualNode | undefined)[]
|
|
335
|
+
let prevLcsOldPos = lcsArr[curLcsArrIndex]!
|
|
336
|
+
for (let i = 0; i < oldPosList.length; i += 1) {
|
|
337
|
+
const oldPos = oldPosList[i]!
|
|
338
|
+
if (i === lcsArr[curLcsArrIndex]) {
|
|
339
|
+
prevLcsOldPos = oldPos
|
|
340
|
+
curLcsArrIndex += 1
|
|
341
|
+
oldListOp[oldPos] = OpKind.Stable
|
|
342
|
+
continue
|
|
343
|
+
}
|
|
344
|
+
if (oldPos === -1) {
|
|
345
|
+
const item = items[i]!
|
|
346
|
+
const index = indexes === null ? i : indexes[i]!
|
|
347
|
+
changedItems[i] = newListItem(item, index)
|
|
348
|
+
continue
|
|
349
|
+
}
|
|
350
|
+
if (oldPos > prevLcsOldPos) {
|
|
351
|
+
oldListOp[oldPos] = OpKind.BackwardMove
|
|
352
|
+
} else {
|
|
353
|
+
oldListOp[oldPos] = OpKind.ForwardMove
|
|
354
|
+
}
|
|
355
|
+
changedItems[i] = elem.childNodes[oldPos] as VirtualNode
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// visit the op list again and do the operations one-by-one
|
|
359
|
+
let realListDiff = 0
|
|
360
|
+
let opOldPos = 0
|
|
361
|
+
let opIndex = 0
|
|
362
|
+
curLcsArrIndex = 0
|
|
363
|
+
do {
|
|
364
|
+
const nextStable = curLcsArrIndex < lcsArr.length
|
|
365
|
+
? lcsArr[curLcsArrIndex]!
|
|
366
|
+
: changedItems.length
|
|
367
|
+
const nextStableOldPos = curLcsArrIndex < lcsArr.length
|
|
368
|
+
? oldPosList[nextStable]!
|
|
369
|
+
: oldListOp.length
|
|
370
|
+
|
|
371
|
+
// remove items between two LCS items
|
|
372
|
+
while (opOldPos < nextStableOldPos) {
|
|
373
|
+
if (oldListOp[opOldPos] === undefined) {
|
|
374
|
+
const start = opOldPos
|
|
375
|
+
opOldPos += 1
|
|
376
|
+
let count = 1
|
|
377
|
+
while (opOldPos < nextStableOldPos && oldListOp[opOldPos] === undefined) {
|
|
378
|
+
opOldPos += 1
|
|
379
|
+
count += 1
|
|
380
|
+
}
|
|
381
|
+
elem.removeChildren(start + realListDiff, count)
|
|
382
|
+
realListDiff -= count
|
|
383
|
+
} else {
|
|
384
|
+
if (oldListOp[opOldPos] === OpKind.BackwardMove) {
|
|
385
|
+
realListDiff -= 1
|
|
386
|
+
}
|
|
387
|
+
opOldPos += 1
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// insert or move items between two LCS items
|
|
392
|
+
while (opIndex < nextStable) {
|
|
393
|
+
const newItem = changedItems[opIndex]!
|
|
394
|
+
const oldPos = oldPosList[opIndex]!
|
|
395
|
+
if (oldPos === -1) {
|
|
396
|
+
const start = opIndex
|
|
397
|
+
opIndex += 1
|
|
398
|
+
let count = 1
|
|
399
|
+
while (opIndex < nextStable && oldPosList[opIndex] === -1) {
|
|
400
|
+
opIndex += 1
|
|
401
|
+
count += 1
|
|
402
|
+
}
|
|
403
|
+
elem.insertChildren(
|
|
404
|
+
changedItems.slice(start, start + count) as VirtualNode[],
|
|
405
|
+
nextStableOldPos + realListDiff,
|
|
406
|
+
)
|
|
407
|
+
realListDiff += count
|
|
408
|
+
} else {
|
|
409
|
+
elem.insertChildAt(newItem, nextStableOldPos + realListDiff)
|
|
410
|
+
const item = items[opIndex]!
|
|
411
|
+
const index = indexes === null ? opIndex : indexes[opIndex]!
|
|
412
|
+
const oldIndex = oldIndexes === null ? oldPos : oldIndexes[oldPos]!
|
|
413
|
+
const u: UpdatePathTreeRoot = updatePathTree === true || updatePathTree === undefined
|
|
414
|
+
? updatePathTree
|
|
415
|
+
: (updatePathTree as UpdatePathTreeNode[])[opIndex]
|
|
416
|
+
updateListItem(item, index, u, index !== oldIndex, newItem)
|
|
417
|
+
if (oldListOp[oldPos] === OpKind.BackwardMove) {
|
|
418
|
+
realListDiff += 1
|
|
419
|
+
}
|
|
420
|
+
opIndex += 1
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// stable items might be marked and indexes in stable positions might change;
|
|
425
|
+
// if that, do an update
|
|
426
|
+
// IDEA do not update if {{index}} is not used in template
|
|
427
|
+
if (curLcsArrIndex < lcsArr.length) {
|
|
428
|
+
const item = items[nextStable]!
|
|
429
|
+
const index = indexes === null ? nextStable : indexes[nextStable]!
|
|
430
|
+
const oldIndex = oldIndexes === null ? nextStableOldPos : oldIndexes[nextStableOldPos]!
|
|
431
|
+
const u: UpdatePathTreeRoot = updatePathTree === true || updatePathTree === undefined
|
|
432
|
+
? updatePathTree
|
|
433
|
+
: (updatePathTree as UpdatePathTreeNode[])[nextStable]
|
|
434
|
+
const node = elem.childNodes[nextStableOldPos + realListDiff]! as VirtualNode
|
|
435
|
+
updateListItem(item, index, u, index !== oldIndex, node)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
opOldPos = nextStableOldPos + 1
|
|
439
|
+
opIndex = nextStable + 1
|
|
440
|
+
curLcsArrIndex += 1
|
|
441
|
+
} while (curLcsArrIndex <= lcsArr.length)
|
|
442
|
+
}
|
|
443
|
+
}
|