import com.mosesSupposes.fuse.FuseKitCommon; /** * Fuse Kit 2 * Copyright (c) 2006 Moses Gunesch, MosesSupposes.com * * Distributed under MIT Open Source License, see Fuse-Kit-License.html (in fuse package directory) * Easing Equations (c) 2003 Robert Penner used by permission, see PennerEasing * Visit http://www.mosessupposes.com/Fuse * * @ignore * * Pass this class to {@link com.mosesSupposes.fuse.ZigoEngine#register} or {@link com.mosesSupposes.fuse.ZigoEngine#simpleSetup} * to enable Fuse-style Object Syntax parsing capability with {@link com.mosesSupposes.fuse.ZigoEngine#doTween}. * Note that registering Fuse is not required to use this feature. * @usage *
ZigoEngine.doTween({ target:clip1, scale:200, ease:Strong.easeIn, time:"00:50", startAt:"01:50" });*
ZigoEngine.doTween
.
* These otherwise untracked instances are given an ID of -1 and are auto-deleted by the FuseItem class upon completion using removeInstance
.
*/
private static var _aInstances:Array;
/**
* This method needn't be called as method call is rerouted here automatically upon ZigoEngine.doTween
.
* @return comma-delimited string listing properties successfully added to the engine.
*/
public static function doTween():String
{
for (var i:String in arguments) {
if (typeof arguments[i]=='object') {
if (_aInstances==undefined) _aInstances = new Array();
var o:FuseItem = new FuseItem(_aInstances.length, arguments[i], -1);
return o.startItem();
}
}
}
// --------------------------------------------------------------------//
// 1. Fuse-access methods
// 2. Constructor & parseProfile
// 3. doTweens, tween event handlers, utils
// --------------------------------------------------------------------//
// 1.
/**
* @exclude
* label property queried by Fuse
* @return label string if FuseItem contains a label property
*/
public function get label():String
{
return _oElements.label;
}
/**
* @exclude
* Fuse needs to retrieve original objects passed for Array methods that return them
* @return true if trigger has been fired within currently playing item
*/
public function hasTriggerFired():Boolean
{
return (_bTrigger==true);
}
/**
* @exclude
* Fuse needs to retrieve original objects passed for Array methods that return them
* @return original action object as passed by user
*/
public function getInitObj():Object
{
return (_initObj);
}
/**
* @exclude
* Fuse calls this to get additional playing or paused targets to add to defaults when getActiveTargets is called on a Fuse.
* @return a list of target objects or empty array
*/
public function getActiveTargets(targetList:Array):Array
{
if (!(_aTweens.length>0)) return targetList;
var found:Boolean = false;
for (var i:String in _aTweens) {
// filter duplicates
for (var j:String in targetList) {
if (targetList[j]==(_aTweens[i]).targ) {
found = true;
break;
}
}
if (found==false) {
targetList.unshift((_aTweens[i]).targ);
}
}
return targetList;
}
/**
* @exclude
*/
public function toString():String { return String((_sID())+':'+_sImage); }
/**
* @exclude
* Called by parent Fuse to retrieve simple freestanding delays (note that in certain cases
* FuseItems use ZigoEngine tweens to time complex delays, such as those that appear within
* an action group). Such non-tweened delays are centralized into the parent Fuse, which runs
* a setInterval timer and handles pause/resume behavior for that delay.
* @param scope current default scope set in parent Fuse instance
* @return delay in seconds
*/
public function evalDelay(scope:Object):Number
{
var d:Object = _oElements.delay;
if (d instanceof Function) {
d = d.apply((_oElements.delayscope!=undefined) ? _oElements.delayscope : scope);
}
if (typeof d=='string') d = (parseClock(String(d)));
if (_global.isNaN(Number(d))==true) return 0;
return Number(d);
}
/**
* @exclude
* Called by parent Fuse to play the FuseItem, including triggering commands, firing callbacks not associated with tweens, and starting tweens.
* @param targs - an array of default targets currently set in parent Fuse instance
* @param scope - current default scope set in parent Fuse instance
* @return returns successfully tweened props for doTween()
*/
public function startItem(targs:Array, scope:Object, duration:Number, easing:Object):String
{
_ZigoEngine = _global.com.mosesSupposes.fuse.ZigoEngine;
var fuse:Object = _global.com.mosesSupposes.fuse.Fuse;
var outputLevel:Number = (fuse!=undefined) ? fuse.OUTPUT_LEVEL : _ZigoEngine.OUTPUT_LEVEL;
// Fuse command like 'pause' or 'stop'. v2.0: Only delay,scope,args are retained for items containing command.
if (_oElements.command!=null) {
var cs:Object = (_oElements.scope || scope); // profile scope used for eval only. command always sent to parent fuse
var command:String = (_oElements.command instanceof Function) ? String(_oElements.command.apply(cs)) : String(_oElements.command); // user can pass a Delegate to scope this
// IMPORTANT: args param is not used during eval, args are passed to Fuse, primarily for use with skipTo(index/label)
var args:Array = (_oElements.args instanceof Function) ? _oElements.args.apply(cs) : _oElements.args;
var valid:Boolean = FuseKitCommon._validateFuseCommand(command, (_aProfiles.length>0), (args!=null && !(args instanceof Array && args.length==0)), outputLevel, false);
if (valid==true) {
_nPlaying = 1;
if (!(args instanceof Array)) args = (args==null) ? [] : [args];
dispatchRequest(String(command), args);
}
if (valid==false || command=='setStartProps') {
complete();
}
return null; // From docs: "Actions containing a command property may ONLY contain the additional properties: scope, args, label, delay."
}
// Changed order to deal with skipLevel. Now we tween first then fire callbacks and events.
if (_aTweens.length>0) this.stop();
_ZigoEngine.addListener(this); // For monitoring targets that go missing. Only one corresponding remove, in stop(), which is called by complete().
_nPlaying = 2; // Special flag meaning doTweens is running, important for avoiding onTweenInterrupt/End conflicts.
var propsAdded:String = null;
if (_aProfiles.length>0) {
if (_ZigoEngine==undefined) {
FuseKitCommon.error('112');
}
else {
propsAdded = doTweens(targs, scope, duration, easing, false, false);
}
}
// do not move. Callbacks can contain pause or other play commands, so this is checked afterward
_nPlaying = 1;
// Non-tween callbacks & events (skipped if skipLevel is 2 and all tweens failed)
var fa:Array = _oElements.aEvents;
for (var i:String in fa) {
if (propsAdded==null && _aTweens.length>0 && (fa[i]).skipLevel==2) continue;
fireEvents(fa[i],scope,outputLevel,targs);
}
if (propsAdded==null && !(_aTweens.length>0) && _nPlaying==1) {
if (outputLevel==3) FuseKitCommon.output((_sID())+' no tweens added - item done. [getTimer()='+getTimer()+']');
complete();
}
return propsAdded;
}
/**
* @exclude
* Called by parent Fuse to stop the FuseItem's tweens. If currently playing, the internal method onStop is called which clears current tween list and associated listeners.
*/
public function stop():Void
{
// (for onTweenInterrupt)
var doOnStop:Boolean = (_nPlaying>-1);
_nPlaying = -1;
// active stop: clear this item's tweens and remove listeners
if (doOnStop==true) onStop();
_ZigoEngine.removeListener(this);
}
// -- private --
/**
* @exclude
*/
private static function removeInstance(id:Number):Void
{
FuseItem(_aInstances[id]).destroy();
delete _aInstances[id];
}
/**
* @exclude
* Clears active elements. (Fuse event reverse-subscribed by parent Fuse)
*/
private function onStop():Void
{
_bStartSet = false;
for (var i:String in _aTweens) {
var to:Object = _aTweens[i];
to.targ.removeListener(this);
_ZigoEngine.removeTween(to.targ, to.props);
delete _aTweens[i];
}
delete _aTweens;
_bTrigger = false;
}
/**
* @exclude
* An event dispatched by parent Fuse to all child FuseItems to preset tween start-values.
* @param o event object containing a .filter property which can specify exclusion from the call
*/
private function evtSetStart(o:Object):Void
{
// no starts to set or Fuse is about to play this item.
if (_sImage.indexOf('StartProps:')==-1 || o.curIndex==_nItemID) {
return;
}
if (o.all!=true) {
var match:Boolean = false;
for (var i:String in o.filter) {
if (Number(o.filter[i])==_nItemID || String(o.filter[i])==_oElements.label) match = true;
}
if (match==false) {
return;
}
}
_nPlaying = 2; // Special flag meaning doTweens is running, important for avoiding onTweenInterrupt/End conflicts.
doTweens(o.targs, o.scope, null, null, true, false);
_nPlaying = -1;
// flag removed when parent Fuse stopped.
_bStartSet = true;
}
/**
* @exclude
* Called by parent Fuse to pause or resume the FuseItem's tweens and tweened delays. During resume it is not assumed
* that targets and pauses are intact, each is checked and the internal tween array is trimmed if items have gone missing.
* @param resume indicates whether it is a pause or resume call
*/
public function pause(resume:Boolean):Void
{
if (_nPlaying==-1) return;
_nPlaying = ((resume==true) ? 1 : 0);
for (var i:String in _aTweens) {
var o:Object = _aTweens[i];
var t:Object = o.targ;
var p:Object = o.props;
if (resume==true) {
// Is pause intact? Target/prop could have been manipulated since it was paused here.
var missing:Array = [];
var oldTL:Number = _aTweens.length;
for (var j:String in p) {
if (_ZigoEngine.isTweenPaused(t,p[j])==false) missing.push(p[j]);
}
if (missing.length>0) {
onTweenEnd({__zigoID__:o.targZID, props:missing, isResume:true});
}
if (_aTweens.length==oldTL) { // otherwise onTweenEnd removed the tween
t.addListener(this);
_ZigoEngine.unpauseTween(t, o.props);
}
}
else {
t.removeListener(this);
_ZigoEngine.pauseTween(t, o.props);
}
}
if (resume==true && !(_aTweens.length>0)) { // no tweens.
complete();
}
else if (resume==true) {
_ZigoEngine.addListener(this);
}
else {
_ZigoEngine.removeListener(this);
}
}
/**
* @exclude
* Called by parent Fuse during fastForward to advance all animations.
* Do not fire callbacks/events.
* Parent fuse handles advance.
* @param ignore integrate polymorphically with Fuse.fastForward which needs null for first param
* @param targs parent fuse default
* @param scope parent fuse default (only applies to runtime eval. to retrieve tween params, callbacks not fired)
*/
public function fastForward(ignore:Object, targs:Array, scope:Object):Void
{
if (_nPlaying==1) {
for (var i:String in _aTweens) {
var o:Object = _aTweens[i];
var t:Object = o.targ;
t.removeListener(this);
_ZigoEngine.ffTween(t, o.props, true);
}
return;
}
if (_nPlaying==2) {
FuseKitCommon.error('125',_nItemID);
}
_nPlaying = 2;
doTweens(targs, scope, null, null, false, true);
stop();
}
/**
* @exclude
* Called by parent Fuse to clear FuseItem instance's memory and listeners during Fuse's destroy cycle.
*/
public function destroy():Void
{
var doRemove:Boolean = (_nPlaying>-1);
_nPlaying = -1;
for (var i:String in _aTweens) {
var o:Object = _aTweens[i];
o.targ.removeListener(this);
if (doRemove==true) _ZigoEngine.removeTween(o.targ, o.props);
delete _aTweens[i];
}
for (var j:String in this) {
delete this[j];
}
}
/**
* @exclude
* @param type fuse method
* @param args method params
*/
private function dispatchRequest(type:String, args:Array):Void
{// avoids import of Fuse class since FuseItem can be used with ZigoEngine as an Object Syntax extension
var f:Object = _global.com.mosesSupposes.fuse.Fuse.getInstance(_nFuseID);
if (!(args instanceof Array) && args!=null) args = (new Array(args));
Function(f[type]).apply(f, args);
}
// 2.
/**
* @exclude
* Concise string ID representing the parent Fuse's fixed ID and the FuseItem's current index in the Fuse, such as "Fuse#0>Item#0"
*/
private function _sID():String // like "Fuse#0>Item#0"
{
var str:String;
if (_nFuseID==-1) {
str = '-One-off tween ';
}
else {
str = (_global.com.mosesSupposes.fuse.Fuse.getInstance(_nFuseID)).getHandle();
}
str+='>Item #'+String(_nItemID);
if (_oElements.label!=undefined) str+=' "'+_oElements.label+'"';
return str;
}
/**
* @exclude
* Constructor - Attempts to parse action(s) into _oElements
and _aProfiles
, building the verbose string ID _sImage
in the process.
* @param id current index of FuseItem in parent Fuse instance
* @param o action object or Array of action objects pushed into the Fuse for parsing
* @param fuseID permanent unique ID of parent Fuse stored in _nFuseID
*/
public function FuseItem (id:Number, o:Object, fuseID:Number)
{
_ZigoEngine = _global.com.mosesSupposes.fuse.ZigoEngine;
this._nItemID = id;
this._nFuseID = fuseID;
this._initObj = o;
_aProfiles = [];
_oElements = { aEvents:[] };
_oTemps = {};
if (!(o instanceof Array)) o = [o];
var fuse:Object = _global.com.mosesSupposes.fuse.Fuse;
_oTemps.outputLevel = (fuse!=undefined) ? fuse.OUTPUT_LEVEL : _global.com.mosesSupposes.fuse.ZigoEngine.OUTPUT_LEVEL;
// v2 Command actions can only contain delay, label, scope, args and may not be nested in groups.
if (o.length==1) {
var o0:Object = o[0];
var obj:Object = (o0.action!=undefined) ? o0.action : o0;
if (obj.__buildMode!=true && obj.command!=undefined) {
_oElements.command = obj.command;
_oElements.scope = obj.scope; // v2.0: changed commandscope & commandargs to scope, args.
_oElements.args = obj.args;
_sImage = ' Elements:['+('command'+((typeof obj.command=='string') ? ':"'+obj.command+'", ' : ', '));
// if (obj.label!=undefined && typeof obj.label=='string') {
// _sImage+=('label, ');
// _oElements.label = obj.label; // one label per Command Action
// }
if (obj.delay!=undefined) {
_sImage+='delay, ';
_oElements.delay = obj.delay; // one delay per Command Action
}
_sImage=_sImage.slice(0,-2)+']';
if (obj.func!=undefined && _oTemps.outputLevel>0) FuseKitCommon.error('113');
return;
}
}
// persistant vars for looping through actions
_oTemps.sImgS = '';
_oTemps.sImgE = '';
_oTemps.sImgB = '';
_oTemps.afl = 0;
_oTemps.ael = 0;
_oTemps.twDelayFlag = false;
_oTemps.nActions = o.length;
_oTemps.fuseProps = FuseKitCommon._fuseprops();
_oTemps.cbProps = FuseKitCommon._cbprops();
_oTemps.sUP = FuseKitCommon._underscoreable();
_oTemps.sCT = FuseKitCommon._cts();
_oTemps.bTriggerFound = false;
// Parse each profile.
for (var i:String in o) {
var item:Object = o[i];
if (item.label!=undefined && typeof item.label=='string') _oElements.label = item.label; // one string-only label per FuseItem
var aap:Object;
var bApplied:Boolean = Boolean(typeof item.action=='object');
if (bApplied==true) {
var a:Array = (item.action instanceof Array) ? item.action : [ item.action ]; // support action array
aap = { // applied-action profile, these props are mixed into the action during parseProfile.
delay:item.delay,
target:item.target,
addTarget:item.addTarget,
label:item.label,
trigger:item.trigger
};
for (var j:String in a) {
var oPr:Object = parseProfile(a[j], aap);
if (oPr!=undefined) {
_aProfiles.unshift(oPr);
}
}
}
else {
var a:Object = item;
var oPr:Object = parseProfile(a, aap);
if (oPr!=undefined) {
_aProfiles.unshift(oPr);
}
}
}
// build string image (if a command was passed in, this happens up top.)
_sImage = '';
var str:String = '';
// if (_oElements.label!=undefined) str+=('label, ');
if (_oTemps.afl>0) str+= ((_oTemps.afl>1) ? _oTemps.afl+' callbacks, ' : 'callback, ');
if (_oElements.delay!=undefined || _oTemps.twDelayFlag==true) str+='delay, ';
if (_oTemps.bTriggerFound==true) str+='trigger, ';
if (_oTemps.ael>0) str+= ((_oTemps.ael>1) ? _oTemps.ael+' events, ' : 'event, ');
if (str!='') _sImage+=' Elements:['+(str.slice(0,-2))+']';
if (_oTemps.sImgS!='') _sImage+= ' StartProps:['+(_oTemps.sImgS.slice(0,-2))+']'; // careful: "StartProps:" is checked in evtSetStart
if (_oTemps.sImgE!='') _sImage+= ' Props:['+(_oTemps.sImgE.slice(0,-2))+']';
if (_oTemps.sImgB!='') _sImage+= ' Simple Syntax Props:['+(_oTemps.sImgB.slice(0,-1))+']';
if (_sImage.slice(-2)==', ') _sImage = _sImage.slice(0,-2);
delete _oTemps;
}
/**
* @exclude
* Used by constructor to parse each action object passed (multiple objects can be passed in an Array for simultaneous action groups).
* The parsing process is a fairly complex procudure that blocks tween start & end properties, tags 'auto-fill' end properties in which
* only a start value was passed, extracts freestanding items that do not require tweens, and generates proxy tweens used to handle delays within groups.
* @param obj the action object to be parsed into a profile and pushed into _aProfiles
* @param aap Stands for 'applied action profile' object. When an 'applied action' is encountered, this override profile mixes properties into the resulting profile.
* @return parsed profile object
*/
private function parseProfile(obj:Object, aap:Object):Object
{
var i:String, j:String, k:String;
// Build Mode (simple syntax) objects
if (obj.__buildMode==true) {
if (obj.command!=undefined) {
if (obj.command=='delay') { // addCommand('delay',Number)
_oElements.delay = obj.commandargs;
}
else if (obj.command=='trigger') {
if (_oTemps.bTriggerFound==false) { // only one trigger is allowed per FuseItem
_oTemps.bTriggerFound = true;
return { trigger:obj.commandargs, _doTimer:true };
}
else if (_oTemps.outputLevel>0) {
FuseKitCommon.error('124', (_sID()), obj.commandargs);
}
}
else {
_oElements.command = obj.command;
_oElements.args = obj.commandargs;
}
}
if (obj.func!=undefined) {
_oTemps.afl++;
_oElements.aEvents.unshift({ scope:obj.scope, func:obj.func, args:obj.args });
}
if (obj.tweenargs!=undefined) {
_oTemps.sImgB += (obj.tweenargs[1].toString()+','); // (allowing duplicates in simple syntax props image to save code, since it could be comma-delim str)
return obj;
}
return null;
}
var oPr:Object = {
delay:(aap.delay!=undefined) ? aap.delay : obj.delay,
ease:obj.ease,
seconds:obj.seconds,
event:obj.event,
eventparams:obj.eventparams,
skipLevel:(typeof obj.skipLevel=='number' && obj.skipLevel>=0 && obj.skipLevel<=2) ? obj.skipLevel : _ZigoEngine.SKIP_LEVEL, // correct early for use in FuseItem.doTweens
roundResults:obj.roundResults,
oSP:{},
oEP:{},
oAFV:{}
};
// trigger
var trigger:Object = ((aap.trigger!=undefined) ? aap.trigger : obj.trigger); // can be true or number, not parsed until doTweens
if (trigger!=undefined) {
if (_oTemps.bTriggerFound==false) { // only one trigger is allowed per FuseItem
oPr.trigger = trigger;
_oTemps.bTriggerFound = true;
}
else if (_oTemps.outputLevel>0) {
FuseKitCommon.error('124',(_sID()),trigger);
}
}
// synonyms
if (oPr.delay==undefined) oPr.delay = obj.startAt;
if (oPr.ease==undefined) oPr.ease = obj.easing; // synonym
if (oPr.seconds==undefined) oPr.seconds = ((obj.duration!=undefined) ? obj.duration : obj.time); // synonym
// applied action target param overrides action target param
if (aap.target!=undefined) oPr.target = ((aap.target instanceof Array) ? aap.target : [aap.target]);
else if (obj.target!=undefined) oPr.target = ((obj.target instanceof Array) ? obj.target : [obj.target]);
// applied action addTarget param adds to action addTarget param (don't change order)
if (obj.addTarget!=undefined) oPr.addTarget = ((obj.addTarget instanceof Array) ? obj.addTarget : [obj.addTarget]);
if (aap.addTarget!=undefined) {
if (oPr.addTarget==undefined) oPr.addTarget = ((aap.addTarget instanceof Array) ? aap.addTarget : [aap.addTarget]);
else oPr.addTarget = ((oPr.addTarget instanceof Array) ? (oPr.addTarget.concat(aap.addTarget)) : ((new Array(oPr.addTarget)).concat(aap.addTarget)));
}
var bTwFlag:Boolean = false;
for (j in obj) {
var v:Object = obj[j];
if ((_oTemps.cbProps).indexOf('|'+j+'|')>-1) { // a callback-object prop
if (j!='skipLevel') oPr[j] = v;
continue;
}
if ((_oTemps.fuseProps).indexOf('|'+j+'|')>-1) {// skip adding fuse props which are handled above. animation properties remain.
if (j=='command' && _oTemps.nActions>1 && _oTemps.outputLevel>0) {
FuseKitCommon.error('109',String(v), true); // command within group error
}
continue;
}
if (typeof v=='object') {
var copy:Object = (v instanceof Array) ? ([]) : {};
for (k in v) copy[k] = v[k];
v = copy;
}
var se:Object;
var seCP:Object;
if (j.indexOf('start_')==0) { // added undescore here v2.1.1r1, if no issues come up remove this comment later.
if (j=='start_controlX' || j=='start_controlY' || j.indexOf('_bezier_')>-1) {
// Illegal! _bezier_ and controlX/Y are protected properties and cannot have start values set.
if (_oTemps.outputLevel > 0) {
FuseKitCommon.error('110',(_sID()), j); // 110 changed, this was added later.
}
continue;
}
j = j.slice(6);
se = oPr.oSP;
}
else {
se = oPr.oEP;
}
if (ADD_UNDERSCORES==true && _oTemps.sUP.indexOf('|_'+j+'|')>-1) j='_'+j;
if (_oTemps.sCT.indexOf('|'+j+'|')>-1) {
var addPct:Boolean = (j=='_tintPercent' && se.colorProp.p=='_tint');
var addTint:Boolean = (j=='_tint' && se.colorProp.p=='_tintPercent');
if (se.colorProp==undefined || addPct==true || addTint==true) { // write only 1 color prop per profile, saves cleanup work during tween.
if (addPct==true) se.colorProp = {p:'_tint', v:{ tint:se.colorProp.v, percent:v }};
else if (addTint==true) se.colorProp = {p:'_tint', v:{ tint:v, percent:se.colorProp.v }};
else se.colorProp = {p:j, v:v};
bTwFlag = true;
}
else if (_oTemps.outputLevel>0) {
FuseKitCommon.error('115',(_sID()),j);
}
}
else if (v!=null) { // (null values are only accepted for color props)
se[j] = v;
bTwFlag = true;
}
} // end parse props(j), still looping through actions(i)
/* Special "Nontween delay" cases
* (Note that normally delays are played by parent fuse except in these cases)
* -start/update callbacks without any tween props
* -delay within multi-item group
*/
if (bTwFlag==false && (oPr.trigger!=undefined ||
((oPr.delay!=undefined || oPr.seconds!=undefined) &&
( (oPr.startfunc!=undefined || oPr.updfunc!=undefined)
|| (oPr.func!=undefined && _oTemps.nActions>1) )))) {
if (_ZigoEngine==undefined) { // ignore output level for crucial error message
FuseKitCommon.error('116');
}
else {
if (oPr.func!=undefined) _oTemps.afl++;
if (oPr.event!=undefined) _oTemps.ael++;
oPr._doTimer = true;
if (oPr.delay!=undefined) _oTemps.twDelayFlag = true;
return oPr;
}
}
if (bTwFlag==true) { // do a final round of cleanup on tween profile and build string image
var bEC:Boolean = (oPr.oEP.colorProp!=undefined);
for (var l:Number=0; l<2; l++) {
var se:Object = (l==0) ? oPr.oSP : oPr.oEP;
var str:String = (l==0) ? _oTemps.sImgS : _oTemps.sImgE;
var sCP:String = se.colorProp.p;
if (sCP!=undefined) { // combine color back in (colorProp was used to enforce single start/end color)
se[sCP] = se.colorProp.v;
delete se.colorProp;
}
if ((se._xscale!=undefined || se._scale!=undefined) && (se._width!=undefined || se._size!=undefined)) {
var discard:String = (se._xscale!=undefined) ? '_xscale' : '_scale';
delete se[discard];
if (_oTemps.outputLevel>0) FuseKitCommon.error('115',(_sID()),discard);
}
if ((se._yscale!=undefined || se._scale!=undefined) && (se._height!=undefined || se._size!=undefined)) {
var discard:String = (se._yscale!=undefined) ? '_yscale' : '_scale';
delete se[discard];
if (_oTemps.outputLevel>0) FuseKitCommon.error('115',(_sID()),discard);
}
if (se._fade!=undefined && se._alpha!=undefined) {
delete se._alpha;
if (_oTemps.outputLevel>0) FuseKitCommon.error('115',(_sID()),'_alpha');
}
for (j in se) {
if (str.indexOf(j+', ')==-1) str+=(j+', ');
if (se==oPr.oSP) {
if (oPr.oEP[j]==undefined && !(j==sCP && bEC==true)) { // add 'autofill' lookup
oPr.oAFV[j] = true;
oPr.oEP[j] = [];
}
}
}
((l==0) ? _oTemps.sImgS = str : _oTemps.sImgE = str);
}
return oPr;
}
// If no tweens were added or start/end profiles ended up empty, move usable props to _oElements
if (oPr.delay!=undefined && _oTemps.nActions==1) { // single-item actions only, see first if() in this block for multi-item actions
_oElements.delay = oPr.delay;
_oElements.delayscope = oPr.scope; // (internal, not a valid user prop!)
}
if (oPr.event!=undefined) {
_oTemps.ael++;
_oElements.aEvents.unshift({scope:oPr.scope, e:oPr.event, ep:oPr.eventparams, skipLevel:oPr.skipLevel});
}
// actions containing startfunc/updfunc are handled w/nonTweenDelay.
var oldL:Number = _oElements.aEvents.length;
if (oPr.func!=undefined) _oElements.aEvents.push({func:oPr.func, scope:oPr.scope, args:oPr.args, skipLevel:oPr.skipLevel});
_oTemps.afl+=(_oElements.aEvents.length-oldL);
delete oPr;
return undefined;
}
// 3.
/**
* @exclude
* Internal method to preset start values and generate tween calls to be sent to the engine. This is a complex procedure mainly due to the
* 'runtime-evaluation' feature of the Kit - scope, target(s), and all start and end values delegated to a function are retrieved by executing
* such functions just as the item is encountered in the sequence. doTweens handles all of this, builds and sends the tween calls while storing
* a reference in the internal _aTweens array. It then does emergency cleanup in situations where no tweens successfully fired and boolean end-values,
* callbacks, or delays are orphaned. Presetting start values is handled with 0-second tween calls which is important for interrupting any current tweens,
* which are monitored by any running Fuses; Start values with missing end-values are 'auto-filled' during doTweens.
* @param targs parent Fuse instance's current default targets
* @param defaultScope parent Fuse instance's current default scope
* @param setStart flag indicating that the doTweens call should only preset start values.
* @return returns successfully tweened props for doTween()
*/
private function doTweens(targs:Array, defaultScope:Object, defaultSeconds:Number, defaultEase:Object, setStart:Boolean, isFF:Boolean):String
{
if (_aTweens==null) {
this._aTweens = [];
}
var tba:Object = _oTwBeingAdded = {};
var ZE:Function = _ZigoEngine;
var addTween:Function = function(target:Object, props:Object, endvals:Object, seconds:Number, ease:Object, delay:Number, callback:Object):Array {
if (target.__zigoID__==null) ZE.initializeTargets(target);
tba[target.__zigoID__] = true; // flag this target in _oTwBeingAdded only during the ZManager.addTween call, used by other FuseItems in the same Fuse (see onTweenEnd)
var sProps:String = ZE.doTween.apply(ZE, arguments);
tba[target.__zigoID__] = false;
return ((sProps==null) ? [] : (sProps.split(',')));
};
var fuse:Object = _global.com.mosesSupposes.fuse.Fuse;
var outputLevel:Number = (fuse!=undefined) ? fuse.OUTPUT_LEVEL : _ZigoEngine.OUTPUT_LEVEL;
var propsAdded:String = '';
var nTgErrors:Number = 0;
var i:String, j:String, k:String;
var doSetStarts:Boolean = (_bStartSet!=true && (setStart==true || _sImage.indexOf('StartProps:')>-1));
// cycling through each action profile
for (var h:Number=0; h<_aProfiles.length; h++)
{
if (_nPlaying<2) return null; // abort if item has been stopped during doTweens
var pr:Object = _aProfiles[h];
/*
* Build-Mode profile item (startprops option doesn't exist here)
* Do condensed tween loop. Currently lacking target error tracking.
* - used to have this as a separate profile loop but there are ways to mix buildmode and
* object syntax tweens in the same group.
*/
if (pr.__buildMode==true) {
var twArgs:Array = (_aProfiles[h]).tweenargs;
var prevPropsAdded:String = propsAdded;
if ((twArgs[6]).cycles===0 || ((twArgs[6]).cycles.toUpperCase())=='LOOP') {
delete (twArgs[6]).cycles;
if (outputLevel>0) FuseKitCommon.error('117',(_sID()));
}
var cb:Object = FuseKitCommon.parseCallback(twArgs[6]); // validated callback preserves cb-id across doTween calls
if (!(twArgs[0] instanceof Array)) twArgs[0] = [ twArgs[0] ];
for (i in twArgs[0]) {
if (isFF==true) {
addTween(twArgs[0][i], twArgs[1], twArgs[2], 0, null, 0, {skipLevel:0});
if (outputLevel==3) {
FuseKitCommon.output('\n-'+(_sID())+' FF(simple syntax)\ttargets:['+twArgs[0][i]+']\tprops:['+twArgs[1]+']');
}
}
else {
var aProps:Array = addTween(twArgs[0][i], twArgs[1], twArgs[2], twArgs[3], twArgs[4], twArgs[5], cb);
if (aProps.length>0) {
_aTweens.push({targ:twArgs[0][i], props:aProps, targZID:(twArgs[0][i]).__zigoID__});
(twArgs[0][i]).addListener(this);
for (j in aProps) if (propsAdded.indexOf(aProps[j]+',')==-1) propsAdded+=(aProps[j]+',');
}
if (outputLevel==3) {
FuseKitCommon.output('\n-'+(_sID())+' TWEEN(simple syntax)\ttargets:['+twArgs[0][i]+']\tprops tweened:['+aProps.toString()+']');
}
}
}
if (isFF==false && (prevPropsAdded==propsAdded || propsAdded=='')) nTgErrors++;
continue;
}
var scope:Object = defaultScope; // this local is used many times within this loop for runtime-eval
// targets + addTargets
var targets:Array = [];
var aBase:Array = (pr.target==undefined) ? targs : pr.target;
var aTemp:Array = [];
var bTgError:Boolean = false;
// (any runtime func (or delegate) may return one targ or an array of targs)
for (i in aBase) {
var v:Object = aBase[i];
aTemp = aTemp.concat((v instanceof Function) ? v.apply(scope) : v);
}
for (i in pr.addTarget) {
var v:Object = pr.addTarget[i];
aTemp = aTemp.concat((v instanceof Function) ? v.apply(scope) : v);
}
for (i in aTemp) {
var v:Object = aTemp[i];
if (v!=null) {
var exists:Boolean = false;
for (j in targets) {
if (targets[j]==v) {
exists = true;
break;
}
}
if (exists==false) targets.unshift(v);
}
else {
bTgError = true;
}
}
var doTimer:Boolean = (pr._doTimer==true && targets.length==0 && isFF==false);
if (bTgError==true || (targets.length==0 && pr._doTimer!=true)) {
nTgErrors++;
}
// -- 1. start props --
if (doSetStarts==true)
{
// generate one ZigoEngine.doTween() call per target. Props parsed for runtime-eval, bools, validation
for (i in targets) {
if (_nPlaying<2) return null; // abort if item has been stopped during doTweens
var targ:Object = targets[i];
var aSP:Array = [];
var aSV:Array = [];
if (setStart==true) {
for (var q:String in pr.oEP) {
// Use 3rd param createNew to pre-create any missing filters on setStartProps, so the filter doesn't suddenly appear just before that action starts.
_global.com.mosesSupposes.fuse.FuseFMP.getFilterProp(targ,q,true);
}
}
for (var p:String in pr.oSP) {
var v:Object = pr.oSP[p];
if (v instanceof Function) v = v.apply(scope);
if (v===true || v===false) { // set start booleans immediately.
targ[p] = v;
if (pr.oAFV[p]==true) { // prohibit autofill with booleans.
for (k in pr.oEP[p]) if (pr.oEP[p][k].targ==targ) pr.oEP[p].splice(Number(k),1);
pr.oEP[p].push({targ:targ,val:'IGNORE',_isAF:true});
}
continue;
}
// autofill missing end values. Assume resets for known properties, otherwise take a snapshot of the current value to return to.
if (pr.oAFV[p]==true && !(p=='_colorReset' && v==100) && !(p=='_tintPercent' && v==0)) {// if no endprop was passed for startprop, store current value (does not apply to color prop which resets, preset during constructor parse)
var afv:Object;
if (p=='_tint' || p=='_colorTransform') {
afv = _ZigoEngine.getColorTransObj();
}
else if (String(FuseKitCommon._resetTo100()).indexOf('|'+p+'|')>-1 || (p=='_fade' && v<50)) {
afv = 100;
}
else if (String(FuseKitCommon._resetTo0()).indexOf('|'+p+'|')>-1 || p=='_fade') { // (that is, _fade && v>=50, covered by the conditional)
afv = 0;
}
else { // snapshot current val, retaining target (which is important in the case of relative endvals)
var fmpVal:Number = _global.com.mosesSupposes.fuse.FuseFMP.getFilterProp(targ,p,true);
if (fmpVal!=null) afv = fmpVal;
else afv = (_global.isNaN(targ[p])==false) ? targ[p] : 0;
}
for (k in pr.oEP[p]) if (pr.oEP[p][k].targ==targ) pr.oEP[p].splice(Number(k),1);
pr.oEP[p].push({targ:targ,val:afv,_isAF:true});
}
if (typeof v=='object') {
var copy:Object = (v instanceof Array) ? ([]) : {};
for (k in v) copy[k] = ((v[k]) instanceof Function) ? Function(v[k]).apply(scope) : v[k];
v = copy;
}
aSP.push(p);
aSV.push(v);
}// end startprops loop(n)
// set starts using egine, which monitors/broadcasts interrupts + parses complex properties.
if (aSV.length>0) {
if (outputLevel==3) FuseKitCommon.output((_sID())+' '+targ+' SET STARTS: '+['['+aSP+']', '['+aSV+']']);
addTween(targ, aSP, aSV, 0);
}
} // end set starts
}// end if startprops
if (setStart==true) {
continue;
}
// prep for end props loops
var event:Object, skipLevel:Number, oSimpleCB:Object, oCB:Object, triggerTrue:Boolean, triggerTime:Number;
var cbstr:String='';
if (isFF==false) {
// Each action may define a "scope" param which overrides Fuse default scope
// (scope cascades to updscope & startscope if omitted.)
if (pr.scope!=undefined) {
// NOTE: Removed runtime-eval support for scope, because it messes up static function calls
// such as scope:FuseFMP, func:'removeFilter' -- since the class reference is actually a function.
scope = pr.scope; //(pr.scope instanceof Function) ? pr.scope.apply(scope) : pr.scope;
}
// build callback object
skipLevel = ((pr.skipLevel instanceof Function) ? pr.skipLevel.apply(scope) : pr.skipLevel);
var extra1:Number = ((pr.extra1 instanceof Function) ? pr.extra1.apply(scope) : pr.extra1);
var extra2:Number = ((pr.extra2 instanceof Function) ? pr.extra2.apply(scope) : pr.extra2);
var roundResults:Number = ((pr.roundResults instanceof Function) ? pr.roundResults.apply(scope) : pr.roundResults);
oSimpleCB = { skipLevel:skipLevel, extra1:extra1, extra2:extra2, roundResults:roundResults };
oCB = { skipLevel:skipLevel, extra1:extra1, extra2:extra2, roundResults:roundResults };
if (pr.cycles!=undefined) {
var cycles:Object = ((pr.cycles instanceof Function) ? pr.cycles.apply(scope) : pr.cycles);
if ((Number(cycles)==0 || (String(cycles).toUpperCase())=='LOOP') && fuse!=undefined) {
delete pr.cycles;
if (outputLevel>0) FuseKitCommon.error('117',(_sID())); // infinite cycles not allowed in fuses
}
else {
oSimpleCB.cycles = oCB.cycles = cycles;
}
}
if (pr.func!=undefined || pr.startfunc!=undefined || pr.updfunc!=undefined) {
for (i in pr) {
if (i.indexOf('func')>-1) {
oCB[i] = pr[i];
}
else if (i=='startscope' || i=='updscope' || i.indexOf('args')>-1) {
// see note above under pr.scope (runtime eval support removed for scopes)
oCB[i] = pr[i]; //(pr[i] instanceof Function) ? Function(pr[i]).apply(scope) : pr[i];
}
}
if (scope!=undefined) {
if (oCB.func!=undefined && oCB.scope==undefined) oCB.scope = scope; // auto-fill callback scopes where possible
if (oCB.updfunc!=undefined && oCB.updscope==undefined) oCB.updscope = scope;
if (oCB.startfunc!=undefined && oCB.startscope==undefined) oCB.startscope = scope;
}
}
for (j in oCB) cbstr+=(j+':'+oCB[j]+'|');
// build event object (leave after callback)
if (pr.event!=undefined) {
event = {scope:pr.scope, e:pr.event, ep:pr.eventparams, skipLevel:skipLevel};
}
// trigger: may be boolean, number, or runtime-eval function
triggerTrue = (pr.trigger===true);
triggerTime = undefined;
if (triggerTrue==false && pr.trigger!=undefined) {
triggerTime = ((pr.trigger instanceof Function) ? pr.trigger.apply(scope) : pr.trigger);
if (typeof triggerTime=='string') {
triggerTime = ((String(triggerTime).charAt(0)=='-') ? -(parseClock(String(triggerTime).slice(1))) : (parseClock(String(triggerTime))));
}
if (_global.isNaN(triggerTime)==true) triggerTime = undefined;
}
}// end isFF==false
// -- 2. end props --
// Generate one ZigoEngine.doTween() call per target since envals can differ due to auto-fill feature.
// the last round of evaluating seconds, delay, and booleans is saved for the pickup round that happens after this loop
var delay:Number, seconds:Number, ease:Object;
var booleans:Object;// Group end-booleans per target to be set in onTweenEnd
var tweenSuccess:Boolean = false;
var targsOrProxy:Array = ((doTimer==false) ? targets : [0]);// force loop to occur once for targetless timer tweens
var nBezError:Number = -1; // limit error to once per profile, all similar errors are thrown in parseProfile.
for (i in targsOrProxy) {
if (_nPlaying<2) return null; // abort if item has been stopped during doTweens
if (isFF==false) {
// Eval other per-profile params (putting this in the loop is less efficient but it allows runtime-eval-funcs to be run per target.)
// Q: when a user builds an action and there are multiple targets, do they want getters to be fired per target, or per action?
if (pr.ease!=null) {
ease = pr.ease;
if (ease instanceof Function) { // could be a runtime eval function!
var ef:Function = (Function(ease));
if (typeof ef(1,1,1,1)!='number') ease = ef.apply(scope); // it's not a valid easing equation the engine can use.
}
}
if (ease==null) ease = defaultEase;
seconds = (pr.seconds instanceof Function) ? pr.seconds.apply(scope) : pr.seconds;
if (seconds!=undefined) {
if (typeof seconds=='string') seconds = (parseClock(String(seconds)));
if (_global.isNaN(seconds)==true) seconds = (_ZigoEngine.DURATION || 0);
}
if (seconds==null) seconds = defaultSeconds;
delay = (pr.delay instanceof Function) ? pr.delay.apply(scope) : pr.delay;
if (typeof delay=='string') delay = (parseClock(String(delay)));
if (delay==null || _global.isNaN(delay)==true) delay = 0;
if (doTimer==true) continue;
}
// ---------------------------------------------------------------
//parse
var targ:Object = targsOrProxy[i];
var aEP:Array = [];
var aEV:Array = [];
var numBools:Number = 0;
var bezIndex:Number = -2; // -2=none,-1=loose props,uint=existing _bezier_ param
for (var p:String in pr.oEP) {
var v:Object = pr.oEP[p];
if (v instanceof Function) {
v = v.apply(scope);
}
if (v===true || v===false) { // end booleans will be attached to a tween & set in onTweenEnd.
if (booleans==undefined) booleans = {};
booleans[p] = v;
numBools++;
continue;
}
if (typeof v=='object') {
if ((v[0])._isAF==true) { // this is an autofilled property - match targets.
for (k in v) {
if ((v[k]).targ==targ) {
v = (v[k]).val;
break;
}
}
}
else {
var copy:Object = (v instanceof Array) ? ([]) : {};
for (k in v) copy[k] = ((v[k]) instanceof Function) ? Function(v[k]).apply(scope) : v[k];
v = copy;
}
}
if (v!='IGNORE') {
if (p=='_bezier_') bezIndex = aEP.length;
else if (bezIndex==-2 && (p=='controlX' || p=='controlY')) bezIndex = -1;
aEP.push(p);
aEV.push(v);
}
} // end endprops loop(n)
if (aEV.length>0) {
if (bezIndex>-2) {
// Build bezier after all parsing is complete. This ordering enables start_x & start_y + autofill functionality. (Moved here from parseProfile in v2.1.2)
if (bezIndex==-1) bezIndex = aEP.length;
aEP[bezIndex] = '_bezier_';
if (typeof aEV[bezIndex]!='object') aEV[bezIndex] = {}; // might have been defined by user
var bezObj:Object = aEV[bezIndex]; // set a reference since the index gets messed up during splice.
for (j in aEP) { // splice x,y out of end props and profile object into bezier object.
if (('|x|y|_x|_y|controlX|controlY|').indexOf('|'+aEP[j]+'|')>-1) {
if (aEP[j].charAt(0)=='_') aEP[j] = aEP[j].slice(-1);
if (typeof bezObj[aEP[j]] == 'number') { // collision: similar property was already included in a _bezier_ parameter in the same action. Discard the loose properry
if (outputLevel>0 && (nBezError==-1 || nBezError==i)) {
FuseKitCommon.error('115', (_sID()), aEP[j]);
nBezError = Number(i);
}
}
else {
bezObj[aEP[j]] = aEV[j];
}
aEP.splice(Number(j), 1);
aEV.splice(Number(j), 1);
}
}
}
if (isFF==true) {
if (outputLevel==3) FuseKitCommon.output('\n-'+(_sID())+' FF\ttargets:['+targ+']\tprops:['+aEP.toString()+']');
addTween(targ, aEP, aEV, 0, null, 0, { skipLevel:0 });
continue;
}
// normal tweens. monitor only the props that are added to the engine's tweenlist.
// Only add callbacks/booleans/events in the case of single target - otherwise these things will be picked up with a fake tween later.
// listener: fixes an obscure issue where doTween returns null but has fired callbacks/events, which can happen during 0-second, skipLevel:0 tweens, also when ZigoEngine.TIME_MULTIPLIER=0.
// Provides a third option where callbacks are stripped. (note: tests seem to prove that asbroadcaster is fast enough to make this work although in theory the event might be dispatched too late to show up.)
var listener:Object = { caught:false, onTweenEnd:function(evto:Object) { (this).caught = true; } };
targ.addListener(listener);
// ~ THE TWEEN CALL ~
var aProps:Array = addTween(targ, aEP, aEV, seconds, ease, delay, oCB);
// ~ ~ ~ ~ ~ ~ ~ ~ ~
targ.removeListener(listener);
if (aProps.length==0) {
if (listener.caught==true) { oCB = oSimpleCB; }
}
else {
if (aProps.length>0) {
var to:Object = {targ:targ, props:aProps, bools:booleans, targZID:targ.__zigoID__};
if (tweenSuccess==false) {
// Important: callback, event, trigger:true need to only be added once per profile.
oCB = oSimpleCB;
to.event = event;
event = booleans = undefined;
to.trigger = triggerTrue; // single-target profile with trigger:true
}
_aTweens.push(to);
targ.addListener(this);
tweenSuccess = true;
for (j in aProps) if (propsAdded.indexOf(aProps[j]+',')==-1) propsAdded+=(aProps[j]+',');
}
// TRACE TWEENS (lets you know if one or more props didn't get added)
if (outputLevel==3) {
var epstr:String = aEP.toString();
if (aProps.length>aEP.length) epstr += ('\n\t[NO-CHANGE PROPS DISCARDED (disregard this for double props like _scale). KEPT:'+aProps.toString()+']');
var evstr:String = '';
for (j in aEV) evstr=(((typeof aEV[j]=='string')?'"'+aEV[j]+'"':aEV[j]) + ', '+evstr);
FuseKitCommon.output('\n-'+(_sID())+' TWEEN:\n'+(['\t[getTimer():'+getTimer()+'] ','targ: '+targ, 'props: '+epstr, 'endVals: '+evstr, 'time: '+((seconds==undefined) ? _ZigoEngine.DURATION : seconds), 'easing: '+((ease==undefined) ? _ZigoEngine.EASING : ease), 'delay: '+((delay==undefined) ? 0 : delay), 'callbacks: '+((cbstr=='') ? '(none)':cbstr)]).join('\n\t'));
}
}
listener = undefined;
}
} // end targets loop(i)
if (_global.isNaN(seconds)==true || pr.seconds==null) seconds = 0;
var time:Number = delay+seconds;
// time-based trigger: use a fake tween (trigger time must be less than tween duration+delay)
if (triggerTime!=undefined) {
// Special option to use a negative trigger time, which is counted back from the end of the tween
if (triggerTime<0) {
triggerTime += time;
}
if (triggerTime>0 && (time==0 || triggerTime