@eclipse-scout/core
Version:
Eclipse Scout runtime
120 lines (109 loc) • 4.33 kB
text/typescript
/*
* Copyright (c) 2010, 2023 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
import {arrays, Event, EventDelegatorOptions, EventEmitter, EventHandler, EventListener, objects, PropertyChangeEvent, PropertyEventEmitter, scout} from '../index';
/**
* Delegates events between two {@link EventEmitter}s.
*/
export class EventDelegator {
source: EventEmitter;
target: EventEmitter;
callSetter: boolean;
delegateProperties: string[];
excludeProperties: string[];
delegateEvents: string[];
delegateAllProperties: boolean;
delegateAllEvents: boolean;
protected _mirrorListener: EventListener;
protected _destroyHandler: EventHandler;
constructor(source: EventEmitter, target: EventEmitter, options?: EventDelegatorOptions) {
options = options || {};
this.source = source;
this.target = target;
this.callSetter = scout.nvl(options.callSetter, true);
this.delegateProperties = options.delegateProperties || [];
this.excludeProperties = options.excludeProperties || [];
this.delegateEvents = options.delegateEvents || [];
this.delegateAllProperties = !!options.delegateAllProperties;
this.delegateAllEvents = !!options.delegateAllEvents;
this._mirrorListener = null;
this._destroyHandler = null;
this._installSourceListener();
}
destroy() {
this._uninstallSourceListener();
}
protected _installSourceListener() {
if (this._mirrorListener) {
throw new Error('source listeners already installed.');
}
this._mirrorListener = {
func: this._onSourceEvent.bind(this)
};
this.source.events.addListener(this._mirrorListener);
this._destroyHandler = this._uninstallSourceListener.bind(this);
this.source.on('destroy', this._destroyHandler);
this.target.on('destroy', this._destroyHandler);
}
protected _uninstallSourceListener() {
if (this._mirrorListener) {
this.source.events.removeListener(this._mirrorListener);
this._mirrorListener = null;
}
if (this._destroyHandler) {
this.source.off('destroy', this._destroyHandler);
this.target.off('destroy', this._destroyHandler);
this._destroyHandler = null;
}
}
protected _onSourceEvent(event: Event) {
if (event.type === 'propertyChange') {
this._onSourcePropertyChange(event as PropertyChangeEvent<any>);
} else if (this.delegateAllEvents || this.delegateEvents.indexOf(event.type) > -1) {
this.target.trigger(event.type, event);
}
}
protected _onSourcePropertyChange(event: PropertyChangeEvent<any>) {
if (this.excludeProperties.indexOf(event.propertyName) > -1) {
return;
}
if (this.delegateAllProperties || this.delegateProperties.indexOf(event.propertyName) > -1) {
let newValue = event.newValue;
if (this.source instanceof PropertyEventEmitter && this.source.isMultiDimensionalProperty(event.propertyName)) {
// Delegate the dimension object instead of the computed value
newValue = this.source.getPropertyDimensions(event.propertyName);
}
if (EventDelegator.equalsProperty(event.propertyName, this.target, newValue)) {
return;
}
if (this.callSetter) {
(this.target as PropertyEventEmitter).callSetter(event.propertyName, newValue);
} else {
this.target.trigger(event.type, event);
}
}
}
static equalsProperty(propName: string, obj: object, value: any): boolean {
let propValue = obj[propName];
// Compare arrays using arrays.equals()
if (Array.isArray(value) && Array.isArray(propValue)) {
return arrays.equals(value as [], propValue as []);
}
return objects.equals(propValue, value);
}
static create(source: EventEmitter, target: EventEmitter, options: EventDelegatorOptions): EventDelegator {
if ((options.delegateProperties && options.delegateProperties.length > 0) ||
(options.delegateEvents && options.delegateEvents.length > 0) ||
options.delegateAllProperties ||
options.delegateAllEvents) {
return new EventDelegator(source, target, options);
}
return null;
}
}