From 57171c768e864eeafa37e11b594397245bc33fb9 Mon Sep 17 00:00:00 2001 From: vakrilov Date: Fri, 15 May 2015 16:55:02 +0300 Subject: [PATCH] WeakEvents with map --- apps/tests/ui/helper.ts | 1 + apps/tests/weak-event-listener-tests.ts | 202 +++++++++------------ ui/button/button-common.ts | 13 +- ui/core/bindable.ts | 22 ++- ui/core/weak-event-listener.d.ts | 60 ++----- ui/core/weak-event-listener.ts | 230 +++++++++++++----------- ui/list-view/list-view-common.ts | 11 +- ui/text-base/text-base.ts | 14 +- 8 files changed, 251 insertions(+), 302 deletions(-) diff --git a/apps/tests/ui/helper.ts b/apps/tests/ui/helper.ts index b2ad8b48e..ef59eb584 100644 --- a/apps/tests/ui/helper.ts +++ b/apps/tests/ui/helper.ts @@ -225,6 +225,7 @@ export function forceGC() { if (platform.device.os === platform.platformNames.ios) { // Could cause GC on the next call. new ArrayBuffer(4 * 1024 * 1024); + TKUnit.wait(ASYNC); } utils.GC(); } \ No newline at end of file diff --git a/apps/tests/weak-event-listener-tests.ts b/apps/tests/weak-event-listener-tests.ts index 96eb01f34..49524f1a0 100644 --- a/apps/tests/weak-event-listener-tests.ts +++ b/apps/tests/weak-event-listener-tests.ts @@ -4,89 +4,64 @@ import observable = require("data/observable"); import weakEvents = require("ui/core/weak-event-listener"); import helper = require("./ui/helper"); +class Target { + public counter: number = 0; + public onEvent(data: observable.EventData) { + this.counter++; + } + +} + export function test_addWeakEventListener_throwsWhenCalledwitnInvalid_source() { TKUnit.assertThrows(() => { - weakEvents.WeakEventListener.addWeakEventListener({ - source: undefined, - target: {}, - handler: emptyHandler, - eventName: observable.Observable.propertyChangeEvent - }); + weakEvents.addWeakEventListener(undefined, "eventName", emptyHandler, {}); }); } export function test_addWeakEventListener_throwsWhenCalledwitnInvalid_target() { TKUnit.assertThrows(() => { - weakEvents.WeakEventListener.addWeakEventListener({ - source: new observable.Observable(), - target: undefined, - handler: emptyHandler, - eventName: observable.Observable.propertyChangeEvent - }); + weakEvents.addWeakEventListener(new observable.Observable(), "eventName", emptyHandler, undefined); }); } export function test_addWeakEventListener_throwsWhenCalledwitnInvalid_handler() { TKUnit.assertThrows(() => { - weakEvents.WeakEventListener.addWeakEventListener({ - source: new observable.Observable(), - target: {}, - handler: undefined, - eventName: observable.Observable.propertyChangeEvent - }); + weakEvents.addWeakEventListener(new observable.Observable(), "eventName", undefined, {}); }); } export function test_addWeakEventListener_throwsWhenCalledwitnInvalid_name() { TKUnit.assertThrows(() => { - weakEvents.WeakEventListener.addWeakEventListener({ - source: new observable.Observable(), - target: {}, - handler: emptyHandler, - eventName: undefined - }); + weakEvents.addWeakEventListener(new observable.Observable(), undefined, emptyHandler, {}); }); } export function test_addWeakEventListener_listensForEvent() { var source = new observable.Observable(); - var target = new Object; - var callbackCalled = false; - var handler = function (args: observable.EventData) { - callbackCalled = true; - } + var target = new Target(); - weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: target, - handler: handler, - eventName: observable.Observable.propertyChangeEvent - }) + weakEvents.addWeakEventListener( + source, + observable.Observable.propertyChangeEvent, + target.onEvent, + target); + + helper.forceGC(); source.set("testProp", "some value"); - TKUnit.assert(callbackCalled, "Handler not called."); + TKUnit.assertEqual(target.counter, 1, "Handler not called."); } export function test_removeWeakEventListener_StopsListeningForEvet() { var source = new observable.Observable(); - var target = new Object; - var callbackCalled = false; - var handler = function (args: observable.EventData) { - callbackCalled = true; - } + var target = new Target(); - var listenerID = weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: target, - handler: handler, - eventName: observable.Observable.propertyChangeEvent - }) - - weakEvents.WeakEventListener.removeWeakEventListener(listenerID); + weakEvents.addWeakEventListener(source, observable.Observable.propertyChangeEvent, target.onEvent, target); + weakEvents.removeWeakEventListener(source, observable.Observable.propertyChangeEvent, target.onEvent, target) source.set("testProp", "some value"); - TKUnit.assert(!callbackCalled, "Handler should not be called."); + TKUnit.assertEqual(target.counter, 0, "Handler should not be called."); } export function test_handlerIsCalled_WithTargetAsThis() { @@ -98,12 +73,7 @@ export function test_handlerIsCalled_WithTargetAsThis() { callbackCalled = true; } - weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: target, - handler: handler, - eventName: observable.Observable.propertyChangeEvent - }) + weakEvents.addWeakEventListener(source, observable.Observable.propertyChangeEvent, handler, target); source.set("testProp", "some value"); TKUnit.assert(callbackCalled, "Handler not called."); @@ -111,19 +81,10 @@ export function test_handlerIsCalled_WithTargetAsThis() { export function test_listnerDoesNotRetainTarget() { var source = new observable.Observable(); - var target = new Object; + var target = new Target(); var callbackCalled = false; - var handler = function (args: observable.EventData) { - TKUnit.assertEqual(this, target, "this should be the target"); - callbackCalled = true; - } - weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: target, - handler: handler, - eventName: observable.Observable.propertyChangeEvent - }) + weakEvents.addWeakEventListener(source, observable.Observable.propertyChangeEvent, target.onEvent, target); var targetRef = new WeakRef(target); target = undefined; @@ -134,19 +95,10 @@ export function test_listnerDoesNotRetainTarget() { export function test_listnerDoesNotRetainSource() { var source = new observable.Observable(); - var target = new Object(); + var target = new Target(); var callbackCalled = false; - var handler = function (args: observable.EventData) { - TKUnit.assertEqual(this, target, "this should be the target"); - callbackCalled = true; - } - weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: target, - handler: handler, - eventName: observable.Observable.propertyChangeEvent - }) + weakEvents.addWeakEventListener(source, observable.Observable.propertyChangeEvent, target.onEvent, target); var sourceRef = new WeakRef(source); source = undefined; @@ -155,50 +107,74 @@ export function test_listnerDoesNotRetainSource() { TKUnit.assert(!sourceRef.get(), "Source should be released after GC"); } -export function test_listnerIsCleared_WhenTargetIsDead() { - var source = new observable.Observable(); +//export function test_listnerIsCleared_WhenTargetIsDead() { +// var source = new observable.Observable(); - var listenerID = addListenerWithSource(source); - helper.forceGC(); +// var listenerID = addListenerWithSource(source); +// helper.forceGC(); - for (var i = 0; i < weakEvents.WeakEventListener.cleanDeadReferencesCountTrigger; i++) { - addListenerWithSource(source); - } +// for (var i = 0; i < weakEvents.cleanDeadReferencesCountTrigger; i++) { +// addListenerWithSource(source); +// } - TKUnit.assert(types.isUndefined(weakEvents.WeakEventListener._weakEventListeners[listenerID]), "The first listener should be dead by now"); -} +// TKUnit.assert(types.isUndefined(weakEvents._weakEventListeners[listenerID]), "The first listener should be dead by now"); +//} -export function test_listnerIsCleared_WhenSourceIsDead() { - var target = {}; +//export function test_listnerIsCleared_WhenSourceIsDead() { +// var target = {}; - var listenerID = addListenerWithTarget(target); - helper.forceGC(); +// var listenerID = addListenerWithTarget(target); +// helper.forceGC(); - for (var i = 0; i < weakEvents.WeakEventListener.cleanDeadReferencesCountTrigger; i++) { - addListenerWithTarget(target); - } +// for (var i = 0; i < weakEvents.cleanDeadReferencesCountTrigger; i++) { +// addListenerWithTarget(target); +// } - TKUnit.assert(types.isUndefined(weakEvents.WeakEventListener._weakEventListeners[listenerID]), "The first listener should be dead by now"); -} +// TKUnit.assert(types.isUndefined(weakEvents._weakEventListeners[listenerID]), "The first listener should be dead by now"); +//} -function addListenerWithSource(source: observable.Observable): number { - return weakEvents.WeakEventListener.addWeakEventListener({ - source: source, - target: {}, - handler: emptyHandler, - eventName: observable.Observable.propertyChangeEvent - }) -} +//function addListenerWithSource(source: observable.Observable): number { +// return weakEvents.addWeakEventListener({ +// source: source, +// target: {}, +// handler: emptyHandler, +// eventName: observable.Observable.propertyChangeEvent +// }) +//} -function addListenerWithTarget(target: any): number { - return weakEvents.WeakEventListener.addWeakEventListener({ - source: new observable.Observable(), - target: target, - handler: emptyHandler, - eventName: observable.Observable.propertyChangeEvent - }) -} +//function addListenerWithTarget(target: any): number { +// return weakEvents.addWeakEventListener({ +// source: new observable.Observable(), +// target: target, +// handler: emptyHandler, +// eventName: observable.Observable.propertyChangeEvent +// }) +//} function emptyHandler(data: observable.EventData) { // Do nothing. -} \ No newline at end of file +} + + + +export function testWeakMap(): void { + var source = new observable.Observable(); + var target = new Target(); + var targetRef = new WeakRef(target); + var weakMap = new WeakMap(); + + weakMap.set(source, target); + TKUnit.assertEqual(weakMap.get(source), target, "target"); + + target = undefined; + source = undefined; + + helper.forceGC(); + TKUnit.wait(1); + + TKUnit.waitUntilReady(function () { + return false; + }) + + TKUnit.assert(!targetRef.get(), "Target should be dead"); +} diff --git a/ui/button/button-common.ts b/ui/button/button-common.ts index e1d8cfdc6..47922c008 100644 --- a/ui/button/button-common.ts +++ b/ui/button/button-common.ts @@ -4,7 +4,7 @@ import definition = require("ui/button"); import proxy = require("ui/core/proxy"); import formattedString = require("text/formatted-string"); import observable = require("data/observable"); -import weakEventListener = require("ui/core/weak-event-listener"); +import weakEvents = require("ui/core/weak-event-listener"); var textProperty = new dependencyObservable.Property( "text", @@ -37,8 +37,6 @@ export class Button extends view.View implements definition.Button { public static textProperty = textProperty; public static formattedTextProperty = formattedTextProperty; - private _formattedTextWeakListenerId: number; - public _onBindingContextChanged(oldValue: any, newValue: any) { super._onBindingContextChanged(oldValue, newValue); if (this.formattedText) { @@ -61,16 +59,11 @@ export class Button extends view.View implements definition.Button { set formattedText(value: formattedString.FormattedString) { if (this.formattedText !== value) { if (this.formattedText) { - weakEventListener.WeakEventListener.removeWeakEventListener(this._formattedTextWeakListenerId); + weakEvents.removeWeakEventListener(this.formattedText, observable.Observable.propertyChangeEvent, this.onFormattedTextChanged, this); } this._setValue(Button.formattedTextProperty, value); if (value) { - this._formattedTextWeakListenerId = weakEventListener.WeakEventListener.addWeakEventListener({ - target: this, - source: value, - eventName: observable.Observable.propertyChangeEvent, - handler: this.onFormattedTextChanged - }); + weakEvents.addWeakEventListener(value, observable.Observable.propertyChangeEvent, this.onFormattedTextChanged, this); } } } diff --git a/ui/core/bindable.ts b/ui/core/bindable.ts index 09e728877..da860ac59 100644 --- a/ui/core/bindable.ts +++ b/ui/core/bindable.ts @@ -162,12 +162,11 @@ export class Binding { if (this.sourceOptions) { var sourceOptionsInstance = this.sourceOptions.instance.get(); if (sourceOptionsInstance instanceof observable.Observable) { - this.weakEventId = weakEvents.WeakEventListener.addWeakEventListener({ - target: this, - source: this.sourceOptions.instance.get(), - eventName: observable.Observable.propertyChangeEvent, - handler: this.onSourcePropertyChanged, - }); + weakEvents.addWeakEventListener( + sourceOptionsInstance, + observable.Observable.propertyChangeEvent, + this.onSourcePropertyChanged, + this); } } } @@ -177,8 +176,15 @@ export class Binding { return; } - weakEvents.WeakEventListener.removeWeakEventListener(this.weakEventId); - delete this.weakEventId; + if (this.sourceOptions) { + var sourceOptionsInstance = this.sourceOptions.instance.get(); + if (sourceOptionsInstance) { + weakEvents.removeWeakEventListener(sourceOptionsInstance, + observable.Observable.propertyChangeEvent, + this.onSourcePropertyChanged, + this); + } + } if (this.source) { this.source.clear(); diff --git a/ui/core/weak-event-listener.d.ts b/ui/core/weak-event-listener.d.ts index a1fd306c6..450f04981 100644 --- a/ui/core/weak-event-listener.d.ts +++ b/ui/core/weak-event-listener.d.ts @@ -2,56 +2,20 @@ declare module "ui/core/weak-event-listener" { import observable = require("data/observable"); /** - * An interface that defines all options needed for creating weak event listener. + * Creates and initialize WeakEventListener. + * @param source Observable class which emits the event. + * @param eventName The event name. + * @param handler The function which should be called when event occurs. + * @param target Subscriber (target) of the event listener. It will be used as a thisArg in the handler function. */ - export interface WeakEventListenerOptions { - /** - * Subscriber (target) of the event listener. It will be used as a thisArg in the handler function. - */ - target: any; - - /** - * Observable class which emits the event. - */ - source: observable.Observable; - - /** - * Name of the event. - */ - eventName: string; - - /** - * The function which should be called when event occurs. - */ - handler: (eventData: observable.EventData) => void; - } + export function addWeakEventListener(source: observable.Observable, eventName: string, handler: (eventData: observable.EventData) => void, target: any) : void; /** - * Represents a class that utilize work with weak event listeners. + * Removes and clears all resources from WeakEventListener. + * @param source Observable class which emits the event. + * @param eventName The event name. + * @param handler The function which should be called when event occurs. + * @param target Subscriber (target) of the event listener. It will be used as a thisArg in the handler function. */ - export class WeakEventListener { - /** - * Creates and initialize WeakEventListener (if all required options are set). - * @param options An instance of WeakEventListenerOptions needed to create WeakEventListener instance. - * Returns The id of the WeakEventListener object to be used in removeWeakEventListener method. - */ - static addWeakEventListener(options: WeakEventListenerOptions): number; - - /** - * Removes and clears all resources from WeakEventListener with given id. - * @param The id of the WeakEventListener object. - */ - static removeWeakEventListener(listenerId: number): void; - - /** - * Specifies how often will internal clearing of dead references will occur. - * Clearing will be triggered on addWeakEventListener on every N times where N is - * the value of this property. Set 0 to disable clearing. - */ - static cleanDeadReferencesCountTrigger: number; - - //@private - static _weakEventListeners: Object; - //@endprivate - } + export function removeWeakEventListener(source: observable.Observable, eventName: string, handler: (eventData: observable.EventData) => void, target: any): void; } \ No newline at end of file diff --git a/ui/core/weak-event-listener.ts b/ui/core/weak-event-listener.ts index 2bf5def4a..886125964 100644 --- a/ui/core/weak-event-listener.ts +++ b/ui/core/weak-event-listener.ts @@ -2,120 +2,142 @@ import definition = require("ui/core/weak-event-listener"); import types = require("utils/types"); -var CLEAN_TRIGGER_DEFAULT = 1000; -export class WeakEventListener implements definition.WeakEventListener { - private id: number; - private targetRef: WeakRef; - private senderRef: WeakRef; - private eventName: string; - private handler: (eventData: observable.EventData) => void; +var handlersForEventName = new Map void>(); +var sourcesMap = new WeakMap>>(); - static _idCounter: number = 0; - static _weakEventListeners = {}; - static _cleanDeadReferencesCountTrigger = CLEAN_TRIGGER_DEFAULT; - static get cleanDeadReferencesCountTrigger(): number { - return WeakEventListener._cleanDeadReferencesCountTrigger; - } - static set cleanDeadReferencesCountTrigger(value: number) { - WeakEventListener._cleanDeadReferencesCountTrigger = value; +class TargetHandlerPair { + tagetRef: WeakRef; + handler: (eventData: observable.EventData) => void; + + constructor(target: Object, handler: (eventData: observable.EventData) => void) { + this.tagetRef = new WeakRef(target); + this.handler = handler; } +} - private handlerCallback(eventData) { - var target = this.targetRef.get(); - if (target) { - this.handler.call(target, eventData); - } - else { - // The target is dead - we can unsubscribe; - WeakEventListener.removeWeakEventListener(this.id); - } - } - - private init(options: definition.WeakEventListenerOptions, listenerId: number) { - this.id = listenerId; - this.targetRef = new WeakRef(options.target); - this.senderRef = new WeakRef(options.source); - this.eventName = options.eventName; - this.handler = options.handler; - - var sourceInstance = this.senderRef.get(); - if (sourceInstance) { - sourceInstance.addEventListener(this.eventName, this.handlerCallback, this); - } - } - - private clear() { - var sender = this.senderRef.get(); - if (sender) { - sender.removeEventListener(this.eventName, this.handlerCallback, this); - } - - this.targetRef.clear(); - this.targetRef = undefined; - this.senderRef.clear(); - this.senderRef = undefined; - - this.eventName = undefined; - this.handler = undefined; - } - - static addWeakEventListener(options: definition.WeakEventListenerOptions) { - if (types.isNullOrUndefined(options.target)) { - throw new Error("targetWeakRef is null or undefined"); - } - - if (types.isNullOrUndefined(options.source)) { - throw new Error("sourceWeakRef is null or undefined"); - } - - if (!types.isString(options.eventName)) { - throw new Error("eventName is not a string"); - } - - if (!types.isFunction(options.handler)) { - throw new Error("handler is not a function"); - } - - var listenerId = WeakEventListener._idCounter++; - var weakEventListener = new WeakEventListener(); - weakEventListener.init(options, listenerId); - - WeakEventListener._weakEventListeners[listenerId] = new WeakRef(weakEventListener); - - if (WeakEventListener._cleanDeadReferencesCountTrigger && - (listenerId % WeakEventListener._cleanDeadReferencesCountTrigger) === 0) { - WeakEventListener._cleanDeadReferences(); - } - - return listenerId; - } - - static removeWeakEventListener(listenerId: number) { - var listenerRef = >WeakEventListener._weakEventListeners[listenerId]; - - if (listenerRef) { - var listener = listenerRef.get(); - if (listener) { - listener.clear(); +function getHandlerForEventName(eventName: string): (eventData: observable.EventData) => void { + var handler = handlersForEventName.get(eventName); + if (!handler) { + var handler = function (eventData: observable.EventData) { + var source = eventData.object; + var sourceEventMap = sourcesMap.get(source); + if (!sourceEventMap) { + // There is no event map for this source - it is safe to detach the listener; + source.removeEventListener(eventName, handlersForEventName.get(eventName)); + return; } - } - delete WeakEventListener._weakEventListeners[listenerId]; + var targetHandlerPairList = sourceEventMap.get(eventName); + if (!targetHandlerPairList) { + return; + } + + var deadPairsIndexes = []; + for (var i = 0; i < targetHandlerPairList.length; i++) { + var pair = targetHandlerPairList[i]; + + var target = pair.tagetRef.get(); + if (target) { + pair.handler.call(target, eventData); + } + else { + deadPairsIndexes.push(i); + } + } + + if (deadPairsIndexes.length === targetHandlerPairList.length) { + // There are no alive targets for this event - unsubscribe + source.removeEventListener(eventName, handlersForEventName.get(eventName)); + sourceEventMap.delete(eventName); + } + else { + for (var j = deadPairsIndexes.length - 1; j >= 0; j--) { + targetHandlerPairList.splice(deadPairsIndexes[j], 1); + } + } + }; + handlersForEventName.set(eventName, handler); } - static _cleanDeadReferences() { - var deadListeners = new Array(); - for (var id in WeakEventListener._weakEventListeners) { - var listenerRef = >WeakEventListener._weakEventListeners[id]; + return handler; +} - var listener = listenerRef.get(); - if (!listener || !listener.targetRef.get() || !listener.senderRef.get()) { - deadListeners.push(id); - } +function validateArgs(source: observable.Observable, eventName: string, handler: (eventData: observable.EventData) => void, target: any) { + if (types.isNullOrUndefined(source)) { + throw new Error("source is null or undefined"); + } + + if (types.isNullOrUndefined(target)) { + throw new Error("target is null or undefined"); + } + + if (!types.isString(eventName)) { + throw new Error("eventName is not a string"); + } + + if (!types.isFunction(handler)) { + throw new Error("handler is not a function"); + } +} + +export function addWeakEventListener(source: observable.Observable, eventName: string, handler: (eventData: observable.EventData) => void, target: any) { + validateArgs(source, eventName, handler, target); + + var sourceEventMap = sourcesMap.get(source); + if (!sourceEventMap) { + sourceEventMap = new Map>(); + sourcesMap.set(source, sourceEventMap); + } + + var pairList = sourceEventMap.get(eventName); + if (!pairList) { + pairList = new Array(); + sourceEventMap.set(eventName, pairList); + } + + pairList.push(new TargetHandlerPair(target, handler)); + + source.addEventListener(eventName, getHandlerForEventName(eventName)); +} + +export function removeWeakEventListener(source: observable.Observable, eventName: string, handler: (eventData: observable.EventData) => void, target: any) { + validateArgs(source, eventName, handler, target); + + var handlerForEventWithName = handlersForEventName.get(eventName); + if (!handlerForEventWithName) { + // We have never created handler for event with this name; + return; + } + + var sourceEventMap = sourcesMap.get(source); + if (!sourceEventMap) { + return; + } + + var targetHandlerPairList = sourceEventMap.get(eventName); + if (!targetHandlerPairList) { + return; + } + + // Remove all pairs that match given target and handler or have a dead target + var targetHandlerPairsToRemove = []; + for (var i = 0; i < targetHandlerPairList.length; i++) { + var pair = targetHandlerPairList[i]; + + var registeredTarget = pair.tagetRef.get(); + if (!registeredTarget || (registeredTarget === target && handler === pair.handler)) { + targetHandlerPairsToRemove.push(i); } + } - for (var i = 0; i < deadListeners.length; i++) { - WeakEventListener.removeWeakEventListener(deadListeners[i]); + if (targetHandlerPairsToRemove.length === targetHandlerPairList.length) { + // There are no alive targets for this event - unsubscribe + source.removeEventListener(eventName, handlerForEventWithName); + sourceEventMap.delete(eventName); + } + else { + for (var j = targetHandlerPairsToRemove.length - 1; j >= 0; j--) { + targetHandlerPairList.splice(targetHandlerPairsToRemove[j], 1); } } } diff --git a/ui/list-view/list-view-common.ts b/ui/list-view/list-view-common.ts index a5cc1ece5..f8cdc734f 100644 --- a/ui/list-view/list-view-common.ts +++ b/ui/list-view/list-view-common.ts @@ -7,7 +7,7 @@ import dependencyObservable = require("ui/core/dependency-observable"); import builder = require("ui/builder"); import label = require("ui/label"); import color = require("color"); -import weakEventListener = require("ui/core/weak-event-listener"); +import weakEvents = require("ui/core/weak-event-listener"); import types = require("utils/types"); var ITEMS = "items"; @@ -132,17 +132,12 @@ export class ListView extends view.View implements definition.ListView { public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { if (data.oldValue instanceof observable.Observable && types.isDefined(this._itemsChangedWeakListenerId)) { - weakEventListener.WeakEventListener.removeWeakEventListener(this._itemsChangedWeakListenerId); + weakEvents.removeWeakEventListener(data.oldValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this); delete this._itemsChangedWeakListenerId; } if (data.newValue instanceof observable.Observable) { - this._itemsChangedWeakListenerId = weakEventListener.WeakEventListener.addWeakEventListener({ - target: this, - source: data.newValue, - eventName: observableArray.ObservableArray.changeEvent, - handler: this._onItemsChanged, - }); + weakEvents.addWeakEventListener(data.newValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this); } this.refresh(); diff --git a/ui/text-base/text-base.ts b/ui/text-base/text-base.ts index 1bf124d7f..77e77cefb 100644 --- a/ui/text-base/text-base.ts +++ b/ui/text-base/text-base.ts @@ -4,7 +4,7 @@ import observable = require("data/observable"); import dependencyObservable = require("ui/core/dependency-observable"); import proxy = require("ui/core/proxy"); import formattedString = require("text/formatted-string"); -import weakEventListener = require("ui/core/weak-event-listener"); +import weakEvents = require("ui/core/weak-event-listener"); import utils = require("utils/utils"); import trace = require("trace"); @@ -38,8 +38,6 @@ export class TextBase extends view.View implements definition.TextBase { public static textProperty = textProperty; public static formattedTextProperty = formattedTextProperty; - private _formattedTextChangedListenerId: number; - constructor(options?: definition.Options) { super(options); } @@ -80,17 +78,11 @@ export class TextBase extends view.View implements definition.TextBase { set formattedText(value: formattedString.FormattedString) { if (this.formattedText !== value) { if (this.formattedText) { - weakEventListener.WeakEventListener.removeWeakEventListener(this._formattedTextChangedListenerId); - delete this._formattedTextChangedListenerId; + weakEvents.removeWeakEventListener(this.formattedText, observable.Observable.propertyChangeEvent, this.onFormattedTextChanged, this); } this._setValue(TextBase.formattedTextProperty, value); if (value) { - this._formattedTextChangedListenerId = weakEventListener.WeakEventListener.addWeakEventListener({ - target: this, - source: value, - eventName: observable.Observable.propertyChangeEvent, - handler: this.onFormattedTextChanged, - }); + weakEvents.addWeakEventListener(value, observable.Observable.propertyChangeEvent, this.onFormattedTextChanged, this); } } }