Skip to content

Adding safe event listeners, [Event] metadata autowiring, and a basic phase validation implementation. #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
11 changes: 1 addition & 10 deletions src/utils/error/getStackTrace.as
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ package utils.error
*/
public function getStackTrace():String
{
try
{
throw new Error();
}
catch (err:Error)
{
return err.getStackTrace();
}
// It's impossible to reach this
return null;
return new Error().getStackTrace();
}
}
16 changes: 10 additions & 6 deletions src/utils/event/addTargetEventListener.as
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package utils.event
{
import flash.display.DisplayObject;
import flash.events.IEventDispatcher;

public function addTargetEventListener(_target:DisplayObject, _type:String, _listener:Function, _useCapture:Boolean = false, _priority:int = 0, _useWeakReference:Boolean = true):void
public function addTargetEventListener(target:IEventDispatcher,
type:String,
listener:Function,
useWeakReference:Boolean = true,
useCapture:Boolean = false,
priority:int = 0):void
{
if (_target != null)
{
_target.addEventListener(_type, _listener, _useCapture, _priority, _useWeakReference);
}
if(!target) return;

target.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
}
13 changes: 13 additions & 0 deletions src/utils/event/getSafeEventHandler.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package utils.event
{
import flash.events.Event;

public function getSafeEventHandler(func:Function):Function
{
safeEventHandlers[func] ||= function(event:Event):void {
func.length ? func(event) : func();
}

return safeEventHandlers[func];
}
}
13 changes: 8 additions & 5 deletions src/utils/event/removeTargetEventListener.as
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package utils.event
{
import flash.display.DisplayObject;
import flash.events.IEventDispatcher;

public function removeTargetEventListener(_target:DisplayObject, _type:String, _listener:Function, _useCapture:Boolean = false):void
public function removeTargetEventListener(target:IEventDispatcher,
type:String,
listener:Function,
useCapture:Boolean = false):void
{
if (_target != null)
{
_target.removeEventListener(_type, _listener, _useCapture);
}
if(!target) return;

target.removeEventListener(type, listener, useCapture);
}
}
5 changes: 5 additions & 0 deletions src/utils/event/safeEventHandlers.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package utils.event
{
import flash.utils.Dictionary;
internal const safeEventHandlers:Dictionary = new Dictionary(false);
}
12 changes: 12 additions & 0 deletions src/utils/event/trashSafeEventHandler.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package utils.event
{
public function trashSafeEventHandler(func:Function):Function
{
if(!(func in safeEventHandlers))
return null;

const handler:Function = safeEventHandlers[func];
delete safeEventHandlers[func];
return handler;
}
}
31 changes: 31 additions & 0 deletions src/utils/metadata/unwireEvents.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package utils.metadata
{
import flash.events.IEventDispatcher;
import flash.utils.Dictionary;

import utils.event.getSafeEventHandler;
import utils.event.removeTargetEventListener;
import utils.event.trashSafeEventHandler;
import utils.type.describeMethods;

public function unwireEvents(target:IEventDispatcher):void
{
var methods:XMLList = describeMethods(target, 'Event');
var type:String;
var func:*;
var dict:Dictionary = new Dictionary(false);

for each(var m:XML in methods)
{
for each(var meta:XML in m.metadata.(@name=="Event"))
{
type = [email protected]();
dict[func = target[m.name()]] = true;
removeTargetEventListener(target, type, getSafeEventHandler(func));
}
}

for(func in dict)
trashSafeEventHandler(func);
}
}
22 changes: 22 additions & 0 deletions src/utils/metadata/wireEvents.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package utils.metadata
{
import flash.events.IEventDispatcher;

import utils.event.addTargetEventListener;
import utils.event.getSafeEventHandler;
import utils.type.describeMethods;

public function wireEvents(target:IEventDispatcher):void
{
var methods:XMLList = describeMethods(target, 'Event');
var type:String;
for each(var m:XML in methods)
{
for each(var meta:XML in m.metadata.(@name=="Event"))
{
type = [email protected]();
addTargetEventListener(target, type, getSafeEventHandler(target[m.@name]), false);
}
}
}
}
57 changes: 57 additions & 0 deletions src/utils/syncro/Phase.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package utils.syncro
{
import flash.events.Event;
import flash.events.IEventDispatcher;

internal dynamic class Phase extends Array
{
public function Phase(name:String, priority:int, ascending:Boolean)
{
_name = name;
_priority = priority;
_ascending = ascending;

super();
}

private var _ascending:Boolean = true;

private var _name:String = '';
public function get name():String
{
return _name;
}

private var _priority:int = 0;
public function get priority():int
{
return _priority;
}

public function render():void
{
if(_ascending)
reverse();

var obj:Object;

// Protective clone so items added during
// validation don't cause an infinite loop.
var protect:Array = concat();

// Clear the list so items can be added during validation.
length = 0;
var n:int = protect.length;

while(--n >= 0)
{
obj = protect.pop();

if(name in obj)
obj[name]();
else if(obj is IEventDispatcher)
IEventDispatcher(obj).dispatchEvent(new Event(name));
}
}
}
}
11 changes: 11 additions & 0 deletions src/utils/syncro/addphase.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package utils.syncro
{
public function addphase(name:String, priority:int = 0, ascending:Boolean = true):void
{
if(name in syncro.names)
return;

var phase:Phase = syncro.names[name] = new Phase(name, priority, ascending);
syncro.phases.push(phase);
}
}
25 changes: 25 additions & 0 deletions src/utils/syncro/invalidate.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package utils.syncro
{
import utils.display.wait;

public function invalidate(target:Object, depth:int, name:String):void
{
if(!(name in syncro.names))
return;

var phase:Array = syncro.phases.filter(function(e:Phase, ...args):Boolean{
return e.name == name;
})[0];

if(!phase || phase.indexOf(target) != -1)
return;

phase.splice(depth, 0, target);

if(syncro.invalidated)
return;

syncro.invalidated = true;
wait(1, render);
}
}
14 changes: 14 additions & 0 deletions src/utils/syncro/render.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package utils.syncro
{
public function render():void
{
var p:Array = syncro.phases;
p.sortOn('priority');

//Set this before validating.
syncro.invalidated = false;

for(var i:int = 0, n:int = p.length; i < n; i += 1)
Phase(p[i]).render();
}
}
9 changes: 9 additions & 0 deletions src/utils/syncro/syncro.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package utils.syncro
{
internal class syncro
{
internal static var invalidated:Boolean = false;
internal static const phases:Array = [];
internal static const names:Array = [];
}
}