ListenerProxy
The ListenerProxy-Class is an easy to use controller for ActionScript 3 EventListeners. It helps you to easily keep track of all the Listeners you register onto an Object. You are able to
• Add/Remove single Listener to single Object
• Add/Remove single Listener to multiple Objects
• Add/Remove multiple Listeners to single Object
• Add/Remove multiple Listeners to multiple Objects
with a single line if you like :) I prefer using more than one line for better readability.
But there's even more:
• Check if an object has a specified Listener
• Check if an object has a specified Listener, linked to a specified Function (remember, you're able to register multiple Functions to one single Event in ActionScript by default)
• Print a list of all registered EventListeners of a specified Object
Does not work standalone. Instructions included in the code.
/** @private
///// -- DANIELBUNTE.DE -- /////
[CLASS] :: de.danielbunte.utils.listeners.ListenerProxy
[CREATED] :: v.1-alpha 12th February 2009
[VERSION] :: v3.0.0-stable
[MODIFIED] :: 17th April 2012
[AUTHOR] :: Daniel Bunte, Graf-Ludolf-Str. 23, D-31515, Wunstorf (2010)
[AUTHOR] :: Daniel Bunte, Am Heisterholz 2, D-31535, Neustadt am Ruebenberge (2011)
[AUTHOR] :: Daniel Bunte, Reetzer Str. 10a, D-31515, Wunstorf (2011)
/////
[ D E S C R I P T I O N ]
This is the ListenerProxy-class which keeps track of Listeners registred on an Object
END -::- [ D E S C R I P T I O N ]
/////
[ C H A N G E L O G ]
::12th February 2009 { created the class and defined basic methods
[v.1-alpha]
}
::13th February 2009 { completed class with useful functions
[v.1-beta]
}
::19th February 2009 { moved class from com.meinebuntetuete to de.danielbunte for future use; tested functionality
of the class
[v1.0-stable]
}
::23rd February 2009 { modified hasListener- & search-methods, so that the function-param could be null
[v1.1-stable]
}
::16th April 2009 { modified the methods addListener and removeListener so that either a String or even an Array
could be given as strListenerType-parameter
[v1.2-stable]
}
::29th April 2009 { modified the methods addListener and removeListener so that either a String or even an Array
could be given as objToAddTo-parameter
[v1.3-stable]
}
::30th May 2009 { changed all uints to ints, because of performance; added VERSION trace
[v1.3.1-stable]
}
::01st June 2009 { removed a bug that throwed an Error if addListener recieved an Array as Params
[v1.3.2-stable]
}
::22nd June 2009 { made just a few code- & syntax-improvements
[v1.3.3-stable]
}
::06th August 2009 { fixed bug with adding/removing multiple Listeners to multiple Objects (e.g.: ListenerProxy.getInstance().
addListener([this.objFoo, this.objBar], [Event.COMPLETE, ProgressEvent.PROGRESS], this.loadHandler);)
also removed a duplicate if(!objCurrentObject.hasOwnProperty('addEventListener'))
{
throw new Error(ListenerProxy.NO_ABILITY_ERROR + ' => ' + objToAddTo);
}
[v1.3.4-stable]
}
::18th August 2009 { made some formatting- & performance-improvements; removed asterisks as type-definition and
replaced with Object-type; added method to trace all listeners (getListenersListing), so removed
the T O D O; commented out the public static function self(); formatted the C H A N G E L O G
[v1.4.0-stable]
}
::10th January 2010 { now using Vectors to store Listeners, instead of Arrays - that's a lot faster;
completely removed the static method "self", use getInstance instead!;
added ASDocs-like comments;
optimized and shortened if-expressions, now using some switch-statements;
instead of using Arrays for multiple Listeners/Objects, you can also pass a
Vector of type Object/Sprite/Whatever for your Objects and of type String
for the EventListener-Types (it's faster, believe me!);
if an object doesn't have any more Listeners, it is completely remove from
Dictionary, this should happen since v1.0-stable but was obviously a bug.;
Improved and extended Error-Messages
[v2.0.0-stable]
}
::12th February 2010 { added license-message
[v2.0.0-stable]
}
::18th February 2010 { Completely removed Arrays - these are now directly converted into Vector by
using Vector.<Object>(myArr);
[v2.0.1-stable]
}
::25th February 2010 { Arrays can't be converted into a Vector by simply doing vec = myArr as Vector.<T>,
so I had to add the a again. This is obviously a bugfix :)
[v2.0.2-stable]
}
::01st April 2011 { fixed a bug in hasListener that always returned true (wrong comparison between
result >= int(0 - 1) what should be [and now it is] result !== int(0 - 1))
[v2.0.3-stable]
}
::27th July 2011 { pop() now supports multiple objects to be popped at once, pop() doesn't return Objects anymore
optimized loops to while(++i !== len) instead of for(; i < len; ++i);
some other minor optimizations
[v2.1.0-stable]
}
::27th July 2011 { set blnRemoveAllListeners of pop() to true by default
[v2.1.1-stable]
}
::17th April 2012 { added ListenerProxyEntry as an internal class, instead of using an untyped Object
Arrays are now converted into Vector.<String> automatically, so we only need one typed variable for the add/remove methods
cleaned up the code for open source relase
[v3.0.0-stable]
}
END -::- [ C H A N G E L O G ]
/////
*/
package de.danielbunte.utils.listeners
{
import flash.events.TimerEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.utils.Dictionary;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
import flash.utils.Timer;
public class ListenerProxy
{
private static var objClassInstance :ListenerProxy ;
private var dictObjects :Dictionary , //all the objects will be stored here
intNumObjects :int ; //stores the Number of Objects within the Dictionary-Object
private static const NO_ABILITY_ERROR :String = 'ListenerProxy:: Object has no ability to add an EventListener!',
NOT_INITIALIZABLE :String = 'ListenerProxy:: no direct initialization! user ListenerProxy.getInstance() instead.',
SYNTAX_ERROR :String = 'ListenerProxy:: Syntax Error while adding or removing Listener, or popping Object!',
USAGE_INSTRUCTIONS :String = 'ListenerProxy:: Usage Instructions following\n\n' +
'You can avoid this message by using ListenerProxy.getInstance(false) when you use this class the first time in your code.\n\n' +
'This ListenerProxy-Class helps you to easily keep track of all the Listeners you register onto an Object. You are able to\n' +
' • Add/Remove single Listener to single Object\n' +
' • Add/Remove single Listener to multiple Objects\n' +
' • Add/Remove multiple Listeners to single Object \n' +
' • Add/Remove multiple Listeners to multiple Objects\n' +
'with a single line if you like :) I prefer using more than one line for better readability.\n' +
'But there\'s even more:\n' +
' • Check if an object has a specified Listener\n' +
' • Check if an object has a specified Listener, linked to a specified Function (remember, you\'re able to register multiple Functions to one single Event in ActionScript by default)\n' +
' • Print a list of all registered EventListeners of a specified Object\n\n' +
'Case 1 - You want to add one single EventListener to one single Object:\n' +
'ListenerProxy.getInstance.addListener(mySprite, MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tThis is the same as:\n' +
'\tmySprite.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n\n' +
'Case 2 - You want to add one single EventListener to multiple Objects:\n' +
'ListenerProxy.getInstance.addListener([mySprite_1, mySprite_2, mySprite_3], MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tThis is the same as:\n' +
'\tmySprite_1.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite_2.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite_3.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n\n' +
'Case 3 - You want to add multiple EventListeners to one single Object:\n' +
'ListenerProxy.getInstance().addListener(mySprite, [MouseEvent.MOUSE_OVER, MouseEvent.MOUSE_OUT, MouseEvent.CLICK], this.mouseHandler);\n' +
'\t\tN O T E: I always like to do some formatting like this:\n' +
'\t\tListenerProxy.getInstance().addListener(mySprite,\n' +
'\t\t [\n' +
'\t\t MouseEvent.MOUSE_OVER,\n' +
'\t\t MouseEvent.MOUSE_OUT,\n' +
'\t\t MouseEvent.CLICK\n' +
'\t\t ],\n' +
'\t\t this.mouseHandler);\n' +
'\t\tI like it that way and think it\'s better readable, but that\'s just a tip.\n' +
'\tThe above Lines are the same like this:\n' +
'\tmySprite.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite.addEventListener(MouseEvent.MOUSE_OUT, this.mouseHandler);\n' +
'\tmySprite.addEventListener(MouseEvent.CLICK, this.mouseHandler);\n\n' +
'Case 4 - You want to add multiple EventListeners to multiple Objects:\n' +
'ListenerProxy.getInstance.addListener([mySprite_1, mySprite_2, mySprite_3], [MouseEvent.MOUSE_OVER, MouseEvent.MOUSE_OUT, MouseEvent.CLICK], this.mouseHandler);\n' +
'\tThis is the same as:\n' +
'\tmySprite_1.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite_1.addEventListener(MouseEvent.MOUSE_OUT, this.mouseHandler);\n' +
'\tmySprite_1.addEventListener(MouseEvent.CLICK, this.mouseHandler);\n' +
'\tmySprite_2.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite_2.addEventListener(MouseEvent.MOUSE_OUT, this.mouseHandler);\n' +
'\tmySprite_2.addEventListener(MouseEvent.CLICK, this.mouseHandler);\n' +
'\tmySprite_3.addEventListener(MouseEvent.MOUSE_OVER, this.mouseHandler);\n' +
'\tmySprite_3.addEventListener(MouseEvent.MOUSE_OUT, this.mouseHandler);\n' +
'\tmySprite_3.addEventListener(MouseEvent.CLICK, this.mouseHandler);\n\n' +
'Instead of using an Array for multiple Listeners/Objects by using the braces [], you can also pass a Vector with type Object as parameter.\n' +
'That\'d look like this:\n' +
'ListenerProxy.getInstance().addListener(new <Object>[\n' +
' mySprite_1,\n' +
' mySprite_2,\n' +
' mySprite_3\n' +
' ],\n' +
' new <String>[\n' +
' MouseEvent.MOUSE_OVER,\n' +
' MouseEvent.MOUSE_OUT,\n' +
' MouseEvent.CLICK\n' +
' ],\n' +
' this.mouseHandler);\n' +
'This is the recommended way - of course the array-version is easier to type and to teach.\n' +
'For further information on Vector, see this page and especially the user-comments: http://livedocs.adobe.com/flex/3/langref/Vector.html\n\n' +
'ListenerProxy:: End of Usage Instructions',
VERSION :String = 'ListenerProxy:: v3.0.0-stable (17th July 2012) [© by Daniel Bunte - danielbunte.de] | Also visit my agency\'s website http://badnoob.com! We do excellent Flashwork and powerful standalone Server-applications';
/** @private **/
public function ListenerProxy(internalClass:InternalListenerProxy):void //Singleton is used!
{
if(!internalClass)
{
throw new Error(ListenerProxy.NOT_INITIALIZABLE);
}
this.dictObjects = new Dictionary();
}
// -- PUBLIC STATIC METHODS -- //
/**
* Returns an Instance of the Class.
*
* <p>We use a Singleton-Pattern, so only one instance of this class is created at all. We
* only need one, or do you need more? :D</p>
*
* @param blnPrintInstructions If set to true(default) the Usage-Instructions will be traced when the class is initialized.
*
* @return An instance of this Class
*/
public static function getInstance(blnPrintInstructions:Boolean = true):ListenerProxy
{
if(!ListenerProxy.objClassInstance)
{
ListenerProxy.objClassInstance = new ListenerProxy(new InternalListenerProxy());
trace(ListenerProxy.VERSION + ((blnPrintInstructions) ? '\n'+ ListenerProxy.USAGE_INSTRUCTIONS : ''));
}
return ListenerProxy.objClassInstance;
}
// -- PUBLIC METHODS -- //
/**
* Adds one single or multiple Listeners to one single or multiple Objects.
*
* <p>See Usage Instructions for further information.</p>
*
* @param objToAddTo The Object(s) you want to add Listeners to. Can either be an Array, an Object or a Vector.
* @param strListenerType The Listener(s) you want to add to the Object(s). Can either be an Array, a String or a Vector.
* @param funcCallback The EventListener's Handler-Method.
*
* @return void
*/
public function addListener(objToAddTo:Object, objListenerType:Object, funcCallback:Function):void
{
var intNewListenerIndex :int ,
intMinusOne :int = -1 ,
intObjectLen :int ,
intTypeLen :int ,
i :int = -1 ,
j :int ,
objCurrentObject :Object ,
vecObjectIterator :Vector.<Object> ,
vecTypeIterator :Vector.<String> ;
switch(true)
{
case (objListenerType is String) :
{
vecTypeIterator = new <String>[objListenerType as String];
}; break;
case (objListenerType is Vector.<String>) :
{
vecTypeIterator = objListenerType as Vector.<String>;
}; break;
case (objListenerType is Array):
{
vecTypeIterator = Vector.<String>(objListenerType);
}; break;
default :
{
throw new Error(ListenerProxy.SYNTAX_ERROR + ' => ' + objListenerType + '('+ getQualifiedClassName(objToAddTo) +'.'+ getQualifiedSuperclassName(objToAddTo) +')'+ describeType(objToAddTo));
};
}
switch(true)
{
case (objToAddTo is Vector.<Object>) :
{
vecObjectIterator = objToAddTo as Vector.<Object>;
}; break;
case (objToAddTo is Array) :
{
vecObjectIterator = Vector.<Object>(objToAddTo);
}; break;
case (objToAddTo is Object) :
{
vecObjectIterator = new <Object>[objToAddTo];
}; break;
default :
{
throw new Error(ListenerProxy.SYNTAX_ERROR + ' => ' + objToAddTo + '('+ getQualifiedClassName(objToAddTo) +'.'+ getQualifiedSuperclassName(objToAddTo) +')'+ describeType(objToAddTo));
};
}
intObjectLen = vecObjectIterator.length;
intTypeLen = vecTypeIterator.length;
while(++i !== intObjectLen)
{
objCurrentObject = vecObjectIterator[i];
if(this.dictObjects[objCurrentObject] === undefined) //if we don't have this object in dictionary, add it
{
this.push(objCurrentObject);
}
intNewListenerIndex = this.dictObjects[objCurrentObject].length;
j = intMinusOne;
while(++j !== intTypeLen)
{
this.dictObjects[objCurrentObject][intNewListenerIndex] = new ListenerProxyEntry(vecTypeIterator[j], funcCallback); //push into dictionary
objCurrentObject.addEventListener(vecTypeIterator[j], funcCallback); //finally add the listener to the object
++intNewListenerIndex;
}
}
}
/**
* Creates a String-List of all registered EventListeners of the given Object.
*
* <p>If no Object is given as parameter, the Listeners of all Objects are traced.</p>
*
* @param objToList The Object you want to see the list of.
* @param blnTrace If set to true, the created String will be put out via trace. Default is false.
* @param blnNoReturn If set to true, the created String isn't returned. Default is false.
*
* @return List with all Objects and all their EventListeners, if blnNoReturn is set to false.
*/
public function getListenersListing(objToList:Object = null, blnTrace:Boolean = false, blnNoReturn:Boolean = false):String
{
var blnObjectGiven :Boolean = (objToList) ,
intLengthListeners :int ,
i :int ,
objCurrentObject :Object ,
strToReturn :String ,
strCurrent :String ;
if(blnTrace === false && blnNoReturn === true) return null;
createListing: //label to be broken by an inner loop
{
for(objCurrentObject in this.dictObjects)
{
/**
* If there's an Object given as parameter, just overwrite the
* current object with that one, so we don't need to trace the
* whole dictionary.
*/
if(blnObjectGiven === true
&& objCurrentObject !== objToList)
{
if(this.dictObjects[objToList] === undefined) return null;
objCurrentObject = objToList;
}
intLengthListeners = this.dictObjects[objCurrentObject].length;
i = -1;
while(++i !== intLengthListeners)
{
strCurrent = 'ListenerProxy::getListenersListing => '+ objCurrentObject +'\tlistener:\t\t\t'+ this.dictObjects[objCurrentObject][i].type +'\t\t\tcallback: '+ getQualifiedClassName(this.dictObjects[objCurrentObject][i].callback) +'.'+ this.dictObjects[objCurrentObject][i].callback +'['+ this.dictObjects[objCurrentObject][i].callback.length +' parameter]';
if(blnNoReturn === false)
{
strToReturn += strCurrent;
}
if(blnTrace === true)
{
trace(strCurrent);
}
}
/**
* If an Object is given, we can break the whole loop here.
*/
if(blnObjectGiven === true)
{
break createListing;
}
}// end of for(objCurrentObject in this.dictObjects)
}//end of createListing:
if(blnNoReturn === false)
{
return strToReturn;
}
return null; //the script will never get here, yeah, you're right, but we need this, because otherwise we'll get an error from the complier saying that the method doesn't return any value
}
/**
* Checks an Object for a listener-type.
*
* <p>If you want to know if the specified Object already has a Listener of the specified type "strListenerType"
* registered, you can use this method. You can also check if a specified Function is registered to that Event.
* This is useful, because you're able to register multiple Functions with an Event. This of course only works
* correct if you use the ListenerProxy-Class instead of ActionScript's addEventListener-Function.</p>
*
* @param objToAsk This is the object we want to check.
* @param strListenerType This is the Type of Event you want to check for.
* @param funcCallback This is the eventHandler-Function you want to check for.
*
* @return Returns true if the Listener exists, otherwise returns false. Also returns false if the Object isn't registered within the ListenerProxy.
*/
public function hasListener(objToAsk:Object, strListenerType:String, funcCallback:Function = null):Boolean
{
if(this.dictObjects[objToAsk] === undefined) return false; //if we don't have this object in dictionary, return
if(this.search(objToAsk, strListenerType, funcCallback) !== -1) return true;
return false;
}
/**
* Deletes the specified Object, Array or Vector.<Object> from the Dictionary.
*
* <p>Caution! Doesn't work like Array.pop()!
* this function just removes the specified
* Objects from the Dictionary. You can't do just a pop(), because the Class is not
* really indexed, so you have to specifiy the object you want to remove.</p>
*
* @param objToPop The object you want to remove from Dictionary. Can Either be an Object, Array or Vector.<Object> (to remove multiple Objects at once).
* @param blnRemoveAllListeners If set to true, all registered Listeners of all the Objects given as objToPop will be deleted. Default is true.
*/
public function pop(objToPop:Object, blnRemoveAllListeners:Boolean = true):void
{
if(objToPop === null) return;
var intIndexOfListener :int ,
intMinusOne :int = -1 ,
intObjectLen :int ,
intListenerLen :int ,
intZero :int ,
i :int = -1 ,
j :int = -1 ,
objCurrentEntry :ListenerProxyEntry ,
objCurrentObject :Object ,
vecObjectIterator :Vector.<Object> ,
vecListeners :Vector.<ListenerProxyEntry> ;
switch(true)
{
case (objToPop is Object) :
{
vecObjectIterator = new <Object>[objToPop];
}; break;
case (objToPop is Vector.<Object>) :
{
vecObjectIterator = objToPop as Vector.<Object>;
}; break;
case (objToPop is Array) :
{
vecObjectIterator = Vector.<Object>(objToPop);
}; break;
default :
{
throw new Error(ListenerProxy.SYNTAX_ERROR + ' => ' + objToPop + '('+ getQualifiedClassName(objToPop) +'.'+ getQualifiedSuperclassName(objToPop) +')'+ describeType(objToPop));
};
}
intObjectLen = vecObjectIterator.length;
while(++i !== intObjectLen)
{
objCurrentObject = vecObjectIterator[i];
if(this.dictObjects[objCurrentObject] === undefined) //if we don't have this object in dictionary, continue
{
continue;
}
if(blnRemoveAllListeners === true)
{
vecListeners = this.dictObjects[objCurrentObject];
intListenerLen = vecListeners.length;
j = intMinusOne;
while(++j !== intListenerLen)
{
objCurrentEntry = vecListeners[intZero];
this.internalRemoveListener(objCurrentObject, objCurrentEntry.type, objCurrentEntry.callback, intZero, false);
}
}
delete this.dictObjects[objCurrentObject];
--this.intNumObjects;
}
}
/**
* Appends a the given Object to the Dictionary.
*
* @param objToPush The Object that you want to append to the Dictionary
*
* @return void
*/
public function push(objToPush:Object):void
{
if(objToPush.hasOwnProperty('addEventListener') === false) //if the object itself doesn't have the ability to add an eventlistener, don't add to dictionary
{
throw new Error(ListenerProxy.NO_ABILITY_ERROR + ' => ' + objToPush + '('+ getQualifiedClassName(objToPush) +'.'+ getQualifiedSuperclassName(objToPush) +')'+ describeType(objToPush));
}
if(this.dictObjects[objToPush] === undefined) //if it doesn't exist already
{
this.dictObjects[objToPush] = new<ListenerProxyEntry>[];
++this.intNumObjects;
}
}
/**
* Removes one single or multiple Listeners from one single or multiple Objects.
*
* <p>If there are no more EventListeners on a Object, it is removed from Dictionary.
* See Usage Instructions for further information.</p>
*
* @param objToRemoveFrom The Object(s) you want remove Listeners from. Can either be an Array, an Object or a Vector.
* @param strListenerType The Listener(s) you want to remove from the Object(s). Can either be an Array, a String or a Vector.
* @param funcCallback The EventListener's Handler-Method.
*
* @return void
*/
public function removeListener(objToRemoveFrom:Object, strListenerType:Object, funcCallback:Function):void
{
var intIndexOfListener :int ,
intMinusOne :int = -1 ,
intObjectLen :int ,
intTypeLen :int ,
i :int = -1 ,
j :int ,
objCurrentObject :Object ,
vecObjectIterator :Vector.<Object> ,
vecTypeIterator :Vector.<String> ;
switch(true)
{
case (strListenerType is String) :
{
vecTypeIterator = new <String>[strListenerType as String];
}; break;
case (strListenerType is Vector.<String>) :
{
vecTypeIterator = strListenerType as Vector.<String>;
}; break;
case (strListenerType is Array) :
{
vecTypeIterator = Vector.<String>(strListenerType);
}; break;
default :
{
throw new Error(ListenerProxy.SYNTAX_ERROR + ' => ' + strListenerType + '('+ getQualifiedClassName(objToRemoveFrom) +'.'+ getQualifiedSuperclassName(objToRemoveFrom) +')'+ describeType(objToRemoveFrom));
};
}
switch(true)
{
case (objToRemoveFrom is Object) :
{
vecObjectIterator = new <Object>[objToRemoveFrom];
}; break;
case (objToRemoveFrom is Vector.<Object>) :
{
vecObjectIterator = objToRemoveFrom as Vector.<Object>;
}; break;
case (objToRemoveFrom is Array) :
{
vecObjectIterator = Vector.<Object>(objToRemoveFrom);
}; break;
default :
{
throw new Error(ListenerProxy.SYNTAX_ERROR + ' => ' + objToRemoveFrom + '('+ getQualifiedClassName(objToRemoveFrom) +'.'+ getQualifiedSuperclassName(objToRemoveFrom) +')'+ describeType(objToRemoveFrom));
};
}
intObjectLen = vecObjectIterator.length;
intTypeLen = vecTypeIterator.length;
while(++i !== intObjectLen)
{
objCurrentObject = vecObjectIterator[i];
if(this.dictObjects[objCurrentObject] === undefined) //if we don't have this object in dictionary, return
{
continue;
}
j = intMinusOne;
while(++j !== intTypeLen)
{
intIndexOfListener = this.search(objCurrentObject, vecTypeIterator[j], funcCallback)
if(intIndexOfListener === intMinusOne) continue; //if the listener couldn't be found, continue with next one
this.internalRemoveListener(objCurrentObject, vecTypeIterator[j], funcCallback, intIndexOfListener);
}
}
}
// -- PRIVATE METHODS -- //
/** @private **/
private function internalRemoveListener(objToRemoveFrom:Object, strListenerType:String, funcCallback:Function, intIndexOfListener:int, blnAutoDeleteFromDictionary:Boolean = true):void
{
//first remove the listener from the object itself
var objCurrentEntry :ListenerProxyEntry = this.dictObjects[objToRemoveFrom][intIndexOfListener],
strType :String = objCurrentEntry.type,
funcCallback :Function = objCurrentEntry.callback;
if(objToRemoveFrom.hasEventListener(strType) === true) //secure that the object has this listener
{
objToRemoveFrom.removeEventListener(strType, funcCallback);
}
//void variables
strType = null;
//void the listener
objCurrentEntry.destruct();
objCurrentEntry = null;
this.dictObjects[objToRemoveFrom].splice(intIndexOfListener, 1);
if(blnAutoDeleteFromDictionary === true && this.dictObjects[objToRemoveFrom].length === 0)
{
this.pop(objToRemoveFrom);
}
}
/** @private **/
private function search(objToSearchIn:Object, strListenerType:String, callback:Function = null):int
{
if(this.intNumObjects === 0) //no objects in dictionary, so return -1
{
return -1;
}
if(this.dictObjects[objToSearchIn] === undefined) //current object is not in dictionary, so return -1
{
return -1;
}
var i :int = -1 ,
intLength :int = this.dictObjects[objToSearchIn].length ,
intCurrentTypeCount :int ,
objCurrentEntry :ListenerProxyEntry ;
while(++i !== intLength)
{
objCurrentEntry = this.dictObjects[objToSearchIn][i];
if( objCurrentEntry.type === strListenerType
&& objCurrentEntry.callback === callback )
{
return i; //if the specified listener is found, return the index
}
if( objCurrentEntry.type === strListenerType
&& callback === null )
{
++intCurrentTypeCount; //count the number of registred listeners for this type in the case that callback is not defined
}
}
//used if callback is not defined within the params
if(intCurrentTypeCount === 1) //we've counted the number of registred listeners for the searched listenertype
{
return 0; //we've only one registred listeners for this type, so return index 0
}
return -1; //if nothing is found, return -1
}
// -- GETTERS AND SETTERS -- //
/**
* Returns the number of the registered Objects
*
* @return Number of registered Objects
*/
public function get length():int
{
return this.intNumObjects;
}
}
}
//the following class is used for Singleton-Pattern, so only one instance can exist
internal class InternalListenerProxy {}
internal class ListenerProxyEntry
{
private var funcCallback :Function ,
strType :String ;
public function ListenerProxyEntry(strType:String, funcCallback:Function):void
{
this.funcCallback = funcCallback ;
this.strType = strType ;
}
// -- PUBLIC METHODS -- //
public function destruct():void
{
this.funcCallback = null;
this.strType = null;
}
// -- GETTERS AND SETTERS -- //
public function get callback():Function
{
return this.funcCallback;
}
public function set callback(funcCallback:Function):void
{
this.funcCallback = funcCallback;
}
public function get type():String
{
return this.strType;
}
public function set type(strValue:String):void
{
this.strType = strValue;
}
}