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.
Files changed (197) hide show
  1. package/.eslintignore +4 -0
  2. package/dist/glass_easel.all.js +2 -2
  3. package/dist/glass_easel.all.js.map +1 -1
  4. package/dist/glass_easel.d.ts +2546 -0
  5. package/dist/glass_easel.domlike.global.js +2 -2
  6. package/dist/glass_easel.domlike.global.js.map +1 -1
  7. package/guide/zh_CN/appendix/backend_protocol.md +164 -74
  8. package/jest.unit.config.js +7 -4
  9. package/package.json +7 -5
  10. package/rollup.config.ts +101 -0
  11. package/src/backend/backend_protocol.ts +26 -345
  12. package/src/backend/composed_backend_protocol.ts +10 -264
  13. package/src/backend/current_window_backend_context.ts +478 -0
  14. package/src/backend/domlike_backend_protocol.ts +9 -498
  15. package/src/backend/empty_backend.ts +265 -0
  16. package/src/backend/empty_composed_backend.ts +245 -0
  17. package/src/backend/index.ts +18 -0
  18. package/src/backend/suggested_backend_protocol.ts +62 -11
  19. package/src/behavior.ts +131 -442
  20. package/src/class_list.ts +328 -222
  21. package/src/component.ts +349 -184
  22. package/src/component_params.ts +54 -25
  23. package/src/component_space.ts +36 -15
  24. package/src/data_path.ts +22 -34
  25. package/src/data_proxy.ts +334 -27
  26. package/src/devtool.ts +89 -0
  27. package/src/element.ts +667 -285
  28. package/src/element_iterator.ts +9 -4
  29. package/src/event.ts +39 -20
  30. package/src/external_shadow_tree.ts +2 -2
  31. package/src/func_arr.ts +55 -101
  32. package/src/global_options.ts +18 -42
  33. package/src/index.ts +72 -73
  34. package/src/mutation_observer.ts +10 -7
  35. package/src/native_node.ts +79 -35
  36. package/src/node.ts +23 -30
  37. package/src/relation.ts +101 -12
  38. package/src/render.ts +5 -3
  39. package/src/selector.ts +9 -7
  40. package/src/shadow_root.ts +96 -240
  41. package/src/template_engine.ts +10 -7
  42. package/src/text_node.ts +43 -19
  43. package/src/tmpl/index.ts +38 -30
  44. package/src/tmpl/native_rendering.ts +14 -21
  45. package/src/tmpl/proc_gen_wrapper.ts +189 -151
  46. package/src/tmpl/proc_gen_wrapper_dom.ts +10 -8
  47. package/src/tmpl/range_list_diff.ts +30 -9
  48. package/src/trait_behaviors.ts +1 -1
  49. package/src/type_symbol.ts +36 -0
  50. package/src/virtual_node.ts +26 -13
  51. package/src/warning.ts +119 -0
  52. package/tests/base/composed_backend.ts +143 -142
  53. package/tests/base/env.ts +76 -3
  54. package/tests/base/match.ts +24 -22
  55. package/tests/base/shadow_backend.ts +917 -0
  56. package/tests/core/backend.test.ts +53 -1
  57. package/tests/core/behavior.test.ts +1 -1
  58. package/tests/core/data_update.test.ts +135 -0
  59. package/tests/core/misc.test.ts +91 -21
  60. package/tests/core/placeholder.test.ts +66 -25
  61. package/tests/core/slot.test.ts +161 -23
  62. package/tests/legacy/component.test.js +152 -78
  63. package/tests/legacy/data_path.test.js +19 -19
  64. package/tests/legacy/data_proxy.test.js +14 -7
  65. package/tests/legacy/external.test.js +8 -8
  66. package/tests/legacy/mutation_observer.test.js +7 -5
  67. package/tests/legacy/slot.test.js +2 -3
  68. package/tests/legacy/virtual.test.js +258 -25
  69. package/tests/tmpl/binding_map.test.ts +201 -195
  70. package/tests/tmpl/event.test.ts +138 -23
  71. package/tests/tmpl/expression.test.ts +15 -15
  72. package/tests/tmpl/lvalue.test.ts +101 -0
  73. package/tests/tmpl/structure.test.ts +486 -43
  74. package/tests/types/chaining.test.ts +27 -30
  75. package/tests/types/createElement.test.ts +5 -4
  76. package/tests/types/definition.test.ts +11 -14
  77. package/tsconfig.json +1 -3
  78. package/dist/glass_easel.all.d.ts +0 -1
  79. package/dist/glass_easel.domlike.global.d.ts +0 -1
  80. package/dist/index.d.ts +0 -1
  81. package/dist/index.js +0 -1
  82. package/dist/types/src/backend/backend_protocol.d.ts +0 -141
  83. package/dist/types/src/backend/backend_protocol.d.ts.map +0 -1
  84. package/dist/types/src/backend/composed_backend_protocol.d.ts +0 -102
  85. package/dist/types/src/backend/composed_backend_protocol.d.ts.map +0 -1
  86. package/dist/types/src/backend/domlike_backend_protocol.d.ts +0 -100
  87. package/dist/types/src/backend/domlike_backend_protocol.d.ts.map +0 -1
  88. package/dist/types/src/backend/mode.d.ts +0 -65
  89. package/dist/types/src/backend/mode.d.ts.map +0 -1
  90. package/dist/types/src/backend/suggested_backend_protocol.d.ts +0 -30
  91. package/dist/types/src/backend/suggested_backend_protocol.d.ts.map +0 -1
  92. package/dist/types/src/behavior.d.ts +0 -434
  93. package/dist/types/src/behavior.d.ts.map +0 -1
  94. package/dist/types/src/class_list.d.ts +0 -83
  95. package/dist/types/src/class_list.d.ts.map +0 -1
  96. package/dist/types/src/component.d.ts +0 -325
  97. package/dist/types/src/component.d.ts.map +0 -1
  98. package/dist/types/src/component_params.d.ts +0 -236
  99. package/dist/types/src/component_params.d.ts.map +0 -1
  100. package/dist/types/src/component_space.d.ts +0 -211
  101. package/dist/types/src/component_space.d.ts.map +0 -1
  102. package/dist/types/src/data_path.d.ts +0 -5
  103. package/dist/types/src/data_path.d.ts.map +0 -1
  104. package/dist/types/src/data_proxy.d.ts +0 -107
  105. package/dist/types/src/data_proxy.d.ts.map +0 -1
  106. package/dist/types/src/data_utils.d.ts +0 -3
  107. package/dist/types/src/data_utils.d.ts.map +0 -1
  108. package/dist/types/src/element.d.ts +0 -365
  109. package/dist/types/src/element.d.ts.map +0 -1
  110. package/dist/types/src/element_iterator.d.ts +0 -43
  111. package/dist/types/src/element_iterator.d.ts.map +0 -1
  112. package/dist/types/src/event.d.ts +0 -105
  113. package/dist/types/src/event.d.ts.map +0 -1
  114. package/dist/types/src/external_shadow_tree.d.ts +0 -20
  115. package/dist/types/src/external_shadow_tree.d.ts.map +0 -1
  116. package/dist/types/src/func_arr.d.ts +0 -39
  117. package/dist/types/src/func_arr.d.ts.map +0 -1
  118. package/dist/types/src/global_options.d.ts +0 -120
  119. package/dist/types/src/global_options.d.ts.map +0 -1
  120. package/dist/types/src/index.d.ts +0 -43
  121. package/dist/types/src/index.d.ts.map +0 -1
  122. package/dist/types/src/mutation_observer.d.ts +0 -79
  123. package/dist/types/src/mutation_observer.d.ts.map +0 -1
  124. package/dist/types/src/native_node.d.ts +0 -11
  125. package/dist/types/src/native_node.d.ts.map +0 -1
  126. package/dist/types/src/node.d.ts +0 -48
  127. package/dist/types/src/node.d.ts.map +0 -1
  128. package/dist/types/src/relation.d.ts +0 -46
  129. package/dist/types/src/relation.d.ts.map +0 -1
  130. package/dist/types/src/render.d.ts +0 -3
  131. package/dist/types/src/render.d.ts.map +0 -1
  132. package/dist/types/src/selector.d.ts +0 -32
  133. package/dist/types/src/selector.d.ts.map +0 -1
  134. package/dist/types/src/shadow_root.d.ts +0 -174
  135. package/dist/types/src/shadow_root.d.ts.map +0 -1
  136. package/dist/types/src/template_engine.d.ts +0 -56
  137. package/dist/types/src/template_engine.d.ts.map +0 -1
  138. package/dist/types/src/text_node.d.ts +0 -44
  139. package/dist/types/src/text_node.d.ts.map +0 -1
  140. package/dist/types/src/tmpl/index.d.ts +0 -19
  141. package/dist/types/src/tmpl/index.d.ts.map +0 -1
  142. package/dist/types/src/tmpl/native_rendering.d.ts +0 -45
  143. package/dist/types/src/tmpl/native_rendering.d.ts.map +0 -1
  144. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts +0 -89
  145. package/dist/types/src/tmpl/proc_gen_wrapper.d.ts.map +0 -1
  146. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts +0 -50
  147. package/dist/types/src/tmpl/proc_gen_wrapper_dom.d.ts.map +0 -1
  148. package/dist/types/src/tmpl/range_list_diff.d.ts +0 -19
  149. package/dist/types/src/tmpl/range_list_diff.d.ts.map +0 -1
  150. package/dist/types/src/trait_behaviors.d.ts +0 -38
  151. package/dist/types/src/trait_behaviors.d.ts.map +0 -1
  152. package/dist/types/src/virtual_node.d.ts +0 -10
  153. package/dist/types/src/virtual_node.d.ts.map +0 -1
  154. package/dist/types/tests/backend/domlike.test.d.ts +0 -2
  155. package/dist/types/tests/backend/domlike.test.d.ts.map +0 -1
  156. package/dist/types/tests/base/composed_backend.d.ts +0 -123
  157. package/dist/types/tests/base/composed_backend.d.ts.map +0 -1
  158. package/dist/types/tests/base/env.d.ts +0 -30
  159. package/dist/types/tests/base/env.d.ts.map +0 -1
  160. package/dist/types/tests/base/match.d.ts +0 -9
  161. package/dist/types/tests/base/match.d.ts.map +0 -1
  162. package/dist/types/tests/core/backend.test.d.ts +0 -2
  163. package/dist/types/tests/core/backend.test.d.ts.map +0 -1
  164. package/dist/types/tests/core/behavior.test.d.ts +0 -2
  165. package/dist/types/tests/core/behavior.test.d.ts.map +0 -1
  166. package/dist/types/tests/core/component_space.test.d.ts +0 -2
  167. package/dist/types/tests/core/component_space.test.d.ts.map +0 -1
  168. package/dist/types/tests/core/data_update.test.d.ts +0 -2
  169. package/dist/types/tests/core/data_update.test.d.ts.map +0 -1
  170. package/dist/types/tests/core/misc.test.d.ts +0 -2
  171. package/dist/types/tests/core/misc.test.d.ts.map +0 -1
  172. package/dist/types/tests/core/placeholder.test.d.ts +0 -2
  173. package/dist/types/tests/core/placeholder.test.d.ts.map +0 -1
  174. package/dist/types/tests/core/slot.test.d.ts +0 -2
  175. package/dist/types/tests/core/slot.test.d.ts.map +0 -1
  176. package/dist/types/tests/core/trait_behaviors.test.d.ts +0 -2
  177. package/dist/types/tests/core/trait_behaviors.test.d.ts.map +0 -1
  178. package/dist/types/tests/tmpl/binding_map.test.d.ts +0 -2
  179. package/dist/types/tests/tmpl/binding_map.test.d.ts.map +0 -1
  180. package/dist/types/tests/tmpl/event.test.d.ts +0 -2
  181. package/dist/types/tests/tmpl/event.test.d.ts.map +0 -1
  182. package/dist/types/tests/tmpl/expression.test.d.ts +0 -2
  183. package/dist/types/tests/tmpl/expression.test.d.ts.map +0 -1
  184. package/dist/types/tests/tmpl/lvalue.test.d.ts +0 -2
  185. package/dist/types/tests/tmpl/lvalue.test.d.ts.map +0 -1
  186. package/dist/types/tests/tmpl/native_rendering.test.d.ts +0 -2
  187. package/dist/types/tests/tmpl/native_rendering.test.d.ts.map +0 -1
  188. package/dist/types/tests/tmpl/structure.test.d.ts +0 -2
  189. package/dist/types/tests/tmpl/structure.test.d.ts.map +0 -1
  190. package/dist/types/tests/types/chaining.test.d.ts +0 -2
  191. package/dist/types/tests/types/chaining.test.d.ts.map +0 -1
  192. package/dist/types/tests/types/createElement.test.d.ts +0 -2
  193. package/dist/types/tests/types/createElement.test.d.ts.map +0 -1
  194. package/dist/types/tests/types/definition.test.d.ts +0 -2
  195. package/dist/types/tests/types/definition.test.d.ts.map +0 -1
  196. package/webpack.config.js +0 -275
  197. /package/src/backend/{mode.ts → shared.ts} +0 -0
