Skip to content

Commit ea64855

Browse files
committed
Merge remote-tracking branch 'origin/master' into feat-webview
2 parents daaa57a + 3f19103 commit ea64855

File tree

9 files changed

+153
-20
lines changed

9 files changed

+153
-20
lines changed

glass-easel/src/behavior.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {
5050
type PropertyDefinition,
5151
} from './data_proxy'
5252
import { simpleDeepCopy } from './data_utils'
53-
import { type EventListener } from './event'
53+
import { type EventListener, type ShadowedEvent } from './event'
5454
import { FuncArr, safeCallback } from './func_arr'
5555
import { type ComponentOptions } from './global_options'
5656
import { normalizeRelation, type RelationDefinition, type RelationHandler } from './relation'
@@ -189,6 +189,11 @@ export class BehaviorBuilder<
189189
_$init: { func: (this: any, ctx: any) => any; once: boolean }[] = []
190190
/** @internal */
191191
_$methodCallerInit?: (this: ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>) => any
192+
/** @internal */
193+
_$listenerEventReplacer?: (
194+
this: ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>,
195+
event: ShadowedEvent<unknown>,
196+
) => ShadowedEvent<unknown>
192197

193198
/** @internal */
194199
constructor(is: string | undefined, ownerSpace: ComponentSpace) {
@@ -209,6 +214,21 @@ export class BehaviorBuilder<
209214
return this as any
210215
}
211216

217+
/**
218+
* Set a listener wrapper function
219+
*
220+
* It should return the wrapped listener.
221+
*/
222+
listenerEventReplacer(
223+
func: (
224+
this: ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>,
225+
event: ShadowedEvent<unknown>,
226+
) => ShadowedEvent<unknown>,
227+
): ResolveBehaviorBuilder<this, TChainingFilter> {
228+
this._$listenerEventReplacer = func
229+
return this as any
230+
}
231+
212232
/**
213233
* Add a behavior
214234
*
@@ -850,6 +870,11 @@ export class Behavior<
850870
_$methodCallerInit?: (
851871
this: ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>,
852872
) => ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>
873+
/** @internal */
874+
_$listenerEventReplacer?: (
875+
this: ComponentInstance<TData, TProperty, TMethod, TExtraThisFields>,
876+
event: ShadowedEvent<unknown>,
877+
) => ShadowedEvent<unknown>
853878

854879
/**
855880
* Create a behavior with classic-style definition
@@ -900,6 +925,7 @@ export class Behavior<
900925
this._$relationMap = undefined
901926
this._$init = []
902927
this._$methodCallerInit = builder._$methodCallerInit
928+
this._$listenerEventReplacer = builder._$listenerEventReplacer
903929
}
904930

905931
general(): GeneralBehavior {

glass-easel/src/component.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import {
5353
performanceMeasureStart,
5454
} from './dev_tools'
5555
import { Element } from './element'
56-
import { type EventListener, type EventListenerOptions } from './event'
56+
import { type ShadowedEvent, type EventListener, type EventListenerOptions } from './event'
5757
import { type ExternalShadowRoot } from './external_shadow_tree'
5858
import { FuncArr, safeCallback, type GeneralFuncType } from './func_arr'
5959
import {
@@ -1232,6 +1232,13 @@ export class Component<
12321232
return this._$methodCaller
12331233
}
12341234

1235+
/**
1236+
* Get the final event object
1237+
*/
1238+
getEventObject(e: ShadowedEvent<unknown>): ShadowedEvent<any> {
1239+
return this._$behavior._$listenerEventReplacer?.(e) || e
1240+
}
1241+
12351242
/**
12361243
* Add a lifetime event listener on the component
12371244
*/

glass-easel/src/event.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,13 @@ export class Event<TDetail> {
272272
targetCaller: Element,
273273
mark: { [name: string]: unknown } | null,
274274
currentTargetCaller: Element,
275+
ownerHost: GeneralComponent | undefined,
275276
): ShadowedEvent<TDetail> {
276277
const ret = Object.create(this) as ShadowedEvent<TDetail>
277278
ret.target = targetCaller
278279
ret.mark = mark
279280
ret.currentTarget = currentTargetCaller
280-
return ret
281+
return ownerHost?.getEventObject(ret) || ret
281282
}
282283

