// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { WidgetModel, unpack_models } from '@jupyter-widgets/base'; import { CoreWidgetModel } from './widget_core'; export class DirectionalLinkModel extends CoreWidgetModel { static serializers = { ...CoreWidgetModel.serializers, target: { deserialize: unpack_models }, source: { deserialize: unpack_models }, }; defaults(): Backbone.ObjectHash { return { ...super.defaults(), target: undefined, source: undefined, _model_name: 'DirectionalLinkModel', }; } initialize( attributes: Backbone.ObjectHash, options: { model_id: string; comm: any; widget_manager: any } ): void { super.initialize(attributes, options); this.on('change', this.updateBindings, this); this.updateBindings(); } updateValue( sourceModel: WidgetModel, sourceAttr: string, targetModel: WidgetModel, targetAttr: string ): void { if (this._updating) { return; } this._updating = true; try { if (targetModel) { targetModel.set(targetAttr, sourceModel.get(sourceAttr)); targetModel.save_changes(); } } finally { this._updating = false; } } updateBindings(): void { this.cleanup(); [this.sourceModel, this.sourceAttr] = this.get('source') || [null, null]; [this.targetModel, this.targetAttr] = this.get('target') || [null, null]; if (this.sourceModel) { this.listenTo(this.sourceModel, 'change:' + this.sourceAttr, () => { this.updateValue( this.sourceModel, this.sourceAttr, this.targetModel, this.targetAttr ); }); this.updateValue( this.sourceModel, this.sourceAttr, this.targetModel, this.targetAttr ); this.listenToOnce(this.sourceModel, 'destroy', this.cleanup); } if (this.targetModel) { this.listenToOnce(this.targetModel, 'destroy', this.cleanup); } } cleanup(): void { // Stop listening to 'change' and 'destroy' events of the source and target if (this.sourceModel) { this.stopListening( this.sourceModel, 'change:' + this.sourceAttr, undefined ); this.stopListening(this.sourceModel, 'destroy', undefined); } if (this.targetModel) { this.stopListening(this.targetModel, 'destroy', undefined); } } sourceModel: WidgetModel; sourceAttr: string; targetModel: WidgetModel; targetAttr: string; private _updating: boolean; } export class LinkModel extends DirectionalLinkModel { defaults(): Backbone.ObjectHash { return { ...super.defaults(), _model_name: 'LinkModel', }; } updateBindings(): void { super.updateBindings(); if (this.targetModel) { this.listenTo(this.targetModel, 'change:' + this.targetAttr, () => { this.updateValue( this.targetModel, this.targetAttr, this.sourceModel, this.sourceAttr ); }); } } cleanup(): void { super.cleanup(); if (this.targetModel) { this.stopListening( this.targetModel, 'change:' + this.targetAttr, undefined ); } } }