Skip to content

Instantly share code, notes, and snippets.

@bustardcelly
Created November 4, 2011 20:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bustardcelly/1340472 to your computer and use it in GitHub Desktop.
Save bustardcelly/1340472 to your computer and use it in GitHub Desktop.
Deferred IViewElement attachment to a subclass of Group on which children are defined in MXML markup.
package
{
import flash.events.Event;
import mx.events.FlexEvent;
import spark.components.Group;
/**
* Use the deferredElements property as the modifier that is handed the list of IVisualElements defined in MXML.
*/
[DefaultProperty("deferredElements")]
/**
* Group container extension in order to do deferred child element attachment.
*/
public class DeferredGroup extends Group
{
protected var _elementAddQuota:int = 10;
/* IVisualElement[] */
protected var _deferredElements:Array;
protected var _deferredElementsChanged:Boolean;
protected var _deferredElementAttacher:IDeferredElementAttacher;
public function DeferredGroup()
{
super();
}
/**
* @inheritDoc
*/
override protected function commitProperties():void
{
super.commitProperties();
if( _deferredElementsChanged )
{
queueDeferredElements();
_deferredElementsChanged = false;
}
}
/**
* Defines and executes the IDeferredElementAttacher implementation used in queue-ing up "packs" of IVisualElement instances declared in MXML and assigned as deferredElements.
*/
protected function queueDeferredElements():void
{
// Define IDeferredElementAttacher and listen for completion on attach of all elements within deferredElements.
_deferredElementAttacher = new FrameDeferredElementAttacher( this );
_deferredElementAttacher.addEventListener( Event.COMPLETE, handleDeferredAttachmentComplete, false, 0, true );
// "Chunk" up lists of IVisualElements based on limit quota.
var i:int;
var startIndex:int;
var endIndex:int;
var length:int = _deferredElements.length;
var count:int = Math.ceil(length / _elementAddQuota);
for( i = 0; i < count; i++ )
{
startIndex = i * _elementAddQuota;
endIndex = startIndex + _elementAddQuota;
endIndex = ( endIndex > length ) ? length : endIndex;
_deferredElementAttacher.addElementPack( _deferredElements.slice( startIndex, endIndex ) );
}
_deferredElementAttacher.start();
}
/**
* Event handler for completion from the IDeferredElementAttacher instance.
* @param evt Event
*/
protected function handleDeferredAttachmentComplete( evt:Event ):void
{
// Kill reference.
_deferredElementAttacher.removeEventListener( Event.COMPLETE, handleDeferredAttachmentComplete, false );
_deferredElementAttacher.dispose();
_deferredElementAttacher = null;
// -> Do whatever you normally would do in a handler for CREATION_COMPLETE.
}
/**
* The amount of IVisualElements to "chunk" into packets for deferred queue.
* @return int
*/
public function get elementAddQuota():int
{
return _elementAddQuota;
}
public function set elementAddQuota( value:int ):void
{
_elementAddQuota = value;
}
/**
* The DefaultProperty array of IVisualElements declared in MXML markup.
* @return Array Required to be IVisualElement[]
*/
public function get deferredElements():Array
{
return _deferredElements;
}
public function set deferredElements( value:Array ):void
{
if( _deferredElements == value ) return;
_deferredElements = value;
_deferredElementsChanged = true;
invalidateProperties();
}
}
}
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import mx.core.IVisualElement;
import mx.core.IVisualElementContainer;
[Event(name="complete", type="flash.events.Event")]
/**
* IDeferredElementAttacher implementation that adds "packs" of IVisualElements based on frame progression.
*/
public class FrameDeferredElementAttacher extends EventDispatcher implements IDeferredElementAttacher
{
/**
* Target container to add IVisualElements to.
*/
protected var target:IVisualElementContainer;
/**
* List of arrays of IVisualElement
*/
protected var packs:Vector.<Array>;
/**
* Instantiates new instance with target container to add elements to.
* @param target IVisualElementContainer
*/
public function FrameDeferredElementAttacher( target:IVisualElementContainer )
{
this.target = target;
packs = new Vector.<Array>();
}
/**
* Assigns frame handler.
*/
protected function addDeferredHandler():void
{
(target as IEventDispatcher).addEventListener( Event.ENTER_FRAME, handleFrame, false, 0, true );
}
/**
* Removes frame handler.
*/
protected function removeDeferredHandler():void
{
(target as IEventDispatcher).removeEventListener( Event.ENTER_FRAME, handleFrame, false );
}
/**
* Frame event handler.
* @param evt Event
*/
protected function handleFrame( evt:Event ):void
{
if( packs.length > 0 )
{
/* IVisualElement */
// Pop packet and add elements to target.
var elements:Array = packs.shift();
while( elements.length > 0 )
{
target.addElement( elements.shift() as IVisualElement );
}
}
else
{
// Emptied. Dispatch complete.
removeDeferredHandler();
dispatchEvent( new Event( Event.COMPLETE ) );
}
}
/**
* @copy IDeferredElementAttacher#addElementPack()
*/
public function addElementPack( value:Array /* IVisualElement */ ):void
{
packs[packs.length] = value;
}
/**
* @copy IDeferredElementAttacher#start()
*/
public function start():void
{
addDeferredHandler();
}
/**
* @copy IDeferredElementAttacher#stop()
*/
public function stop():void
{
removeDeferredHandler();
}
/**
* @copy IDeferredElementAttacher#dispose()
*/
public function dispose():void
{
stop();
target = null;
packs = null;
}
}
}
package
{
import flash.events.IEventDispatcher;
[Event(name="complete", type="flash.events.Event")]
/**
* Queues and dequeue "packs" of IVisualElement instances to be attached to a target container.
*/
public interface IDeferredElementAttacher extends IEventDispatcher
{
/**
* Adds "pack" of IVisualElement to queue.
* @param value Array Array of IVisualElement
*/
function addElementPack( value:Array /* IVisualElement */ ):void;
/**
* Starts dequeue.
*/
function start():void;
/**
* Stops its operation.
*/
function stop():void;
/**
* Kills references and ready for GC.
*/
function dispose():void;
}
}
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.core.IVisualElement;
import mx.core.IVisualElementContainer;
[Event(name="complete", type="flash.events.Event")]
/**
* IDeferredElementAttacher implementation that adds "packs" of IVisualElements based on a defined time delay.
*/
public class TimerDeferredElementAttacher extends EventDispatcher implements IDeferredElementAttacher
{
protected var target:IVisualElementContainer;
/* [] -> IVisualElement[] */
protected var packs:Vector.<Array>;
protected var timer:Timer;
/**
* Instantiates new instance with target container to add elements to.
* @param target IVisualElementContainer
* @param delay int
*/
public function TimerDeferredElementAttacher( target:IVisualElementContainer, delay:int = 100 )
{
this.target = target;
this.packs = new Vector.<Array>();
establishTimer( delay );
}
/**
* @private
*
* Creates and establishes handlers on timer.
* @param delay int
*/
protected function establishTimer( delay:int ):void
{
timer = new Timer( delay, 1 );
timer.addEventListener( TimerEvent.TIMER_COMPLETE, handleTimerComplete, false, 0, true );
}
/**
* @private
*
* Stops and removes handlers on timer.
*/
protected function killTimer():void
{
stop();
timer.removeEventListener( TimerEvent.TIMER_COMPLETE, handleTimerComplete, false );
}
/**
* @private
*
* Event handler for timer complete.
* @param evt Event
*/
protected function handleTimerComplete( evt:Event ):void
{
if( packs.length > 0 )
{
/* IVisualElement */
var elements:Array = packs.shift();
while( elements.length > 0 )
{
target.addElement( elements.shift() as IVisualElement );
}
timer.start();
}
else
{
timer.stop();
timer.reset();
dispatchEvent( new Event( Event.COMPLETE ) );
}
}
/**
* @copy IDeferredElementAttacher#addElementPack()
*/
public function addElementPack( value:Array /* IVisualElement */ ):void
{
packs[packs.length] = value;
}
/**
* @copy IDeferredElementAttacher#start()
*/
public function start():void
{
timer.start();
}
/**
* @copy IDeferredElementAttacher#stop()
*/
public function stop():void
{
timer.stop();
timer.reset();
}
/**
* @copy IDeferredElementAttacher#dispose()
*/
public function dispose():void
{
killTimer();
target = null;
packs = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment