glass-easel 0.2.0 → 0.3.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/.eslintignore +4 -0
- package/dist/glass_easel.all.js +2 -2
- package/dist/glass_easel.all.js.map +1 -1
- package/dist/glass_easel.d.ts +2546 -0
- package/dist/glass_easel.domlike.global.js +2 -2
- package/dist/glass_easel.domlike.global.js.map +1 -1
- package/guide/zh_CN/appendix/backend_protocol.md +164 -74
- package/jest.unit.config.js +7 -4
- package/package.json +7 -5
- package/rollup.config.ts +101 -0
- package/src/backend/backend_protocol.ts +26 -345
- package/src/backend/composed_backend_protocol.ts +10 -264
- package/src/backend/current_window_backend_context.ts +478 -0
- package/src/backend/domlike_backend_protocol.ts +9 -498
- package/src/backend/empty_backend.ts +265 -0
- package/src/backend/empty_composed_backend.ts +245 -0
- package/src/backend/index.ts +18 -0
- package/src/backend/suggested_backend_protocol.ts +62 -11
- package/src/behavior.ts +131 -442
- package/src/class_list.ts +328 -222
- package/src/component.ts +349 -184
- package/src/component_params.ts +54 -25
- package/src/component_space.ts +36 -15
- package/src/data_path.ts +22 -34
- package/src/data_proxy.ts +334 -27
- package/src/devtool.ts +89 -0
- package/src/element.ts +667 -285
- package/src/element_iterator.ts +9 -4
- package/src/event.ts +39 -20
- package/src/external_shadow_tree.ts +2 -2
- package/src/func_arr.ts +55 -101
- package/src/global_options.ts +18 -42
- package/src/index.ts +72 -73
- package/src/mutation_observer.ts +10 -7
- package/src/native_node.ts +79 -35
- package/src/node.ts +23 -30
- package/src/relation.ts +101 -12
- package/src/render.ts +5 -3
- package/src/selector.ts +9 -7
- package/src/shadow_root.ts +96 -240
- package/src/template_engine.ts +10 -7
- package/src/text_node.ts +43 -19
- package/src/tmpl/index.ts +38 -30
- package/src/tmpl/native_rendering.ts +14 -21
- package/src/tmpl/proc_gen_wrapper.ts +189 -151
- package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
- package/src/tmpl/range_list_diff.ts +30 -9
- package/src/trait_behaviors.ts +1 -1
- package/src/type_symbol.ts +36 -0
- package/src/virtual_node.ts +26 -13
- package/src/warning.ts +119 -0
- package/tests/base/composed_backend.ts +143 -142
- package/tests/base/env.ts +76 -3
- package/tests/base/match.ts +24 -22
- package/tests/base/shadow_backend.ts +917 -0
- package/tests/core/backend.test.ts +53 -1
- package/tests/core/behavior.test.ts +1 -1
- package/tests/core/data_update.test.ts +135 -0
- package/tests/core/misc.test.ts +91 -21
- package/tests/core/placeholder.test.ts +66 -25
- package/tests/core/slot.test.ts +161 -23
- package/tests/legacy/component.test.js +152 -78
- package/tests/legacy/data_path.test.js +19 -19
- package/tests/legacy/data_proxy.test.js +14 -7
- package/tests/legacy/external.test.js +8 -8
- package/tests/legacy/mutation_observer.test.js +7 -5
- package/tests/legacy/slot.test.js +2 -3
- package/tests/legacy/virtual.test.js +258 -25
- package/tests/tmpl/binding_map.test.ts +201 -195
- package/tests/tmpl/event.test.ts +138 -23
- package/tests/tmpl/expression.test.ts +15 -15
- package/tests/tmpl/lvalue.test.ts +101 -0
- package/tests/tmpl/structure.test.ts +486 -43
- package/tests/types/chaining.test.ts +27 -30
- package/tests/types/createElement.test.ts +5 -4
- package/tests/types/definition.test.ts +11 -14
- package/tsconfig.json +1 -3
- package/dist/glass_easel.all.d.ts +0 -1
- package/dist/glass_easel.domlike.global.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/types/src/backend/backend_protocol.d.ts +0 -141
- package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
- package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
- package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/backend/mode.d.ts +0 -65
- package/dist/types/src/backend/mode.d.ts.map +0 -1
- package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
- package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
- package/dist/types/src/behavior.d.ts +0 -434
- package/dist/types/src/behavior.d.ts.map +0 -1
- package/dist/types/src/class_list.d.ts +0 -83
- package/dist/types/src/class_list.d.ts.map +0 -1
- package/dist/types/src/component.d.ts +0 -325
- package/dist/types/src/component.d.ts.map +0 -1
- package/dist/types/src/component_params.d.ts +0 -236
- package/dist/types/src/component_params.d.ts.map +0 -1
- package/dist/types/src/component_space.d.ts +0 -211
- package/dist/types/src/component_space.d.ts.map +0 -1
- package/dist/types/src/data_path.d.ts +0 -5
- package/dist/types/src/data_path.d.ts.map +0 -1
- package/dist/types/src/data_proxy.d.ts +0 -107
- package/dist/types/src/data_proxy.d.ts.map +0 -1
- package/dist/types/src/data_utils.d.ts +0 -3
- package/dist/types/src/data_utils.d.ts.map +0 -1
- package/dist/types/src/element.d.ts +0 -365
- package/dist/types/src/element.d.ts.map +0 -1
- package/dist/types/src/element_iterator.d.ts +0 -43
- package/dist/types/src/element_iterator.d.ts.map +0 -1
- package/dist/types/src/event.d.ts +0 -105
- package/dist/types/src/event.d.ts.map +0 -1
- package/dist/types/src/external_shadow_tree.d.ts +0 -20
- package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
- package/dist/types/src/func_arr.d.ts +0 -39
- package/dist/types/src/func_arr.d.ts.map +0 -1
- package/dist/types/src/global_options.d.ts +0 -120
- package/dist/types/src/global_options.d.ts.map +0 -1
- package/dist/types/src/index.d.ts +0 -43
- package/dist/types/src/index.d.ts.map +0 -1
- package/dist/types/src/mutation_observer.d.ts +0 -79
- package/dist/types/src/mutation_observer.d.ts.map +0 -1
- package/dist/types/src/native_node.d.ts +0 -11
- package/dist/types/src/native_node.d.ts.map +0 -1
- package/dist/types/src/node.d.ts +0 -48
- package/dist/types/src/node.d.ts.map +0 -1
- package/dist/types/src/relation.d.ts +0 -46
- package/dist/types/src/relation.d.ts.map +0 -1
- package/dist/types/src/render.d.ts +0 -3
- package/dist/types/src/render.d.ts.map +0 -1
- package/dist/types/src/selector.d.ts +0 -32
- package/dist/types/src/selector.d.ts.map +0 -1
- package/dist/types/src/shadow_root.d.ts +0 -174
- package/dist/types/src/shadow_root.d.ts.map +0 -1
- package/dist/types/src/template_engine.d.ts +0 -56
- package/dist/types/src/template_engine.d.ts.map +0 -1
- package/dist/types/src/text_node.d.ts +0 -44
- package/dist/types/src/text_node.d.ts.map +0 -1
- package/dist/types/src/tmpl/index.d.ts +0 -19
- package/dist/types/src/tmpl/index.d.ts.map +0 -1
- package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
- package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
- package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
- package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
- package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
- package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
- package/dist/types/src/trait_behaviors.d.ts +0 -38
- package/dist/types/src/trait_behaviors.d.ts.map +0 -1
- package/dist/types/src/virtual_node.d.ts +0 -10
- package/dist/types/src/virtual_node.d.ts.map +0 -1
- package/dist/types/tests/backend/domlike.test.d.ts +0 -2
- package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
- package/dist/types/tests/base/composed_backend.d.ts +0 -123
- package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
- package/dist/types/tests/base/env.d.ts +0 -30
- package/dist/types/tests/base/env.d.ts.map +0 -1
- package/dist/types/tests/base/match.d.ts +0 -9
- package/dist/types/tests/base/match.d.ts.map +0 -1
- package/dist/types/tests/core/backend.test.d.ts +0 -2
- package/dist/types/tests/core/backend.test.d.ts.map +0 -1
- package/dist/types/tests/core/behavior.test.d.ts +0 -2
- package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
- package/dist/types/tests/core/component_space.test.d.ts +0 -2
- package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
- package/dist/types/tests/core/data_update.test.d.ts +0 -2
- package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
- package/dist/types/tests/core/misc.test.d.ts +0 -2
- package/dist/types/tests/core/misc.test.d.ts.map +0 -1
- package/dist/types/tests/core/placeholder.test.d.ts +0 -2
- package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
- package/dist/types/tests/core/slot.test.d.ts +0 -2
- package/dist/types/tests/core/slot.test.d.ts.map +0 -1
- package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
- package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
- package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/event.test.d.ts +0 -2
- package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
- package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
- package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
- package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
- package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
- package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
- package/dist/types/tests/types/chaining.test.d.ts +0 -2
- package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
- package/dist/types/tests/types/createElement.test.d.ts +0 -2
- package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
- package/dist/types/tests/types/definition.test.d.ts +0 -2
- package/dist/types/tests/types/definition.test.d.ts.map +0 -1
- package/webpack.config.js +0 -275
- /package/src/backend/{mode.ts → shared.ts} +0 -0
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import * as glassEasel from '../../src'
|
|
2
2
|
|
|
3
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
-
const protocolMethod = (instance: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
5
|
-
const originalFn = descriptor.value as unknown as (...args: any[]) => any
|
|
6
|
-
descriptor.value = function (this: Context | Element, ...args: any[]) {
|
|
7
|
-
if (this._$currentMethod === null) this._$currentMethod = propertyKey
|
|
8
|
-
const ret: unknown = originalFn.apply(this, args)
|
|
9
|
-
this._$currentMethod = null
|
|
10
|
-
return ret
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
3
|
const enum ThrowOption {
|
|
15
4
|
StyleScopeNotFound,
|
|
16
5
|
StyleSheetNotFound,
|
|
@@ -28,7 +17,7 @@ export class Context implements glassEasel.composedBackend.Context {
|
|
|
28
17
|
private _$theme = 'light'
|
|
29
18
|
|
|
30
19
|
private _$styleSheetIdInc = 1
|
|
31
|
-
public _$styleScopes = new Set<number>()
|
|
20
|
+
public _$styleScopes = new Set<number>([0])
|
|
32
21
|
private _$styleSheetContents = new Map<string, unknown>()
|
|
33
22
|
|
|
34
23
|
public _$allElements: Node[] = []
|
|
@@ -46,82 +35,65 @@ export class Context implements glassEasel.composedBackend.Context {
|
|
|
46
35
|
options: glassEasel.EventOptions,
|
|
47
36
|
) => glassEasel.EventBubbleStatus) = null
|
|
48
37
|
|
|
49
|
-
public shouldThrows(when
|
|
50
|
-
if (when === undefined) return true
|
|
38
|
+
public shouldThrows(when: ThrowOption) {
|
|
51
39
|
if (this._$throwOn === true) return true
|
|
52
40
|
if (typeof this._$throwOn !== 'boolean' && this._$throwOn[when]) return true
|
|
53
41
|
return false
|
|
54
42
|
}
|
|
55
|
-
// eslint-disable-next-line class-methods-use-this
|
|
56
|
-
private throws(message: string, when?: ThrowOption) {
|
|
57
|
-
if (!this.shouldThrows(when)) return
|
|
58
|
-
const method = this._$currentMethod || 'unknownMethod'
|
|
59
|
-
this._$currentMethod = null
|
|
60
|
-
throw new Error(`During ComposedBackend.Context#${method}: ${message}`)
|
|
61
|
-
}
|
|
62
43
|
|
|
63
|
-
@protocolMethod
|
|
64
44
|
destroy(): void {
|
|
65
|
-
if (this._$destroyed)
|
|
45
|
+
if (this._$destroyed) throw new Error('destroyed twice')
|
|
66
46
|
this._$destroyed = true
|
|
67
47
|
if (this._$allElements.length !== 0) {
|
|
68
|
-
|
|
48
|
+
throw new Error('destroyed with elements not yet destroyed')
|
|
69
49
|
}
|
|
70
50
|
}
|
|
71
51
|
|
|
72
|
-
@protocolMethod
|
|
73
52
|
getWindowWidth(): number {
|
|
74
53
|
return this._$windowWidth
|
|
75
54
|
}
|
|
76
55
|
|
|
77
|
-
@protocolMethod
|
|
78
56
|
getWindowHeight(): number {
|
|
79
57
|
return this._$windowHeight
|
|
80
58
|
}
|
|
81
59
|
|
|
82
|
-
@protocolMethod
|
|
83
60
|
getDevicePixelRatio(): number {
|
|
84
61
|
return this._$devicePixelRatio
|
|
85
62
|
}
|
|
86
63
|
|
|
87
|
-
@protocolMethod
|
|
88
64
|
getTheme(): string {
|
|
89
65
|
return this._$theme
|
|
90
66
|
}
|
|
91
67
|
|
|
92
|
-
@protocolMethod
|
|
93
68
|
registerStyleSheetContent(path: string, content: unknown): void {
|
|
94
69
|
if (this._$styleSheetContents.has(path)) {
|
|
95
|
-
this.
|
|
96
|
-
`Style sheet with path "${path}" registered twice
|
|
97
|
-
|
|
98
|
-
)
|
|
70
|
+
if (this.shouldThrows(ThrowOption.StyleSheetDoubleRegistration)) {
|
|
71
|
+
throw new Error(`Style sheet with path "${path}" registered twice`)
|
|
72
|
+
}
|
|
99
73
|
}
|
|
100
74
|
this._$styleSheetContents.set(path, content)
|
|
101
75
|
}
|
|
102
76
|
|
|
103
|
-
@protocolMethod
|
|
104
77
|
appendStyleSheetPath(path: string, styleScope?: number): number {
|
|
105
78
|
const id = this._$styleSheetIdInc
|
|
106
79
|
this._$styleSheetIdInc += 1
|
|
107
80
|
this._$styleScopes.add(styleScope ?? 0)
|
|
108
81
|
if (!this._$styleSheetContents.has(path)) {
|
|
109
|
-
this.
|
|
110
|
-
`Style sheet added with path "${path}" not registered
|
|
111
|
-
|
|
112
|
-
)
|
|
82
|
+
if (this.shouldThrows(ThrowOption.StyleSheetNotRegistered)) {
|
|
83
|
+
throw new Error(`Style sheet added with path "${path}" not registered`)
|
|
84
|
+
}
|
|
113
85
|
}
|
|
114
86
|
return id
|
|
115
87
|
}
|
|
116
88
|
|
|
117
|
-
@protocolMethod
|
|
118
89
|
disableStyleSheet(index: number): void {
|
|
119
90
|
if (index >= this._$styleSheetIdInc) {
|
|
120
|
-
this.
|
|
91
|
+
if (this.shouldThrows(ThrowOption.StyleSheetNotFound)) {
|
|
92
|
+
throw new Error(`Style sheet with id "${index}" not exists`)
|
|
93
|
+
}
|
|
121
94
|
}
|
|
122
95
|
}
|
|
123
96
|
|
|
124
|
-
@protocolMethod
|
|
125
97
|
render(cb: (err: Error | null) => void): void {
|
|
126
98
|
if (this._$renderCallbacks) {
|
|
127
99
|
this._$renderCallbacks.push(cb)
|
|
@@ -141,27 +113,22 @@ export class Context implements glassEasel.composedBackend.Context {
|
|
|
141
113
|
this._$rootNode = rootNode
|
|
142
114
|
}
|
|
143
115
|
|
|
144
|
-
@protocolMethod
|
|
145
116
|
getRootNode(): Node {
|
|
146
117
|
return this._$rootNode
|
|
147
118
|
}
|
|
148
119
|
|
|
149
|
-
@protocolMethod
|
|
150
120
|
createElement(tagName: string, stylingName: string): Node {
|
|
151
121
|
return new Element(this, tagName, stylingName)
|
|
152
122
|
}
|
|
153
123
|
|
|
154
|
-
@protocolMethod
|
|
155
124
|
createTextNode(textContent: string): Node {
|
|
156
125
|
return new TextNode(this, textContent)
|
|
157
126
|
}
|
|
158
127
|
|
|
159
|
-
@protocolMethod
|
|
160
128
|
createFragment(): Node {
|
|
161
129
|
return new Fragment(this)
|
|
162
130
|
}
|
|
163
131
|
|
|
164
|
-
@protocolMethod
|
|
165
132
|
onEvent(
|
|
166
133
|
_listener: (
|
|
167
134
|
target: glassEasel.Element,
|
|
@@ -173,7 +140,6 @@ export class Context implements glassEasel.composedBackend.Context {
|
|
|
173
140
|
this._$eventEmitter = _listener
|
|
174
141
|
}
|
|
175
142
|
|
|
176
|
-
@protocolMethod
|
|
177
143
|
// eslint-disable-next-line class-methods-use-this
|
|
178
144
|
createMediaQueryObserver(
|
|
179
145
|
_status: glassEasel.backend.MediaQueryStatus,
|
|
@@ -201,10 +167,10 @@ const stringifyType = (v: unknown) => {
|
|
|
201
167
|
* https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
202
168
|
*/
|
|
203
169
|
const enum NODE_TYPE {
|
|
204
|
-
ELEMENT_NODE
|
|
205
|
-
TEXT_NODE
|
|
206
|
-
DOCUMENT_NODE
|
|
207
|
-
DOCUMENT_FRAGMENT_NODE
|
|
170
|
+
ELEMENT_NODE,
|
|
171
|
+
TEXT_NODE,
|
|
172
|
+
DOCUMENT_NODE,
|
|
173
|
+
DOCUMENT_FRAGMENT_NODE,
|
|
208
174
|
}
|
|
209
175
|
|
|
210
176
|
/** An element for empty backend implementation */
|
|
@@ -227,8 +193,11 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
227
193
|
|
|
228
194
|
private _$style = ''
|
|
229
195
|
private _$styleScope = 0
|
|
230
|
-
private _$
|
|
231
|
-
private _$
|
|
196
|
+
private _$extraStyleScope: number | undefined
|
|
197
|
+
private _$hostStyleScope: number | undefined
|
|
198
|
+
private _$classes: Array<[string, number | undefined]> | undefined
|
|
199
|
+
private _$attributes: Array<[string, unknown]> = []
|
|
200
|
+
private _$styleScopeManager: glassEasel.StyleScopeManager | undefined
|
|
232
201
|
|
|
233
202
|
constructor(ownerContext: Context) {
|
|
234
203
|
this._$ownerContext = ownerContext
|
|
@@ -236,126 +205,153 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
236
205
|
}
|
|
237
206
|
|
|
238
207
|
// eslint-disable-next-line class-methods-use-this
|
|
239
|
-
private throws(message: string, when?: ThrowOption) {
|
|
240
|
-
if (!this._$ownerContext.shouldThrows(when)) return
|
|
241
|
-
const method = this._$currentMethod || 'unknownMethod'
|
|
242
|
-
this._$currentMethod = null
|
|
243
|
-
throw new Error(`During ComposedBackend.Element#${method}: ${message}`)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
208
|
private assertFragment(frag: Node) {
|
|
247
|
-
if (!(frag instanceof Fragment))
|
|
209
|
+
if (!(frag instanceof Fragment))
|
|
210
|
+
throw new Error(`expect a fragment but got ${stringifyType(frag)}`)
|
|
248
211
|
if (frag.parentNode !== null) {
|
|
249
|
-
|
|
212
|
+
throw new Error('fragment should have no parent')
|
|
250
213
|
}
|
|
251
214
|
}
|
|
215
|
+
// eslint-disable-next-line class-methods-use-this
|
|
252
216
|
private assertDetached(child: Node) {
|
|
253
|
-
if (!(child instanceof Node))
|
|
254
|
-
|
|
217
|
+
if (!(child instanceof Node))
|
|
218
|
+
throw new Error(`expect an element but got ${stringifyType(child)}`)
|
|
219
|
+
if (child.parentNode !== null) throw new Error('newChild is not detached')
|
|
255
220
|
}
|
|
256
221
|
private assertChild(child: Node) {
|
|
257
|
-
if (!(child instanceof Node))
|
|
222
|
+
if (!(child instanceof Node))
|
|
223
|
+
throw new Error(`expect an element but got ${stringifyType(child)}`)
|
|
258
224
|
const index = this.childNodes.indexOf(child)
|
|
259
|
-
if (index === -1)
|
|
260
|
-
if (child.parentNode !== this)
|
|
225
|
+
if (index === -1) throw new Error('element is not a child of `this`')
|
|
226
|
+
if (child.parentNode !== this) throw new Error('element is not a child of `this`')
|
|
261
227
|
return index
|
|
262
228
|
}
|
|
263
229
|
private assertChildWithIndex(child: Node, index?: number) {
|
|
264
230
|
const actualIndex = this.assertChild(child)
|
|
265
231
|
const processedIndex = ensureNonNegativeInteger(index)
|
|
266
232
|
if (processedIndex !== undefined && processedIndex !== actualIndex) {
|
|
267
|
-
|
|
233
|
+
throw new Error(`index mismatched, expected ${actualIndex} but got ${processedIndex}`)
|
|
268
234
|
}
|
|
269
235
|
return actualIndex
|
|
270
236
|
}
|
|
271
237
|
private assertIndex(index: number) {
|
|
272
238
|
if (index >= this.childNodes.length) {
|
|
273
|
-
|
|
239
|
+
throw new Error(
|
|
274
240
|
`provided index is invalid, got ${index} but only ${this.childNodes.length} children exist`,
|
|
275
241
|
)
|
|
276
242
|
}
|
|
277
243
|
}
|
|
278
244
|
private assertDeleteCount(deleteCount: number, index: number) {
|
|
279
245
|
if (deleteCount + index > this.childNodes.length) {
|
|
280
|
-
|
|
246
|
+
throw new Error(
|
|
281
247
|
`try to remove ${deleteCount} children starting from ${index}, but there are only ${this.childNodes.length} children.`,
|
|
282
248
|
)
|
|
283
249
|
}
|
|
284
250
|
}
|
|
251
|
+
private assertStyleScope(styleScope: number | undefined) {
|
|
252
|
+
if (styleScope !== undefined && !this._$ownerContext._$styleScopes.has(styleScope)) {
|
|
253
|
+
if (this._$ownerContext.shouldThrows(ThrowOption.StyleScopeNotFound)) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
`set style scope to ${styleScope}, but its owner context do not have a style sheet with that scope`,
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
285
260
|
|
|
286
|
-
|
|
287
|
-
if (this instanceof
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
261
|
+
get tagName(): string {
|
|
262
|
+
if (this instanceof Element) {
|
|
263
|
+
return (
|
|
264
|
+
this._$logicalTagName === 'wx-x' ? this._$stylingTagName : this._$logicalTagName
|
|
265
|
+
).toUpperCase()
|
|
266
|
+
}
|
|
267
|
+
return ''
|
|
292
268
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
269
|
+
|
|
270
|
+
get innerHTML(): string {
|
|
271
|
+
if (this instanceof Element) {
|
|
272
|
+
return this.childNodes.map((child) => child.outerHTML).join('')
|
|
273
|
+
}
|
|
274
|
+
return this.textContent || ''
|
|
296
275
|
}
|
|
297
|
-
|
|
276
|
+
|
|
277
|
+
get outerHTML(): string {
|
|
298
278
|
const ret: string[] = []
|
|
299
|
-
const props: Record<string, string> = {}
|
|
300
|
-
Object.entries(this._$attributes).forEach(([key, value]) => {
|
|
301
|
-
props[key] = `${value as unknown as string}`
|
|
302
|
-
})
|
|
303
|
-
props.id = this.id
|
|
304
|
-
props.style = this._$style
|
|
305
|
-
props.class = this._$classes.map((c) => `${c[0]}$${c[1]}`).join(' ')
|
|
306
|
-
const propsStr = Object.entries(props)
|
|
307
|
-
.filter(([_, value]) => value.length > 0)
|
|
308
|
-
.map(([key, value]) => `${key}="${value}"`)
|
|
309
|
-
.join(' ')
|
|
310
|
-
ret.push(indent)
|
|
311
279
|
if (this instanceof Element) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
ret.push(' />\n')
|
|
319
|
-
} else {
|
|
320
|
-
ret.push('>\n')
|
|
321
|
-
if (this.textContent !== null) ret.push(`${indent} ${this.textContent}\n`)
|
|
322
|
-
this.childNodes.forEach((child) => {
|
|
323
|
-
ret.push(child.dumpToString(`${indent} `))
|
|
280
|
+
const props: Record<string, string> = {}
|
|
281
|
+
this._$attributes.forEach(([key]) => {
|
|
282
|
+
const value = this.getAttribute(key)
|
|
283
|
+
if (value !== null) {
|
|
284
|
+
props[key.toLowerCase()] = value
|
|
285
|
+
}
|
|
324
286
|
})
|
|
325
|
-
|
|
287
|
+
const tagName = this.tagName.toLowerCase()
|
|
288
|
+
ret.push(`<${tagName}`)
|
|
289
|
+
if (this.id) props.id = this.getAttribute('id')!
|
|
290
|
+
if (this._$style) props.style = this.getAttribute('style')!
|
|
291
|
+
if (this._$classes) props.class = this.getAttribute('class')!
|
|
292
|
+
const propsStr = Object.entries(props)
|
|
293
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
294
|
+
.join(' ')
|
|
295
|
+
if (propsStr.length > 0) ret.push(` ${propsStr}`)
|
|
296
|
+
ret.push(`>${this.innerHTML}</${tagName}>`)
|
|
297
|
+
} else {
|
|
298
|
+
ret.push(this.innerHTML)
|
|
326
299
|
}
|
|
327
300
|
return ret.join('')
|
|
328
301
|
}
|
|
329
302
|
|
|
330
|
-
|
|
303
|
+
getAttribute(name: string): string | null {
|
|
304
|
+
// eslint-disable-next-line no-param-reassign
|
|
305
|
+
name = name.toLowerCase()
|
|
306
|
+
if (name === 'id') return this.id
|
|
307
|
+
if (name === 'style') return this._$style
|
|
308
|
+
if (name === 'class')
|
|
309
|
+
return this._$classes
|
|
310
|
+
? this._$classes
|
|
311
|
+
.map(([name, styleScope]) => {
|
|
312
|
+
let prefix = ''
|
|
313
|
+
if (styleScope !== undefined) {
|
|
314
|
+
prefix = this._$styleScopeManager!.queryName(styleScope) || ''
|
|
315
|
+
}
|
|
316
|
+
return `${prefix ? `${prefix}--` : ''}${name}`
|
|
317
|
+
})
|
|
318
|
+
.join(' ')
|
|
319
|
+
: null
|
|
320
|
+
const attr = this._$attributes.find((attr) => attr[0] === name)
|
|
321
|
+
if (!attr) return null
|
|
322
|
+
const value = attr[1]
|
|
323
|
+
if (value === false) return null
|
|
324
|
+
return value === true || value === undefined || value === null ? '' : String(value)
|
|
325
|
+
}
|
|
326
|
+
|
|
331
327
|
release(): void {
|
|
332
|
-
if (this._$released)
|
|
328
|
+
if (this._$released) throw new Error('element released twice')
|
|
333
329
|
this._$released = true
|
|
334
330
|
const index = this._$ownerContext._$allElements.indexOf(this)
|
|
335
|
-
if (index === -1)
|
|
331
|
+
if (index === -1) throw new Error('element not found in its owner Context')
|
|
336
332
|
this._$ownerContext._$allElements.splice(index, 1)
|
|
337
333
|
}
|
|
338
334
|
|
|
339
|
-
@protocolMethod
|
|
340
335
|
associateValue(v: glassEasel.Element): void {
|
|
341
336
|
this.__wxElement = v
|
|
337
|
+
if (v.ownerShadowRoot) {
|
|
338
|
+
const ownerSpace = v.ownerShadowRoot.getHostNode()._$behavior.ownerSpace
|
|
339
|
+
this._$styleScopeManager = ownerSpace.styleScopeManager
|
|
340
|
+
}
|
|
342
341
|
}
|
|
343
342
|
|
|
344
|
-
@protocolMethod
|
|
345
343
|
appendChild(child: Node): void {
|
|
346
344
|
this.assertDetached(child)
|
|
347
345
|
this.childNodes.push(child)
|
|
348
346
|
child.parentNode = this
|
|
349
347
|
}
|
|
350
348
|
|
|
351
|
-
@protocolMethod
|
|
352
349
|
removeChild(child: Node, index?: number): void {
|
|
353
350
|
const actualIndex = this.assertChildWithIndex(child, index)
|
|
354
351
|
this.childNodes.splice(actualIndex, 1)
|
|
355
352
|
child.parentNode = null
|
|
356
353
|
}
|
|
357
354
|
|
|
358
|
-
@protocolMethod
|
|
359
355
|
insertBefore(child: Node, before: Node, index?: number): void {
|
|
360
356
|
this.assertDetached(child)
|
|
361
357
|
const processedIndex = ensureNonNegativeInteger(index)
|
|
@@ -376,7 +372,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
376
372
|
}
|
|
377
373
|
}
|
|
378
374
|
|
|
379
|
-
@protocolMethod
|
|
380
375
|
replaceChild(child: Node, oldChild: Node, index?: number): void {
|
|
381
376
|
this.assertDetached(child)
|
|
382
377
|
const processedIndex = ensureNonNegativeInteger(index)
|
|
@@ -401,7 +396,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
401
396
|
}
|
|
402
397
|
}
|
|
403
398
|
|
|
404
|
-
@protocolMethod
|
|
405
399
|
spliceBefore(before: Node, deleteCount: number, list: Node): void {
|
|
406
400
|
this.assertFragment(list)
|
|
407
401
|
const index = this.assertChild(before)
|
|
@@ -416,7 +410,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
416
410
|
})
|
|
417
411
|
}
|
|
418
412
|
|
|
419
|
-
@protocolMethod
|
|
420
413
|
spliceAppend(list: Node): void {
|
|
421
414
|
this.assertFragment(list)
|
|
422
415
|
this.childNodes.splice(this.childNodes.length, 0, ...list.childNodes)
|
|
@@ -426,7 +419,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
426
419
|
list.childNodes = []
|
|
427
420
|
}
|
|
428
421
|
|
|
429
|
-
@protocolMethod
|
|
430
422
|
spliceRemove(before: Node, deleteCount: number): void {
|
|
431
423
|
const index = this.assertChild(before)
|
|
432
424
|
this.assertDeleteCount(deleteCount, index)
|
|
@@ -436,62 +428,76 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
436
428
|
})
|
|
437
429
|
}
|
|
438
430
|
|
|
439
|
-
@protocolMethod
|
|
440
431
|
setId(id: string): void {
|
|
441
432
|
this.id = id
|
|
442
433
|
}
|
|
443
434
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
435
|
+
setStyleScope(
|
|
436
|
+
styleScope: number,
|
|
437
|
+
extraStyleScope: number | undefined,
|
|
438
|
+
hostStyleScope: number | undefined,
|
|
439
|
+
): void {
|
|
440
|
+
this.assertStyleScope(styleScope)
|
|
441
|
+
this.assertStyleScope(extraStyleScope)
|
|
442
|
+
this.assertStyleScope(hostStyleScope)
|
|
452
443
|
this._$styleScope = styleScope
|
|
444
|
+
this._$extraStyleScope = extraStyleScope
|
|
445
|
+
this._$hostStyleScope = hostStyleScope
|
|
453
446
|
}
|
|
454
447
|
|
|
455
|
-
@protocolMethod
|
|
456
448
|
setStyle(styleText: string): void {
|
|
457
449
|
this._$style = styleText
|
|
458
450
|
}
|
|
459
451
|
|
|
460
|
-
@protocolMethod
|
|
461
452
|
addClass(elementClass: string, styleScope?: number): void {
|
|
462
|
-
const scope = ensureNonNegativeInteger(styleScope)
|
|
453
|
+
const scope = ensureNonNegativeInteger(styleScope)
|
|
454
|
+
if (!this._$classes) this._$classes = []
|
|
463
455
|
const index = this._$classes.findIndex((c) => c[0] === elementClass && c[1] === scope)
|
|
464
456
|
if (index === -1) this._$classes.push([elementClass, scope])
|
|
465
457
|
}
|
|
466
458
|
|
|
467
|
-
@protocolMethod
|
|
468
459
|
removeClass(elementClass: string, styleScope?: number): void {
|
|
469
|
-
const scope = ensureNonNegativeInteger(styleScope)
|
|
460
|
+
const scope = ensureNonNegativeInteger(styleScope)
|
|
461
|
+
if (!this._$classes) return
|
|
470
462
|
const index = this._$classes.findIndex((c) => c[0] === elementClass && c[1] === scope)
|
|
471
463
|
if (index !== -1) this._$classes.splice(index, 1)
|
|
472
464
|
}
|
|
473
465
|
|
|
474
|
-
@protocolMethod
|
|
475
466
|
clearClasses(): void {
|
|
467
|
+
if (!this._$classes) return
|
|
476
468
|
this._$classes = []
|
|
477
469
|
}
|
|
478
470
|
|
|
479
|
-
@protocolMethod
|
|
480
471
|
setAttribute(name: string, value: unknown): void {
|
|
481
|
-
|
|
472
|
+
// eslint-disable-next-line no-param-reassign
|
|
473
|
+
name = name.toLowerCase()
|
|
474
|
+
const index = this._$attributes.findIndex((attr) => attr[0] === name)
|
|
475
|
+
if (value === false) {
|
|
476
|
+
if (index >= 0) {
|
|
477
|
+
this._$attributes.splice(index, 1)
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
if (index >= 0) {
|
|
481
|
+
this._$attributes[index]![1] = value
|
|
482
|
+
} else {
|
|
483
|
+
this._$attributes.push([name, value])
|
|
484
|
+
}
|
|
485
|
+
}
|
|
482
486
|
}
|
|
483
487
|
|
|
484
|
-
@protocolMethod
|
|
485
488
|
removeAttribute(name: string): void {
|
|
486
|
-
|
|
489
|
+
// eslint-disable-next-line no-param-reassign
|
|
490
|
+
name = name.toLowerCase()
|
|
491
|
+
const index = this._$attributes.findIndex((attr) => attr[0] === name)
|
|
492
|
+
if (index >= 0) {
|
|
493
|
+
this._$attributes.splice(index, 1)
|
|
494
|
+
}
|
|
487
495
|
}
|
|
488
496
|
|
|
489
|
-
@protocolMethod
|
|
490
497
|
setText(content: string): void {
|
|
491
498
|
this.textContent = content
|
|
492
499
|
}
|
|
493
500
|
|
|
494
|
-
@protocolMethod
|
|
495
501
|
// eslint-disable-next-line class-methods-use-this
|
|
496
502
|
getBoundingClientRect(cb: (res: glassEasel.backend.BoundingClientRect) => void): void {
|
|
497
503
|
setTimeout(() => {
|
|
@@ -504,7 +510,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
504
510
|
}, 0)
|
|
505
511
|
}
|
|
506
512
|
|
|
507
|
-
@protocolMethod
|
|
508
513
|
// eslint-disable-next-line class-methods-use-this
|
|
509
514
|
getScrollOffset(cb: (res: glassEasel.backend.ScrollOffset) => void): void {
|
|
510
515
|
setTimeout(() => {
|
|
@@ -517,13 +522,11 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
517
522
|
}, 0)
|
|
518
523
|
}
|
|
519
524
|
|
|
520
|
-
@protocolMethod
|
|
521
525
|
// eslint-disable-next-line class-methods-use-this
|
|
522
526
|
setListenerStats(_type: string, _capture: boolean, _mutLevel: glassEasel.EventMutLevel): void {
|
|
523
527
|
// empty
|
|
524
528
|
}
|
|
525
529
|
|
|
526
|
-
@protocolMethod
|
|
527
530
|
// eslint-disable-next-line class-methods-use-this
|
|
528
531
|
setModelBindingStat(
|
|
529
532
|
_attributeName: string,
|
|
@@ -532,7 +535,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
532
535
|
// empty
|
|
533
536
|
}
|
|
534
537
|
|
|
535
|
-
@protocolMethod
|
|
536
538
|
// eslint-disable-next-line class-methods-use-this
|
|
537
539
|
createIntersectionObserver(
|
|
538
540
|
_relativeElement: glassEasel.composedBackend.Element | null,
|
|
@@ -547,7 +549,6 @@ abstract class Node implements glassEasel.composedBackend.Element {
|
|
|
547
549
|
}
|
|
548
550
|
}
|
|
549
551
|
|
|
550
|
-
@protocolMethod
|
|
551
552
|
// eslint-disable-next-line class-methods-use-this
|
|
552
553
|
getContext(cb: (res: unknown) => void): void {
|
|
553
554
|
cb(null)
|
package/tests/base/env.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { TmplGroup } from 'glass-easel-template-compiler'
|
|
5
5
|
import * as glassEasel from '../../src'
|
|
6
6
|
import * as ComposedBackend from './composed_backend'
|
|
7
|
+
import * as ShadowBackend from './shadow_backend'
|
|
7
8
|
|
|
8
9
|
glassEasel.globalOptions.throwGlobalError = true
|
|
9
10
|
const warningThrow = (msg: string) => {
|
|
@@ -20,6 +21,20 @@ glassEasel.addGlobalWarningListener(warningThrow)
|
|
|
20
21
|
return `[GlassEaselTextNode ${glassEasel.dumpSingleElementToString(this)}]`
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
25
|
+
writable: true,
|
|
26
|
+
value: jest.fn().mockImplementation((query) => ({
|
|
27
|
+
matches: false,
|
|
28
|
+
media: query as unknown,
|
|
29
|
+
onchange: null,
|
|
30
|
+
addListener: jest.fn(), // Deprecated
|
|
31
|
+
removeListener: jest.fn(), // Deprecated
|
|
32
|
+
addEventListener: jest.fn(),
|
|
33
|
+
removeEventListener: jest.fn(),
|
|
34
|
+
dispatchEvent: jest.fn(),
|
|
35
|
+
})),
|
|
36
|
+
})
|
|
37
|
+
|
|
23
38
|
export const execWithWarn = <T>(expectCount: number, func: () => T): T => {
|
|
24
39
|
let count = 0
|
|
25
40
|
const warningListener = () => {
|
|
@@ -35,9 +50,30 @@ export const execWithWarn = <T>(expectCount: number, func: () => T): T => {
|
|
|
35
50
|
return ret
|
|
36
51
|
}
|
|
37
52
|
|
|
53
|
+
export const execWithError = <R>(func: () => R, ...errors: string[]): R | void => {
|
|
54
|
+
let count = 0
|
|
55
|
+
const errorListener = (err: unknown) => {
|
|
56
|
+
if (count >= errors.length) return true // will throw
|
|
57
|
+
expect(err).toBeInstanceOf(Error)
|
|
58
|
+
expect((err as Error).message).toBe(errors[count])
|
|
59
|
+
count += 1
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
glassEasel.addGlobalErrorListener(errorListener)
|
|
63
|
+
try {
|
|
64
|
+
return func()
|
|
65
|
+
} catch (e) {
|
|
66
|
+
errorListener(e)
|
|
67
|
+
return undefined
|
|
68
|
+
} finally {
|
|
69
|
+
glassEasel.removeGlobalErrorListener(errorListener)
|
|
70
|
+
expect(count).toBe(errors.length)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
38
74
|
type TemplateOptions = {
|
|
39
75
|
updateMode?: string
|
|
40
|
-
|
|
76
|
+
fallbackListenerOnNativeNode?: boolean
|
|
41
77
|
}
|
|
42
78
|
|
|
43
79
|
export const tmpl = (src: string, options?: TemplateOptions) => {
|
|
@@ -78,6 +114,43 @@ export const multiTmpl = (src: { [path: string]: string }, options?: TemplateOpt
|
|
|
78
114
|
}
|
|
79
115
|
}
|
|
80
116
|
|
|
81
|
-
export const domBackend = new glassEasel.
|
|
82
|
-
export const shadowBackend = new
|
|
117
|
+
export const domBackend = new glassEasel.CurrentWindowBackendContext()
|
|
118
|
+
export const shadowBackend = new ShadowBackend.Context()
|
|
83
119
|
export const composedBackend = new ComposedBackend.Context()
|
|
120
|
+
|
|
121
|
+
export const getCustomExternalTemplateEngine = (
|
|
122
|
+
createExternalShadowRoot: (comp: glassEasel.GeneralComponent) => glassEasel.ExternalShadowRoot,
|
|
123
|
+
) => {
|
|
124
|
+
class CustomExternalTemplateEngine implements glassEasel.templateEngine.Template {
|
|
125
|
+
static create() {
|
|
126
|
+
return new CustomExternalTemplateEngine()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// eslint-disable-next-line class-methods-use-this
|
|
130
|
+
createInstance(comp: glassEasel.GeneralComponent): glassEasel.templateEngine.TemplateInstance {
|
|
131
|
+
return new EmptyTemplateInstance(comp, createExternalShadowRoot(comp))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
class EmptyTemplateInstance implements glassEasel.templateEngine.TemplateInstance {
|
|
136
|
+
comp: glassEasel.GeneralComponent
|
|
137
|
+
shadowRoot: glassEasel.ExternalShadowRoot
|
|
138
|
+
|
|
139
|
+
constructor(comp: glassEasel.GeneralComponent, shadowRoot: glassEasel.ExternalShadowRoot) {
|
|
140
|
+
this.comp = comp
|
|
141
|
+
this.shadowRoot = shadowRoot
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// eslint-disable-next-line class-methods-use-this
|
|
145
|
+
initValues() {
|
|
146
|
+
// empty
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// eslint-disable-next-line class-methods-use-this
|
|
150
|
+
updateValues() {
|
|
151
|
+
// empty
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return CustomExternalTemplateEngine
|
|
156
|
+
}
|