Skip to content

Commit

Permalink
Adding option to be observable by interface vs utility.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Wright committed Feb 15, 2010
1 parent 51c0015 commit a3e843f
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 48 deletions.
2 changes: 2 additions & 0 deletions project/.flexLibProperties
Expand Up @@ -69,6 +69,8 @@
<classEntry path="flight.view.MediatorMap"/>
<classEntry path="flight.vo.IValueObject"/>
<classEntry path="flight.vo.ValueObject"/>
<classEntry path="flight.observers.IObservable"/>
<classEntry path="flight.observers.Observable"/>
</includeClasses>
<includeResources/>
<namespaceManifests>
Expand Down
Binary file modified project/bin/flight-framework.swc
Binary file not shown.
13 changes: 7 additions & 6 deletions project/src/flexUnitTests/binding/ObservingBindTest.as
Expand Up @@ -218,10 +218,11 @@ import flash.events.EventDispatcher;
import flash.utils.Dictionary;

import flight.binding.Binding;
import flight.observers.Observable;
import flight.observers.Observe;


internal class TestObject
internal class TestObject extends Observable
{
private var _str:String;
private var _num:Number;
Expand All @@ -239,7 +240,7 @@ internal class TestObject
public function set obj(value:TestObject):void
{
if (_obj == value) return;
Observe.notifyChange(this, "obj", _obj, _obj = value);
notifyChange("obj", _obj, _obj = value);
}

[Bindable(observable)]
Expand All @@ -251,7 +252,7 @@ internal class TestObject
public function set bool(value:Boolean):void
{
if (_bool == value) return;
Observe.notifyChange(this, "bool", _bool, _bool = value);
notifyChange("bool", _bool, _bool = value);
}

[Bindable(observable)]
Expand All @@ -263,7 +264,7 @@ internal class TestObject
public function set num(value:Number):void
{
if (_num == value) return;
Observe.notifyChange(this, "num", _num, _num = value);
notifyChange("num", _num, _num = value);
}

[Bindable(observable)]
Expand All @@ -275,7 +276,7 @@ internal class TestObject
public function set str(value:String):void
{
if (_str == value) return;
Observe.notifyChange(this, "str", _str, _str = value);
notifyChange("str", _str, _str = value);
}

[Bindable(observable)]
Expand All @@ -287,7 +288,7 @@ internal class TestObject
public function set custom(value:String):void
{
if (_custom == value) return;
Observe.notifyChange(this, "custom", _custom, _custom = value);
notifyChange("custom", _custom, _custom = value);
}

public function clone():TestObject
Expand Down
7 changes: 5 additions & 2 deletions project/src/flight/binding/Binding.as
Expand Up @@ -5,6 +5,7 @@ package flight.binding
import flash.utils.Dictionary;

import flight.events.PropertyEvent;
import flight.observers.IObservable;
import flight.observers.Observe;
import flight.utils.Type;
import flight.utils.getClassName;
Expand Down Expand Up @@ -177,7 +178,8 @@ package flight.binding
if (propName && _twoWay || type == SOURCE || pathIndex < len-1) {
var changeEvents:Array = getBindingEvents(item, propName);
if (changeEvents[0] == "observable") {
Observe.observe(item, propName, null, propertyChange);
if (item is IObservable) IObservable(item).addObserver(propName, null, propertyChange);
else Observe.addObserver(item, propName, null, propertyChange);
} else if (item is IEventDispatcher) {
for each (var changeEvent:String in changeEvents) {
IEventDispatcher(item).addEventListener(changeEvent, onPropertyChange, false, 100, true);
Expand Down Expand Up @@ -222,7 +224,8 @@ package flight.binding
var propName:String = getPropName(path[index]);
var changeEvents:Array = getBindingEvents(item, propName);
if (changeEvents[0] == "observable") {
Observe.stopObserving(item, propName, propertyChange);
if (item is IObservable) IObservable(item).removeObserver(propName, propertyChange);
else Observe.removeObserver(item, propName, propertyChange);
} else if (item is IEventDispatcher) {
for each (var changeEvent:String in changeEvents) {
IEventDispatcher(item).removeEventListener(changeEvent, onPropertyChange);
Expand Down
16 changes: 16 additions & 0 deletions project/src/flight/observers/IObservable.as
@@ -0,0 +1,16 @@
package flight.observers
{
import flash.events.IEventDispatcher;

public interface IObservable
{
function addCheck(property:String, observerHost:IEventDispatcher, observer:Function):void;
function removeCheck(property:String, observer:Function):void;

function addHook(property:String, observerHost:IEventDispatcher, observer:Function):void;
function removeHook(property:String, observer:Function):void;

function addObserver(property:String, observerHost:IEventDispatcher, observer:Function):void;
function removeObserver(property:String, observer:Function):void;
}
}
152 changes: 152 additions & 0 deletions project/src/flight/observers/Observable.as
@@ -0,0 +1,152 @@
package flight.observers
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.utils.Dictionary;

public class Observable extends EventDispatcher implements IObservable
{
private var target:IObservable;
private var properties:Object = {};

public function Observable(target:IObservable = null)
{
this.target = target || this;
}

public function addCheck(property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(Observe.CHECK, property, observerHost, observer);
}

public function removeCheck(property:String, observer:Function):void
{
removeFunction(property, observer);
}

public function addHook(property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(Observe.HOOK, property, observerHost, observer);
}

public function removeHook(property:String, observer:Function):void
{
removeFunction(property, observer);
}

public function addObserver(property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(Observe.OBSERVE, property, observerHost, observer);
}

public function removeObserver(property:String, observer:Function):void
{
removeFunction(property, observer);
}

public function canChange(property:String, oldValue:*, newValue:*):Boolean
{
var check:Boolean = true;

var checks:Dictionary = properties[property];
if (checks) {
check = runFunctions(Observe.CHECK, checks, property, oldValue, newValue);
if (!check) return false;
}

checks = properties["*"];
if (checks) {
check = runFunctions(Observe.CHECK, checks, property, oldValue, newValue);
if (!check) return false;
}

var typeChecks:Array = Observe.findTypeObservers(target, property);
for each (checks in typeChecks) {
check = runFunctions(Observe.CHECK, checks, property, oldValue, newValue);
if (!check) return false;
}

return true;
}

public function modifyChange(property:String, oldValue:*, newValue:*):*
{
var hooks:Dictionary = properties[property];
if (hooks) {
newValue = runFunctions(Observe.HOOK, hooks, property, oldValue, newValue);
}

hooks = properties["*"];
if (hooks) {
newValue = runFunctions(Observe.HOOK, hooks, property, oldValue, newValue);
}

var typeHooks:Array = Observe.findTypeObservers(target, property);
for each (hooks in typeHooks) {
newValue = runFunctions(Observe.HOOK, hooks, property, oldValue, newValue);
}
}

public function notifyChange(property:String, oldValue:*, newValue:*):void
{
var observers:Dictionary = properties[property];
if (observers) {
runFunctions(Observe.OBSERVE, observers, property, oldValue, newValue);
}

observers = properties["*"];
if (observers) {
runFunctions(Observe.OBSERVE, observers, property, oldValue, newValue);
}

var typeObservers:Array = Observe.findTypeObservers(target, property);
for each (observers in typeObservers) {
runFunctions(Observe.OBSERVE, observers, property, oldValue, newValue);
}
}

private function addFunction(type:String, property:String, observerHost:IEventDispatcher, observer:Function):void
{
var funcs:Dictionary = properties[property];
if (!funcs) {
properties[property] = funcs = new Dictionary(true);
}

funcs[observer] = type;
if (observerHost != null) {
observerHost.addEventListener("_", observer);
}
}

private function removeFunction(property:String, observer:Function):void
{
var observers:Dictionary = properties[property];
if (!observers) return;

delete observers[observer];
}

private function runFunctions(type:String, funcs:Dictionary, property:String, oldValue:*, newValue:*):*
{
var result:*;
for (var i:Object in funcs) {
if (funcs[i] != type) continue;
var func:Function = i as Function;
if (func.length == 0) {
result = func.call();
} else if (func.length == 1) {
result = func.call(null, newValue);
} else if (func.length == 2) {
result = func.call(null, oldValue, newValue);
} else if (func.length == 3) {
result = func.call(null, property, oldValue, newValue);
} else {
result = func.call(null, target, property, oldValue, newValue);
}
if (type == Observe.CHECK && result == false) return false;
if (type == Observe.HOOK) newValue = result;
}
return newValue;
}
}
}
50 changes: 10 additions & 40 deletions project/src/flight/observers/Observe.as
Expand Up @@ -5,72 +5,42 @@ package flight.observers

public class Observe
{
private static const CHECK:String = "check";
private static const HOOK:String = "hook";
private static const OBSERVE:String = "observe";
public static const CHECK:String = "check";
public static const HOOK:String = "hook";
public static const OBSERVE:String = "observe";
private static var targets:Dictionary = new Dictionary(true);
private static var types:Dictionary = new Dictionary(true);

public static function check(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
public static function addCheck(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(CHECK, target, property, observerHost, observer);
}

public static function stopChecking(target:Object, property:String, observer:Function):void
public static function removeCheck(target:Object, property:String, observer:Function):void
{
removeFunction(target, property, observer);
}

public static function checkAll(target:Object, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(CHECK, target, "*", observerHost, observer);
}

public static function stopCheckingAll(target:Object, observer:Function):void
{
removeFunction(target, "*", observer);
}

public static function hook(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
public static function addHook(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(OBSERVE, target, property, observerHost, observer);
}

public static function stopHooking(target:Object, property:String, observer:Function):void
public static function removeHook(target:Object, property:String, observer:Function):void
{
removeFunction(target, property, observer);
}

public static function hookAll(target:Object, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(OBSERVE, target, "*", observerHost, observer);
}

public static function stopHookinAll(target:Object, observer:Function):void
{
removeFunction(target, "*", observer);
}

public static function observe(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
public static function addObserver(target:Object, property:String, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(OBSERVE, target, property, observerHost, observer);
}

public static function stopObserving(target:Object, property:String, observer:Function):void
public static function removeObserver(target:Object, property:String, observer:Function):void
{
removeFunction(target, property, observer);
}

public static function observeAll(target:Object, observerHost:IEventDispatcher, observer:Function):void
{
addFunction(OBSERVE, target, "*", observerHost, observer);
}

public static function stopObservingAll(target:Object, observer:Function):void
{
removeFunction(target, "*", observer);
}

public static function release(target:Object):void
{
var storage:Dictionary = target is Class ? types : targets;
Expand Down Expand Up @@ -211,7 +181,7 @@ package flight.observers
return newValue;
}

private static function findTypeObservers(target:Object, property:String):Array
public static function findTypeObservers(target:Object, property:String):Array
{
var observers:Array = [];
for (var i:Object in types) {
Expand Down

0 comments on commit a3e843f

Please sign in to comment.