Skip to content

Commit 438833d

Browse files
committed
feat: add unknown property handler
1 parent f566dcc commit 438833d

File tree

5 files changed

+83
-9
lines changed

5 files changed

+83
-9
lines changed

glass-easel/src/component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,7 @@ export class Component<
879879
options.reflectToAttributes,
880880
comp._$dataGroupObserverTree,
881881
options.propertyComparer,
882+
options.unknownPropertyHandler,
882883
)
883884
comp._$dataGroup = dataGroup
884885

glass-easel/src/data_proxy.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,10 @@ export class DataGroup<
526526
private _$recUpdateLevel = 0
527527
/* @internal */
528528
private _$propertyComparer: ((a: DataValue, b: DataValue) => boolean) | null
529+
/* @internal */
530+
private _$unknownPropertyHandler:
531+
| ((this: GeneralComponent, name: string, value: DataValue) => boolean | void)
532+
| null
529533

530534
/* @internal */
531535
private _$generateInnerData(data: { [key: string]: DataValue }) {
@@ -560,6 +564,9 @@ export class DataGroup<
560564
reflectToAttributes: boolean,
561565
observerTree: DataGroupObserverTree,
562566
propertyComparer: ((a: DataValue, b: DataValue) => boolean) | null,
567+
unknownPropertyHandler:
568+
| ((this: GeneralComponent, name: string, value: DataValue) => boolean | void)
569+
| null,
563570
) {
564571
this._$comp = associatedComponent
565572
this.data = data
@@ -571,6 +578,7 @@ export class DataGroup<
571578
this._$observerTree = observerTree
572579
this._$observerStatus = new Array(observerTree.observers.length) as boolean[]
573580
this._$propertyComparer = propertyComparer
581+
this._$unknownPropertyHandler = unknownPropertyHandler
574582
this.innerData = this._$generateInnerData(data)
575583
}
576584

@@ -585,6 +593,7 @@ export class DataGroup<
585593
false,
586594
new DataGroupObserverTree({}),
587595
null,
596+
null,
588597
)
589598
}
590599

