diff --git a/src/org/osflash/signals/IPriorityOnceSignal.as b/src/org/osflash/signals/IPriorityOnceSignal.as new file mode 100644 index 0000000..412d514 --- /dev/null +++ b/src/org/osflash/signals/IPriorityOnceSignal.as @@ -0,0 +1,21 @@ +package org.osflash.signals +{ + public interface IPriorityOnceSignal extends IOnceSignal + { + /** + * Subscribes a one-time listener for this signal. + * The signal will remove the listener automatically the first time it is called, + * after the dispatch to all listeners is complete. + * @param listener A function with an argument + * that matches the type of event dispatched by the signal. + * If eventClass is not specified, the listener and dispatch() can be called without an argument. + * @param priority The priority level of the event listener. + * The priority is designated by a signed 32-bit integer. + * The higher the number, the higher the priority. + * All listeners with priority n are processed before listeners of priority n-1. + * @return a ISlot, which contains the Function passed as the parameter + * @see ISlot + */ + function addOnceWithPriority(listener:Function, priority:int = 0):ISlot + } +} \ No newline at end of file diff --git a/src/org/osflash/signals/Promise.as b/src/org/osflash/signals/Promise.as index 4644c41..afaec9b 100644 --- a/src/org/osflash/signals/Promise.as +++ b/src/org/osflash/signals/Promise.as @@ -5,22 +5,67 @@ package org.osflash.signals import org.osflash.signals.ISlot; import org.osflash.signals.OnceSignal; - public class Promise extends OnceSignal + public class Promise extends OnceSignal implements IPriorityOnceSignal { - private var isDispatched:Boolean; + private var _isDispatched:Boolean; private var valueObjects:Array; + /** Whether to ignore any subsequent calls to dispatch(). By default, subsequent calls will throw an error. */ + public var ignoreSubsequentDipatches:Boolean = false; + + /** + * Creates a Promise instance to dispatch value objects. + * @param valueClasses Any number of class references that enable type checks in dispatch(). + * For example, new Signal(String, uint) + * would allow: signal.dispatch("the Answer", 42) + * but not: signal.dispatch(true, 42.5) + * nor: signal.dispatch() + * + * NOTE: In AS3, subclasses cannot call super.apply(null, valueClasses), + * but this constructor has logic to support super(valueClasses). + */ + public function Promise(...valueClasses) + { + // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). + valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses; + + super(valueClasses); + } + /** @inheritDoc */ override public function addOnce(listener:Function):ISlot { - var slot:ISlot = super.addOnce(listener); - if (isDispatched) + return addOnceWithPriority(listener); + } + + public function addOnceWithPriority(listener:Function, priority:int = 0):ISlot + { + var slot:ISlot = registerListenerWithPriority(listener, true, priority); + + if (_isDispatched) { slot.execute(valueObjects); slot.remove(); } return slot; + } + + override protected function registerListener(listener:Function, once:Boolean = false):ISlot + { + return registerListenerWithPriority(listener, once); + } + + protected function registerListenerWithPriority(listener:Function, once:Boolean = false, priority:int = 0):ISlot + { + if (registrationPossible(listener, once)) + { + const slot:ISlot = new Slot(listener, this, once, priority); + slots = slots.insertWithPriority(slot); + return slot; + } + + return slots.find(listener); } /** @@ -29,16 +74,24 @@ package org.osflash.signals */ override public function dispatch(...valueObjects):void { - if (isDispatched) + if (_isDispatched) { - throw new IllegalOperationError("You cannot dispatch() a Promise more than once"); + if (!ignoreSubsequentDipatches) + { + throw new IllegalOperationError("You cannot dispatch() a Promise more than once"); + } } else { - isDispatched = true; + _isDispatched = true; this.valueObjects = valueObjects; super.dispatch.apply(this, valueObjects); } } + + public function get isDispatched():Boolean + { + return _isDispatched; + } } }