From 3b944e1ba531be431d396d733f81bd64142a0234 Mon Sep 17 00:00:00 2001 From: atanasovg Date: Tue, 3 Jun 2014 13:53:55 +0300 Subject: [PATCH] Initial prototype of Observable object --- BCL.csproj | 9 +++ ui/core/observable.ts | 113 +++++++++++++++++++++++++++++- ui/core/proxy.ts | 12 ++++ ui/core/view.ts | 6 +- ui/text-view/text-view.android.ts | 21 ++++++ ui/text-view/text-view.common.ts | 14 ++++ ui/text-view/text-view.d.ts | 1 + ui/text-view/text-view.ios.ts | 5 ++ 8 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 ui/core/proxy.ts create mode 100644 ui/text-view/text-view.android.ts create mode 100644 ui/text-view/text-view.common.ts create mode 100644 ui/text-view/text-view.d.ts create mode 100644 ui/text-view/text-view.ios.ts diff --git a/BCL.csproj b/BCL.csproj index 84ea30936..b5e8216d0 100644 --- a/BCL.csproj +++ b/BCL.csproj @@ -152,6 +152,15 @@ text.d.ts + + + text-view.d.ts + + + + + text-view.d.ts + diff --git a/ui/core/observable.ts b/ui/core/observable.ts index 19a76f130..0213f18bb 100644 --- a/ui/core/observable.ts +++ b/ui/core/observable.ts @@ -1 +1,112 @@ - \ No newline at end of file +export enum ChangePhase { + Changing, + Changed +} + +export interface ChangeData { + eventName: string; + sender: Observable; + phase?: ChangePhase; +} + +export interface PropertyChangeData extends ChangeData { + propertyName: string; + oldValue: any; + newValue: any; + cancel?: boolean; +} + +export class Observable { + public static propertyChangeEvent = "propertyChange"; + private _observers = {}; + + // true to track the Changing phase, false otherwise + private _trackChanging = false; + + public bind(eventName: string, callback: (data: ChangeData) => void) { + this.verifyCallback(callback); + var list = this.getEventList(eventName, true); + list.push(callback); + } + + public setProperty(name: string, value: any) { + // TODO: Parameter validation + + if (!(name in this._observers)) { + // no observers to notify for the PropertyChange event + return; + } + + // create data for the change + var data: PropertyChangeData = { + eventName: Observable.propertyChangeEvent, + propertyName: name, + sender: this, + oldValue: this[name], + newValue: value, + cancel: false + }; + + if (this._trackChanging) { + data.phase = ChangePhase.Changing; + this.notifyObservers(data); + if (data.cancel) { + // change is canceled by an observer + // TODO: define some priority, e.g. if someone cancels the change should others be able to override this cancelation? + return; + } + } + + data.phase = ChangePhase.Changed; + this.notifyObservers(data); + + this.setPropertyCore(data); + } + + public getProperty(name: string): any { + return this[name]; + } + + /** + * This method is intended to be overriden by inheritors to specify additional + */ + public setPropertyCore(data: PropertyChangeData) { + // get the new value from the data since some observer may have it modified - e.g. validation scenario + this[data.eventName] = data.newValue; + } + + private getEventList(eventName: string, createIfNeeded?: boolean): Array<(data: ChangeData) => void> { + if (!eventName) { + throw new TypeError("EventName must be valid string."); + } + + var list = void>>this._observers[eventName]; + if (!list && createIfNeeded) { + list = new Array<(data: ChangeData) => void>(); + this._observers[eventName] = list; + } + + return list; + } + + private verifyCallback(callback: any) { + if (!callback || typeof callback !== "function") { + throw new TypeError("Callback must be a valid function."); + } + } + + // The method will return true if the change is accepted, false otherwise + private notifyObservers(data: ChangeData) { + var observers = this.getEventList(data.eventName); + if (!observers) { + return; + } + + var i, + callback; + for (i = 0; i < observers.length; i++) { + callback = observers[i]; + callback(data); + } + } +} \ No newline at end of file diff --git a/ui/core/proxy.ts b/ui/core/proxy.ts new file mode 100644 index 000000000..b5f88f92b --- /dev/null +++ b/ui/core/proxy.ts @@ -0,0 +1,12 @@ +import observable = require("ui/core/observable"); + +export class ProxyObject extends observable.Observable { + public setPropertyCore(data: observable.PropertyChangeData) { + super.setPropertyCore(data); + this.setNativeProperty(data); + } + + public setNativeProperty(data: observable.PropertyChangeData) { + // TODO: + } +} \ No newline at end of file diff --git a/ui/core/view.ts b/ui/core/view.ts index 19a76f130..0c1db8d9a 100644 --- a/ui/core/view.ts +++ b/ui/core/view.ts @@ -1 +1,5 @@ - \ No newline at end of file +import proxy = require("ui/core/proxy"); + +export class View extends proxy.ProxyObject { + +} \ No newline at end of file diff --git a/ui/text-view/text-view.android.ts b/ui/text-view/text-view.android.ts new file mode 100644 index 000000000..9a401df34 --- /dev/null +++ b/ui/text-view/text-view.android.ts @@ -0,0 +1,21 @@ +import observable = require("ui/core/observable"); +import view = require("ui/core/view"); + +export class TextView extends view.View { + public android: android.widget.TextView; + + get text(): string { + if (this.android) { + return this.android.getText().toString(); + } + + return undefined; + } + set text(value: string) { + + } + + public setNativeProperty(data: observable.PropertyChangeData) { + // TODO: + } +} \ No newline at end of file diff --git a/ui/text-view/text-view.common.ts b/ui/text-view/text-view.common.ts new file mode 100644 index 000000000..1f46d6a8e --- /dev/null +++ b/ui/text-view/text-view.common.ts @@ -0,0 +1,14 @@ +import observable = require("ui/core/observable"); +import view = require("ui/core/view"); + +export class TextView extends view.View { + public static textProperty = "text"; + + get text(): string { + return this.getProperty(TextView.textProperty); + } + + public setNativeProperty(data: observable.PropertyChangeData) { + // TODO: + } +} \ No newline at end of file diff --git a/ui/text-view/text-view.d.ts b/ui/text-view/text-view.d.ts new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/ui/text-view/text-view.d.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/text-view/text-view.ios.ts b/ui/text-view/text-view.ios.ts new file mode 100644 index 000000000..fbada2d49 --- /dev/null +++ b/ui/text-view/text-view.ios.ts @@ -0,0 +1,5 @@ +import view = require("ui/core/view"); + +export class TextView extends view.View { + +} \ No newline at end of file