@@ -633,7 +642,7 @@ export class DataGroup<
633642
replaceProperty(propName: string, newData: DataValue): boolean {
634643
let data = newData
635644
const prop = this._$propFields[propName]
636-
if (!prop) return false
645+
if (!prop) return this._$unknownPropertyHandler?.call(this._$comp!, propName, newData) ?? false
637646
if (this._$propertyPassingDeepCopy !== DeepCopyStrategy.None) {
638647
if (this._$propertyPassingDeepCopy === DeepCopyStrategy.SimpleWithRecursion) {
639648
data = deepCopy(newData, true)

glass-easel/src/global_options.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ export type ComponentOptions = {
8383
propertyEarlyInit?: boolean
8484
/** Property comparer function, return false if properties are equal */
8585
propertyComparer?: ((a: any, b: any) => boolean) | null
86+
/** Handle unknown properties or not */
87+
unknownPropertyHandler?:
88+
| ((this: GeneralComponent, name: string, value: any) => boolean | void)
89+
| null
8690
}
8791

8892
export type NormalizedComponentOptions = {
@@ -105,6 +109,9 @@ export type NormalizedComponentOptions = {
105109
virtualHost: boolean
106110
propertyEarlyInit: boolean
107111
propertyComparer: ((a: any, b: any) => boolean) | null
112+
unknownPropertyHandler:
113+
| ((this: GeneralComponent, name: string, value: any) => boolean | void)
114+
| null
108115
}
109116

110117
/**
@@ -147,6 +154,7 @@ export const globalOptions: NormalizedComponentOptions & EnvironmentOptions = {
147154
virtualHost: false,
148155
propertyEarlyInit: false,
149156
propertyComparer: null,
157+
unknownPropertyHandler: null,
150158
throwGlobalError: false,
151159
writeExtraInfoToAttr: false,
152160
backendContext: null,
@@ -196,5 +204,7 @@ export const normalizeComponentOptions = (
196204
propertyEarlyInit:
197205
p.propertyEarlyInit !== undefined ? p.propertyEarlyInit : b.propertyEarlyInit,
198206
propertyComparer: p.propertyComparer !== undefined ? p.propertyComparer : b.propertyComparer,
207+
unknownPropertyHandler:
208+
p.unknownPropertyHandler !== undefined ? p.unknownPropertyHandler : b.unknownPropertyHandler,
199209
}
200210
}

glass-easel/src/tmpl/proc_gen_wrapper.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,10 +1058,8 @@ export class ProcGenWrapper {
10581058

10591059
// set style (or property named `style`)
10601060
y = (elem: Element, v: string) => {
1061-
if (isComponent(elem) && Component.hasProperty(elem, 'style')) {
1062-
const nodeDataProxy = Component.getDataProxy(elem)
1063-
const camelName = dashToCamelCase('style')
1064-
nodeDataProxy.replaceProperty(camelName, v)
1061+
if (isComponent(elem) && Component.getDataProxy(elem).replaceProperty('style', v)) {
1062+
// empty
10651063
} else {
10661064
elem.setNodeStyle(dataValueToString(v), StyleSegmentIndex.MAIN)
10671065
}
@@ -1101,10 +1099,8 @@ export class ProcGenWrapper {
11011099
const value = arr[i + 1]
11021100
v += `${name}:${value};`
11031101
}
1104-
if (isComponent(elem) && Component.hasProperty(elem, 'style')) {
1105-
const nodeDataProxy = Component.getDataProxy(elem)
1106-
const camelName = dashToCamelCase('style')
1107-
nodeDataProxy.replaceProperty(camelName, v)
1102+
if (isComponent(elem) && Component.getDataProxy(elem).replaceProperty('style', v)) {
1103+
// empty
11081104
} else {
11091105
elem.setNodeStyle(dataValueToString(v), StyleSegmentIndex.MAIN)
11101106
}

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,4 +1236,62 @@ describe('partial update', () => {
12361236
expect(domHtml(comp)).toBe('true')
12371237
expect(execArr).toEqual(['middle:observer:true', 'child:observer:true', 'child:property:true'])
12381238
})
1239+
1240+
test('should support unknown property handler', () => {
1241+
let execArr = [] as [string, unknown][]
1242+
let execReturn: boolean = true
1243+
const childCompDef = componentSpace
1244+
.define()
1245+
.options({
1246+
unknownPropertyHandler(propName: string, value: unknown) {
1247+
execArr.push([propName, value])
1248+
return execReturn
1249+
},
1250+
})
1251+
.property('a', String)
1252+
.property('b', String)
1253+
.registerComponent()
1254+
1255+
const compDef = componentSpace
1256+
.define()
1257+
.usingComponents({
1258+
child: childCompDef.general(),
1259+
})
1260+
.template(
1261+
tmpl(`
1262+
<child id="child" style="{{style}}" p="{{p}}" a="{{a}}" bindff="ff" data-dd="{{dd}}" />
1263+
`),
1264+
)
1265+
.data(() => ({
1266+
p: 'p',
1267+
a: 'a',
1268+
dd: 'dd',
1269+
style: 'style',
1270+
}))
1271+
.registerComponent()
1272+
1273+
const comp = glassEasel.Component.createWithContext('root', compDef, domBackend)
1274+
const child = (comp.$.child as glassEasel.Element).asInstanceOf(childCompDef)!
1275+
1276+
expect(execArr).toEqual([
1277+
['style', 'style'],
1278+
['p', 'p'],
1279+
['bindff', 'ff'],
1280+
['dataDd', 'dd'],
1281+
])
1282+
expect(child.style).toBe('')
1283+
expect(child.getListeners()).toEqual({})
1284+
expect(child.dataset).toEqual({})
1285+
1286+
execArr = []
1287+
execReturn = false
1288+
comp.setData({ a: 'a2', dd: 'dd2', style: 'style2' })
1289+
expect(execArr).toEqual([
1290+
['style', 'style2'],
1291+
['dataDd', 'dd2'],
1292+
['data-dd', 'dd2'],
1293+
])
1294+
expect(child.style).toBe('style2')
1295+
expect(child.dataset).toEqual({ dd: 'dd2' })
1296+
})
12391297
})

0 commit comments

Comments
 (0)