@@ -1,19 +1,9 @@
1
- /* eslint-disable class-methods-use-this */
2
- /* global window, document */
1
+ import { type Element as GlassEaselElement } from '../element'
2
+ import { type EventBubbleStatus, type EventOptions, type MutLevel } from '../event'
3
+ import { type BackendMode } from './shared'
4
+ import type * as suggestedBackend from './suggested_backend_protocol'
3
5
 
4
- import { EventOptions, EventBubbleStatus, MutLevel } from '../event'
5
- import { safeCallback, triggerWarning } from '../func_arr'
6
- import {
7
- BackendMode,
8
- BoundingClientRect,
9
- Observer,
10
- MediaQueryStatus,
11
- IntersectionStatus,
12
- } from './mode'
13
- import { Element as GlassEaselElement } from '../element'
14
- import * as suggestedBackend from './suggested_backend_protocol'
15
-
16
- export interface Context extends Partial<suggestedBackend.Context> {
6
+ export interface Context extends Partial<suggestedBackend.ContextForDomLike<Element>> {
17
7
  mode: BackendMode.Domlike
18
8
  destroy(): void
19
9
  getWindowWidth(): number
@@ -33,11 +23,11 @@ export interface Context extends Partial<suggestedBackend.Context> {
33
23
  associateValue(element: Element, value: GlassEaselElement): void
34
24
  onEvent(
35
25
  listener: (
36
- target: unknown,
26
+ target: GlassEaselElement,
37
27
  type: string,
38
28
  detail: unknown,
39
29
  options: EventOptions,
40
- ) => EventBubbleStatus,
30
+ ) => EventBubbleStatus | void,
41
31
  ): void
42
32
  setListenerStats(element: Element, type: string, capture: boolean, mutLevel: MutLevel): void
43
33
  setModelBindingStat(
@@ -45,24 +35,13 @@ export interface Context extends Partial<suggestedBackend.Context> {
45
35
  attributeName: string,
46
36
  listener: ((newValue: unknown) => void) | null,
47
37
  ): void
48
- createIntersectionObserver(
49
- targetElement: Element,
50
- relativeElement: Element | null,
51
- relativeElementMargin: string,
52
- thresholds: number[],
53
- listener: (res: IntersectionStatus) => void,
54
- ): Observer
55
- createMediaQueryObserver(
56
- status: MediaQueryStatus,
57
- listener: (res: { matches: boolean }) => void,
58
- ): Observer
59
- getContext(element: Element, cb: (res: unknown) => void): void
60
38
  }
61
39
 
62
- export interface Element extends Partial<suggestedBackend.Element> {
40
+ export interface Element extends Partial<suggestedBackend.ElementForDomLike> {
63
41
  _$wxArgs?: {
64
42
  modelListeners: { [name: string]: ((newValue: unknown) => void) | null }
65
43
  }
44
+ __wxElement?: GlassEaselElement
66
45
  appendChild(child: Element): void
67
46
  removeChild(child: Element, index?: number): void
68
47
  insertBefore(child: Element, before?: Element, index?: number): void
@@ -79,12 +58,6 @@ export interface Element extends Partial<suggestedBackend.Element> {
79
58
  nextSibling: Element | undefined
80
59
  childNodes: Element[]
81
60
  parentNode: Element | null
82
- getBoundingClientRect(): BoundingClientRect
83
- scrollLeft: number
84
- scrollTop: number
85
- scrollWidth: number
86
- scrollHeight: number
87
- __wxElement?: GlassEaselElement
88
61
  addEventListener<K extends keyof HTMLElementEventMap>(
89
62
  type: K,
90
63
  listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => unknown,
@@ -96,465 +69,3 @@ export interface Element extends Partial<suggestedBackend.Element> {
96
69
  options?: boolean | AddEventListenerOptions,
97
70
  ): void
98
71
  }
99
-
100
- const DELEGATE_EVENTS = [
101
- 'touchstart',
102
- 'touchmove',
103
- 'touchend',
104
- 'touchcancel',
105
- 'mousedown',
106
- 'mousemove',
107
- 'mouseout',
108
- 'mouseover',
109
- 'mouseup',
110
- 'click',
111
- ]
112
-
113
- export class CurrentWindowBackendContext implements Context {
114
- mode: BackendMode.Domlike = BackendMode.Domlike
115
- document = document as unknown as {
116
- createElement(tagName: string): Element
117
- createTextNode(content: string): Element
118
- createDocumentFragment(): Element
119
- }
120
- private _$styleSheets: HTMLElement[] = []
121
- private _$styleSheetRegistry = Object.create(null) as { [path: string]: string }
122
- private _$delegatedEventListeners = Object.create(null) as Record<string, true>
123
- private _$elementEventListeners = new WeakMap<Element, Record<string, true>>()
124
- private _$elementCaptureEventListeners = new WeakMap<Element, Record<string, true>>()
125
- private _$triggedEvents = new WeakSet<Event>()
126
- private _$eventListener?: (
127
- target: any,
128
- type: string,
129
- detail: any,
130
- options: EventOptions,
131
- ) => EventBubbleStatus | void
132
-
133
- destroy() {
134
- /* empty */
135
- }
136
-
137
- getWindowWidth(): number {
138
- return document.documentElement.clientWidth
139
- }
140
-
141
- getWindowHeight(): number {
142
- return document.documentElement.clientHeight
143
- }
144
-
145
- getDevicePixelRatio(): number {
146
- return window.devicePixelRatio
147
- }
148
-
149
- getTheme(): string {
150
- return 'light'
151
- }
152
-
153
- registerStyleSheetContent(path: string, content: unknown): void {
154
- this._$styleSheetRegistry[path] = String(content)
155
- }
156
-
157
- appendStyleSheetPath(path: string, styleScope?: number): number {
158
- const styleText = this._$styleSheetRegistry[path]
159
- if (styleText === undefined) throw new Error(`No style sheet registry "${path}"`)
160
- const s = document.createElement('style')
161
- s.innerText = styleText
162
- if (styleScope !== undefined) s.setAttribute('wx-style-scope', String(styleScope))
163
- document.head.appendChild(s)
164
- const id = this._$styleSheets.length
165
- this._$styleSheets.push(s)
166
- return id
167
- }
168
-
169
- disableStyleSheet(index: number) {
170
- const ss = this._$styleSheets[index]
171
- if (ss) document.head.removeChild(ss)
172
- }
173
-
174
- render(cb: (err: Error | null) => void) {
175
- window.requestAnimationFrame(() => {
176
- safeCallback('Render Callback', cb, this, [null])
177
- })
178
- }
179
-
180
- getRootNode(): Element {
181
- return document.body as unknown as Element
182
- }
183
-
184
- associateValue(element: Element, value: GlassEaselElement): void {
185
- element.__wxElement = value
186
- }
187
-
188
- onEvent(
189
- listener: (
190
- target: any,
191
- type: string,
192
- detail: any,
193
- options: EventOptions,
194
- ) => EventBubbleStatus | void,
195
- ) {
196
- if (!this._$eventListener) {
197
- this._$initEvent()
198
- }
199
- this._$eventListener = listener
200
- }
201
-
202
- private _$getEventDetail(ev: Event) {
203
- const detail: { [key: string]: unknown } = {}
204
- let e: Event = ev
205
- while (Object.getPrototypeOf(e) !== Event.prototype) {
206
- const keys = Object.keys(e)
207
- for (let i = 0; i < keys.length; i += 1) {
208
- const key = keys[i]!
209
- if (typeof (ev as unknown as { [key: string]: unknown })[key] === 'function') continue
210
- detail[key] = (ev as unknown as { [key: string]: unknown })[key]
211
- }
212
- e = Object.getPrototypeOf(e) as Event
213
- }
214
- return detail
215
- }
216
-
217
- private _$trigger(ev: Event, type: string, detail: unknown, bubbles: boolean, composed: boolean) {
218
- if (!this._$eventListener || !ev.target) return
219
-
220
- let t: Element | null = ev.target as any as Element
221
- while (t && !t.__wxElement) t = t.parentNode
222
- if (!t) return
223
-
224
- const bubbleStatus = this._$eventListener(t.__wxElement!, type, detail, {
225
- originalEvent: ev,
226
- bubbles,
227
- composed,
228
- capturePhase: true,
229
- })
230
- if (bubbleStatus === EventBubbleStatus.NoDefault) {
231
- ev.preventDefault()
232
- }
233
- }
234
-
235
- private _$initEvent() {
236
- const TAP_DIST = 10
237
-
238
- const possibleTaps = Object.create(null) as { [id: number]: { x: number; y: number } }
239
- const SIMULATED_MOUSE_ID = -1
240
- let disableMouseEvents = false
241
-
242
- const handleTapStart = (
243
- _ev: Event,
244
- t: { identifier: number; clientX: number; clientY: number },
245
- ) => {
246
- possibleTaps[t.identifier] = {
247
- x: t.clientX,
248
- y: t.clientY,
249
- }
250
- }
251
-
252
- const handleTapMove = (
253
- ev: Event,
254
- t: { identifier: number; clientX: number; clientY: number },
255
- ) => {
256
- const id = t.identifier
257
- if (possibleTaps[id]) {
258
- const u = possibleTaps[id]!
259
- if (Math.abs(u.x - t.clientX) > TAP_DIST || Math.abs(u.y - t.clientY) > TAP_DIST) {
260
- delete possibleTaps[id]
261
- this._$trigger(ev, 'canceltap', u, true, true)
262
- }
263
- }
264
- }
265
-
266
- const handleTapEnd = (
267
- ev: Event,
268
- t: { identifier: number; clientX: number; clientY: number },
269
- ) => {
270
- const id = t.identifier
271
- if (possibleTaps[id]) {
272
- const u = possibleTaps[id]!
273
- delete possibleTaps[id]
274
- if (Math.abs(u.x - t.clientX) > TAP_DIST || Math.abs(u.y - t.clientY) > TAP_DIST) {
275
- this._$trigger(ev, 'canceltap', u, true, true)
276
- } else {
277
- this._$trigger(ev, 'tap', u, true, true)
278
- }
279
- }
280
- }
281
-
282
- const handleTapCancel = (
283
- ev: Event,
284
- t: { identifier: number; clientX: number; clientY: number },
285
- ) => {
286
- const id = t.identifier
287
- if (possibleTaps[id]) {
288
- const u = possibleTaps[id]!
289
- delete possibleTaps[id]
290
- this._$trigger(ev, 'canceltap', u, true, true)
291
- }
292
- }
293
-
294
- document.body.addEventListener(
295
- 'touchstart',
296
- (ev) => {
297
- this._$trigger(ev, 'touchstart', this._$getEventDetail(ev), ev.bubbles, ev.composed)
298
- disableMouseEvents = true
299
- const changedTouches = ev.changedTouches
300
- for (let i = 0; i < changedTouches.length; i += 1) {
301
- handleTapStart(ev, changedTouches[i]!)
302
- }
303
- },
304
- { capture: true },
305
- )
306
- document.body.addEventListener(
307
- 'touchmove',
308
- (ev) => {
309
- this._$trigger(ev, 'touchmove', this._$getEventDetail(ev), ev.bubbles, ev.composed)
310
- const changedTouches = ev.changedTouches
311
- for (let i = 0; i < changedTouches.length; i += 1) {
312
- handleTapMove(ev, changedTouches[i]!)
313
- }
314
- },
315
- { capture: true },
316
- )
317
- document.body.addEventListener(
318
- 'touchend',
319
- (ev) => {
320
- this._$trigger(ev, 'touchend', this._$getEventDetail(ev), ev.bubbles, ev.composed)
321
- const changedTouches = ev.changedTouches
322
- for (let i = 0; i < changedTouches.length; i += 1) {
323
- handleTapEnd(ev, changedTouches[i]!)
324
- }
325
- },
326
- { capture: true },
327
- )
328
- document.body.addEventListener(
329
- 'touchcancel',
330
- (ev) => {
331
- this._$trigger(ev, 'touchcancel', this._$getEventDetail(ev), ev.bubbles, ev.composed)
332
- const changedTouches = ev.changedTouches
333
- for (let i = 0; i < changedTouches.length; i += 1) {
334
- handleTapCancel(ev, changedTouches[i]!)
335
- }
336
- },
337
- { capture: true },
338
- )
339
- document.body.addEventListener(
340
- 'mousedown',
341
- (ev) => {
342
- this._$trigger(ev, 'mousedown', this._$getEventDetail(ev), ev.bubbles, ev.composed)
343
- if (disableMouseEvents) return
344
- handleTapStart(ev, {
345
- identifier: SIMULATED_MOUSE_ID,
346
- clientX: ev.clientX,
347
- clientY: ev.clientY,
348
- })
349
- },
350
- { capture: true },
351
- )
352
- document.body.addEventListener(
353
- 'mousemove',
354
- (ev) => {
355
- this._$trigger(ev, 'mousemove', this._$getEventDetail(ev), ev.bubbles, ev.composed)
356
- if (disableMouseEvents) return
357
- handleTapMove(ev, {
358
- identifier: SIMULATED_MOUSE_ID,
359
- clientX: ev.clientX,
360
- clientY: ev.clientY,
361
- })
362
- },
363
- { capture: true },
364
- )
365
- document.body.addEventListener(
366
- 'mouseup',
367
- (ev) => {
368
- this._$trigger(ev, 'mouseup', this._$getEventDetail(ev), ev.bubbles, ev.composed)
369
- if (disableMouseEvents) return
370
- handleTapEnd(ev, {
371
- identifier: SIMULATED_MOUSE_ID,
372
- clientX: ev.clientX,
373
- clientY: ev.clientY,
374
- })
375
- },
376
- { capture: true },
377
- )
378
- const listeners = this._$delegatedEventListeners
379
- listeners.touchstart = true
380
- listeners.touchmove = true
381
- listeners.touchend = true
382
- listeners.mousedown = true
383
- listeners.mousemove = true
384
- listeners.mouseup = true
385
- }
386
-
387
- setListenerStats(element: Element, type: string, capture: boolean, mutLevel: MutLevel): void {
388
- // for non-passive events,
389
- // the default-prevented status can also be found in `EventBubbleStatus` ,
390
- // so there is nothing to do with non-passive events.
391
- if (!element) return
392
-
393
- const shouldDelegate = DELEGATE_EVENTS.includes(type)
394
- const defaultPrevented = mutLevel === MutLevel.Final
395
-
396
- if (shouldDelegate) {
397
- if (this._$delegatedEventListeners[type]) return
398
- this._$delegatedEventListeners[type] = true
399
-
400
- document.body.addEventListener(
401
- type,
402
- (ev) => {
403
- if (defaultPrevented) ev.preventDefault()
404
- this._$trigger(ev, type, this._$getEventDetail(ev), ev.bubbles, ev.composed)
405
- },
406
- { capture: true },
407
- )
408
- return
409
- }
410
-
411
- const elementEventListeners = capture
412
- ? this._$elementCaptureEventListeners
413
- : this._$elementEventListeners
414
- if (!elementEventListeners.has(element)) elementEventListeners.set(element, Object.create(null))
415
- const listeners = elementEventListeners.get(element)!
416
- if (listeners[type]) return
417
- listeners[type] = true
418
-
419
- element.addEventListener(type, (ev) => {
420
- if (this._$triggedEvents.has(ev)) return
421
- this._$triggedEvents.add(ev)
422
- if (defaultPrevented) ev.preventDefault()
423
- this._$trigger(ev, type, this._$getEventDetail(ev), ev.bubbles, ev.composed)
424
- })
425
- }
426
-
427
- setModelBindingStat(
428
- element: Element,
429
- attributeName: string,
430
- listener: ((newValue: unknown) => void) | null,
431
- ): void {
432
- const updateEventListener = (evName: string, valueFn: () => void) => {
433
- if (!element._$wxArgs) {
434
- element._$wxArgs = {
435
- modelListeners: Object.create(null) as {
436
- [name: string]: ((newValue: unknown) => void) | null
437
- },
438
- }
439
- }
440
- if (element._$wxArgs.modelListeners[attributeName] === undefined) {
441
- if (!listener) return
442
- element._$wxArgs.modelListeners[attributeName] = listener
443
- element.addEventListener(evName, () => {
444
- const listener = element._$wxArgs?.modelListeners[attributeName]
445
- listener?.(valueFn())
446
- })
447
- }
448
- element._$wxArgs.modelListeners[attributeName] = listener
449
- }
450
- const tagName = element.tagName
451
- let valid = false
452
- if (tagName === 'INPUT') {
453
- const elem = element as unknown as HTMLInputElement
454
- const type = elem.type
455
- if (type === 'checkbox') {
456
- if (attributeName === 'checked') {
457
- valid = true
458
- updateEventListener('change', () => elem.checked)
459
- }
460
- } else if (type === 'radio') {
461
- if (attributeName === 'checked') {
462
- valid = true
463
- updateEventListener('change', () => elem.checked)
464
- }
465
- } else {
466
- if (attributeName === 'value') {
467
- valid = true
468
- updateEventListener('input', () => elem.value)
469
- }
470
- }
471
- } else if (tagName === 'TEXTAREA') {
472
- const elem = element as unknown as HTMLTextAreaElement
473
- if (attributeName === 'value') {
474
- valid = true
475
- updateEventListener('input', () => elem.value)
476
- }
477
- } else if (tagName === 'SELECT') {
478
- const elem = element as unknown as HTMLSelectElement
479
- if (attributeName === 'value') {
480
- valid = true
481
- updateEventListener('change', () => elem.value)
482
- }
483
- }
484
- if (!valid) {
485
- triggerWarning(
486
- `unsupported model binding on "${attributeName}" of "${tagName.toLowerCase()}" element.`,
487
- )
488
- }
489
- }
490
-
491
- createIntersectionObserver(
492
- targetElement: Element,
493
- relativeElement: Element | null,
494
- relativeElementMargin: string,
495
- thresholds: number[],
496
- listener: (res: IntersectionStatus) => void,
497
- ): Observer {
498
- const observer = new IntersectionObserver(
499
- (info) => {
500
- info.forEach((entry) => {
501
- listener({
502
- intersectionRatio: entry.intersectionRatio,
503
- boundingClientRect: entry.boundingClientRect,
504
- intersectionRect: entry.intersectionRect,
505
- relativeRect: entry.rootBounds!,
506
- time: entry.time,
507
- })
508
- })
509
- },
510
- {
511
- root: relativeElement as unknown as HTMLElement,
512
- rootMargin: relativeElementMargin,
513
- threshold: thresholds,
514
- },
515
- )
516
- observer.observe(targetElement as unknown as HTMLElement)
517
- return {
518
- disconnect() {
519
- observer.disconnect()
520
- },
521
- }
522
- }
523
-
524
- createMediaQueryObserver(
525
- status: MediaQueryStatus,
526
- listener: (res: { matches: boolean }) => void,
527
- ): Observer {
528
- const calcMatches = () => {
529
- const width = document.documentElement.clientWidth
530
- const height = document.documentElement.clientHeight
531
- if (status.width !== undefined && width !== status.width) return false
532
- if (status.maxWidth !== undefined && width > status.maxWidth) return false
533
- if (status.minWidth !== undefined && width < status.minWidth) return false
534
- if (status.width !== undefined && height !== status.height) return false
535
- if (status.maxHeight !== undefined && height > status.maxHeight) return false
536
- if (status.minHeight !== undefined && height < status.minHeight) return false
537
- const orientation = width > height ? 'landscape' : 'portrait'
538
- if (orientation !== status.orientation) return false
539
- return true
540
- }
541
- let curMatches: boolean | null = null
542
- const listenerFunc = () => {
543
- const matches = calcMatches()
544
- if (curMatches === matches) return
545
- curMatches = matches
546
- listener({ matches })
547
- }
548
- setTimeout(listenerFunc, 0)
549
- window.addEventListener('resize', listenerFunc)
550
- return {
551
- disconnect() {
552
- window.removeEventListener('resize', listenerFunc)
553
- },
554
- }
555
- }
556
-
557
- getContext(element: Element, cb: (res: unknown) => void): void {
558
- cb(null)
559
- }
560
- }