283284
getEventName(): string {
@@ -346,7 +347,7 @@ export class Event<TDetail> {
346347
? currentTarget.getMethodCaller() || currentTarget
347348
: currentTarget
348349
this._$hasListener ||= efa.funcArr.hasFunc()
349-
const ev = this.wrapShadowedEvent(targetCaller, mark, currentTargetCaller)
350+
const ev = this.wrapShadowedEvent(targetCaller, mark, currentTargetCaller, target.ownerShadowRoot?.getHostNode())
350351
const ret = efa.funcArr.call(
351352
currentTargetCaller,
352353
[ev],

glass-easel/src/func_arr.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export class FuncArr<F extends GeneralFuncType> {
1111
private _$type: string
1212
/* @internal */
1313
private _$arr: F[] | null = null
14-
/* @internal */
1514

1615
constructor(type: string) {
1716
this._$type = type

glass-easel/src/native_node.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {
88
} from './backend'
99
import { ClassList, StyleScopeManager } from './class_list'
1010
import { type DataValue, type ModelBindingListener } from './data_proxy'
11-
import { performanceMeasureEnd, performanceMeasureStart } from './dev_tools'
1211
import { Element } from './element'
1312
import { ENV, globalOptions } from './global_options'
13+
import { performanceMeasureEnd, performanceMeasureStart } from './dev_tools'
1414
import { type ShadowRoot } from './shadow_root'
1515
import { NATIVE_NODE_SYMBOL, isNativeNode } from './type_symbol'
1616

@@ -94,7 +94,6 @@ export class NativeNode extends Element {
9494
}
9595
if (ENV.DEV) performanceMeasureEnd()
9696
}
97-
9897
return node
9998
}
10099

glass-easel/src/tmpl/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ import {
1717
} from './proc_gen_wrapper'
1818

1919
export {
20-
setDefaultChangePropFilter,
21-
setDefaultEventListenerWrapper,
2220
type TmplDevArgs,
2321
type EventListenerWrapper,
2422
type ChangePropListener,

glass-easel/src/tmpl/native_rendering.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export class GlassEaselTemplateDOMInstance implements TemplateInstance, External
138138
const evName = event.getEventName()
139139
const bubbles = event.bubbles
140140
for (;;) {
141-
const shadowedEvent = event.wrapShadowedEvent(target as any, null, cur as any)
141+
const shadowedEvent = event.wrapShadowedEvent(target as any, null, cur as any, this.comp)
142142
const f = (cur as unknown as ElementWithEvent)._$wxTmplEv?.[evName]
143143
if (f) {
144144
const r = f.call(cur, shadowedEvent)

glass-easel/src/tmpl/proc_gen_wrapper.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { Component, type GeneralComponent } from '../component'
44
import { type DataPath } from '../data_path'
55
import { type DataValue } from '../data_proxy'
66
import { Element, StyleSegmentIndex } from '../element'
7-
import { type ShadowedEvent, type EventListener } from '../event'
7+
import { type EventListener } from '../event'
88
import { safeCallback } from '../func_arr'
9-
import { ENV } from '../global_options'
109
import { type NativeNode } from '../native_node'
1110
import { type Node } from '../node'
1211
import { SlotMode, type ShadowRoot } from '../shadow_root'
@@ -49,16 +48,10 @@ export interface EventListenerWrapper {
4948
isEventListenerWrapper?: true
5049
}
5150

52-
let defaultChangePropFilter: ChangePropFilter = <T>(x: T) => x
53-
export const setDefaultChangePropFilter = (fn: ChangePropFilter) => {
54-
defaultChangePropFilter = fn
55-
}
51+
const defaultChangePropFilter: ChangePropFilter = <T>(x: T) => x
5652

57-
let defaultEventListenerWrapper: EventListenerWrapper = (elem, evName, listener) => (e) =>
53+
const defaultEventListenerWrapper: EventListenerWrapper = (elem, evName, listener) => (e) =>
5854
listener.call(elem.ownerShadowRoot?.getHostNode().getMethodCaller(), e)
59-
export const setDefaultEventListenerWrapper = (fn: EventListenerWrapper) => {
60-
defaultEventListenerWrapper = fn
61-
}
6255

6356
type TmplArgs = {
6457
key?: number | string

glass-easel/tests/core/behavior.test.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,116 @@ describe('chaining-form interface', () => {
512512
expect(callOrder).toStrictEqual([3, 1, 2])
513513
})
514514

515+
test('chaining listener event replacer', () => {
516+
const callOrder: [number, number | undefined][] = []
517+
const beh = componentSpace
518+
.define()
519+
.init(({ self, lifetime }) => {
520+
lifetime('created', () => {
521+
self.addListener('customEv', (e) => {
522+
callOrder.push([
523+
1,
524+
(e as glassEasel.ShadowedEvent<{ eventOrder?: number }>).detail.eventOrder,
525+
])
526+
})
527+
})
528+
})
529+
.registerBehavior()
530+
531+
let eventOrder = 0
532+
const compDef = componentSpace
533+
.define()
534+
.behavior(beh)
535+
.template(tmpl(`<div id="wrapper" bind:customEv="onCustomEv"></div>`))
536+
.listenerEventReplacer((e) => {
537+
eventOrder += 1
538+
e.detail = { eventOrder }
539+
return e
540+
})
541+
.init(({ self, lifetime, listener }) => {
542+
lifetime('created', () => {
543+
;(self.shadowRoot as glassEasel.ShadowRoot).addListener('customEv', (e) => {
544+
callOrder.push([
545+
3,
546+
(e as glassEasel.ShadowedEvent<{ eventOrder: number }>).detail.eventOrder,
547+
])
548+
})
549+
})
550+
return {
551+
onCustomEv: listener((e) => {
552+
callOrder.push([
553+
2,
554+
(e as glassEasel.ShadowedEvent<{ eventOrder: number }>).detail.eventOrder,
555+
])
556+
}),
557+
}
558+
})
559+
.registerComponent()
560+
const root = glassEasel.Component.createWithContext('root', compDef, domBackend)
561+
;(root.$.wrapper as glassEasel.Element).triggerEvent(
562+
'customEv',
563+
{},
564+
{ bubbles: true, composed: true },
565+
)
566+
expect(callOrder).toStrictEqual([
567+
[2, 1],
568+
[3, 2],
569+
[1, undefined],
570+
])
571+
})
572+
573+
test('chaining listener event replacer on native rendering', () => {
574+
const callOrder: [number, number | undefined][] = []
575+
const beh = componentSpace
576+
.define()
577+
.init(({ self, lifetime }) => {
578+
lifetime('created', () => {
579+
self.addListener('customEv', (e) => {
580+
callOrder.push([
581+
1,
582+
(e as glassEasel.ShadowedEvent<{ eventOrder?: number }>).detail.eventOrder,
583+
])
584+
})
585+
})
586+
})
587+
.registerBehavior()
588+
589+
let eventOrder = 0
590+
const compDef = componentSpace
591+
.define()
592+
.behavior(beh)
593+
.options({ externalComponent: true })
594+
.template(tmpl(`<div id="wrapper" bind:customEv="onCustomEv"></div>`))
595+
.listenerEventReplacer((e) => {
596+
eventOrder += 1
597+
e.detail = { eventOrder }
598+
return e
599+
})
600+
.init(({ listener }) => {
601+
return {
602+
onCustomEv: listener((e) => {
603+
callOrder.push([
604+
2,
605+
(e as glassEasel.ShadowedEvent<{ eventOrder: number }>).detail.eventOrder,
606+
])
607+
}),
608+
}
609+
})
610+
.registerComponent()
611+
const root = glassEasel.Component.createWithContext('root', compDef, domBackend)
612+
glassEasel.triggerExternalEvent(
613+
root,
614+
root.$.wrapper as glassEasel.GeneralBackendElement,
615+
'customEv',
616+
{},
617+
{ bubbles: true, composed: true },
618+
)
619+
expect(callOrder).toStrictEqual([
620+
[2, 1],
621+
[1, undefined],
622+
])
623+
})
624+
515625
test('chaining relations', () => {
516626
const eventArr: number[] = []
517627
const parentDef = componentSpace

0 commit comments

Comments
 (0)