*
*
*
*
*
* @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back".
* @param {!Array.} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
* @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
* @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
*/
Definition = function(ns, dependencies, func, global) {
this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
_defLookup[ns] = this;
this.gsClass = null;
this.func = func;
var _classes = [];
this.check = function(init) {
var i = dependencies.length,
missing = i,
cur, a, n, cl, hasModule;
while (--i > -1) {
if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
_classes[i] = cur.gsClass;
missing--;
} else if (init) {
cur.sc.push(this);
}
}
if (missing === 0 && func) {
a = ("com.greensock." + ns).split(".");
n = a.pop();
cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
//exports to multiple environments
if (global) {
_globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.)
hasModule = (typeof(module) !== "undefined" && module.exports);
if (!hasModule && typeof(define) === "function" && define.amd){ //AMD
define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").pop(), [], function() { return cl; });
} else if (ns === moduleName && hasModule){ //node
module.exports = cl;
}
}
for (i = 0; i < this.sc.length; i++) {
this.sc[i].check();
}
}
};
this.check(true);
},
//used to create Definition instances (which basically registers a class that has dependencies).
_gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
return new Definition(ns, dependencies, func, global);
},
//a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class).
_class = gs._class = function(ns, func, global) {
func = func || function() {};
_gsDefine(ns, [], function(){ return func; }, global);
return func;
};
_gsDefine.globals = _globals;
/*
* ----------------------------------------------------------------
* Ease
* ----------------------------------------------------------------
*/
var _baseParams = [0, 0, 1, 1],
_blankArray = [],
Ease = _class("easing.Ease", function(func, extraParams, type, power) {
this._func = func;
this._type = type || 0;
this._power = power || 0;
this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
}, true),
_easeMap = Ease.map = {},
_easeReg = Ease.register = function(ease, names, types, create) {
var na = names.split(","),
i = na.length,
ta = (types || "easeIn,easeOut,easeInOut").split(","),
e, name, j, type;
while (--i > -1) {
name = na[i];
e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
j = ta.length;
while (--j > -1) {
type = ta[j];
_easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
}
}
};
p = Ease.prototype;
p._calcEnd = false;
p.getRatio = function(p) {
if (this._func) {
this._params[0] = p;
return this._func.apply(null, this._params);
}
var t = this._type,
pw = this._power,
r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
if (pw === 1) {
r *= r;
} else if (pw === 2) {
r *= r * r;
} else if (pw === 3) {
r *= r * r * r;
} else if (pw === 4) {
r *= r * r * r * r;
}
return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
};
//create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
i = a.length;
while (--i > -1) {
p = a[i]+",Power"+i;
_easeReg(new Ease(null,null,1,i), p, "easeOut", true);
_easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
_easeReg(new Ease(null,null,3,i), p, "easeInOut");
}
_easeMap.linear = gs.easing.Linear.easeIn;
_easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
/*
* ----------------------------------------------------------------
* EventDispatcher
* ----------------------------------------------------------------
*/
var EventDispatcher = _class("events.EventDispatcher", function(target) {
this._listeners = {};
this._eventTarget = target || this;
});
p = EventDispatcher.prototype;
p.addEventListener = function(type, callback, scope, useParam, priority) {
priority = priority || 0;
var list = this._listeners[type],
index = 0,
listener, i;
if (list == null) {
this._listeners[type] = list = [];
}
i = list.length;
while (--i > -1) {
listener = list[i];
if (listener.c === callback && listener.s === scope) {
list.splice(i, 1);
} else if (index === 0 && listener.pr < priority) {
index = i + 1;
}
}
list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
if (this === _ticker && !_tickerActive) {
_ticker.wake();
}
};
p.removeEventListener = function(type, callback) {
var list = this._listeners[type], i;
if (list) {
i = list.length;
while (--i > -1) {
if (list[i].c === callback) {
list.splice(i, 1);
return;
}
}
}
};
p.dispatchEvent = function(type) {
var list = this._listeners[type],
i, t, listener;
if (list) {
i = list.length;
t = this._eventTarget;
while (--i > -1) {
listener = list[i];
if (listener) {
if (listener.up) {
listener.c.call(listener.s || t, {type:type, target:t});
} else {
listener.c.call(listener.s || t);
}
}
}
}
};
/*
* ----------------------------------------------------------------
* Ticker
* ----------------------------------------------------------------
*/
var _reqAnimFrame = window.requestAnimationFrame,
_cancelAnimFrame = window.cancelAnimationFrame,
_getTime = Date.now || function() {return new Date().getTime();},
_lastUpdate = _getTime();
//now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
a = ["ms","moz","webkit","o"];
i = a.length;
while (--i > -1 && !_reqAnimFrame) {
_reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
_cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
}
_class("Ticker", function(fps, useRAF) {
var _self = this,
_startTime = _getTime(),
_useRAF = (useRAF !== false && _reqAnimFrame),
_lagThreshold = 500,
_adjustedLag = 33,
_tickWord = "tick", //helps reduce gc burden
_fps, _req, _id, _gap, _nextTime,
_tick = function(manual) {
var elapsed = _getTime() - _lastUpdate,
overlap, dispatch;
if (elapsed > _lagThreshold) {
_startTime += elapsed - _adjustedLag;
}
_lastUpdate += elapsed;
_self.time = (_lastUpdate - _startTime) / 1000;
overlap = _self.time - _nextTime;
if (!_fps || overlap > 0 || manual === true) {
_self.frame++;
_nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
dispatch = true;
}
if (manual !== true) { //make sure the request is made before we dispatch the "tick" event so that timing is maintained. Otherwise, if processing the "tick" requires a bunch of time (like 15ms) and we're using a setTimeout() that's based on 16.7ms, it'd technically take 31.7ms between frames otherwise.
_id = _req(_tick);
}
if (dispatch) {
_self.dispatchEvent(_tickWord);
}
};
EventDispatcher.call(_self);
_self.time = _self.frame = 0;
_self.tick = function() {
_tick(true);
};
_self.lagSmoothing = function(threshold, adjustedLag) {
_lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
_adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
};
_self.sleep = function() {
if (_id == null) {
return;
}
if (!_useRAF || !_cancelAnimFrame) {
clearTimeout(_id);
} else {
_cancelAnimFrame(_id);
}
_req = _emptyFunc;
_id = null;
if (_self === _ticker) {
_tickerActive = false;
}
};
_self.wake = function() {
if (_id !== null) {
_self.sleep();
} else if (_self.frame > 10) { //don't trigger lagSmoothing if we're just waking up, and make sure that at least 10 frames have elapsed because of the iOS bug that we work around below with the 1.5-second setTimout().
_lastUpdate = _getTime() - _lagThreshold + 5;
}
_req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
if (_self === _ticker) {
_tickerActive = true;
}
_tick(2);
};
_self.fps = function(value) {
if (!arguments.length) {
return _fps;
}
_fps = value;
_gap = 1 / (_fps || 60);
_nextTime = this.time + _gap;
_self.wake();
};
_self.useRAF = function(value) {
if (!arguments.length) {
return _useRAF;
}
_self.sleep();
_useRAF = value;
_self.fps(_fps);
};
_self.fps(fps);
//a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition.
setTimeout(function() {
if (_useRAF && _self.frame < 5) {
_self.useRAF(false);
}
}, 1500);
});
p = gs.Ticker.prototype = new gs.events.EventDispatcher();
p.constructor = gs.Ticker;
/*
* ----------------------------------------------------------------
* Animation
* ----------------------------------------------------------------
*/
var Animation = _class("core.Animation", function(duration, vars) {
this.vars = vars = vars || {};
this._duration = this._totalDuration = duration || 0;
this._delay = Number(vars.delay) || 0;
this._timeScale = 1;
this._active = (vars.immediateRender === true);
this.data = vars.data;
this._reversed = (vars.reversed === true);
if (!_rootTimeline) {
return;
}
if (!_tickerActive) { //some browsers (like iOS 6 Safari) shut down JavaScript execution when the tab is disabled and they [occasionally] neglect to start up requestAnimationFrame again when returning - this code ensures that the engine starts up again properly.
_ticker.wake();
}
var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
tl.add(this, tl._time);
if (this.vars.paused) {
this.paused(true);
}
});
_ticker = Animation.ticker = new gs.Ticker();
p = Animation.prototype;
p._dirty = p._gc = p._initted = p._paused = false;
p._totalTime = p._time = 0;
p._rawPrevTime = -1;
p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
p._paused = false;
//some browsers (like iOS) occasionally drop the requestAnimationFrame event when the user switches to a different tab and then comes back again, so we use a 2-second setTimeout() to sense if/when that condition occurs and then wake() the ticker.
var _checkTimeout = function() {
if (_tickerActive && _getTime() - _lastUpdate > 2000) {
_ticker.wake();
}
setTimeout(_checkTimeout, 2000);
};
_checkTimeout();
p.play = function(from, suppressEvents) {
if (from != null) {
this.seek(from, suppressEvents);
}
return this.reversed(false).paused(false);
};
p.pause = function(atTime, suppressEvents) {
if (atTime != null) {
this.seek(atTime, suppressEvents);
}
return this.paused(true);
};
p.resume = function(from, suppressEvents) {
if (from != null) {
this.seek(from, suppressEvents);
}
return this.paused(false);
};
p.seek = function(time, suppressEvents) {
return this.totalTime(Number(time), suppressEvents !== false);
};
p.restart = function(includeDelay, suppressEvents) {
return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
};
p.reverse = function(from, suppressEvents) {
if (from != null) {
this.seek((from || this.totalDuration()), suppressEvents);
}
return this.reversed(true).paused(false);
};
p.render = function(time, suppressEvents, force) {
//stub - we override this method in subclasses.
};
p.invalidate = function() {
this._time = this._totalTime = 0;
this._initted = this._gc = false;
this._rawPrevTime = -1;
if (this._gc || !this.timeline) {
this._enabled(true);
}
return this;
};
p.isActive = function() {
var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
startTime = this._startTime,
rawTime;
return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
};
p._enabled = function (enabled, ignoreTimeline) {
if (!_tickerActive) {
_ticker.wake();
}
this._gc = !enabled;
this._active = this.isActive();
if (ignoreTimeline !== true) {
if (enabled && !this.timeline) {
this._timeline.add(this, this._startTime - this._delay);
} else if (!enabled && this.timeline) {
this._timeline._remove(this, true);
}
}
return false;
};
p._kill = function(vars, target) {
return this._enabled(false, false);
};
p.kill = function(vars, target) {
this._kill(vars, target);
return this;
};
p._uncache = function(includeSelf) {
var tween = includeSelf ? this : this.timeline;
while (tween) {
tween._dirty = true;
tween = tween.timeline;
}
return this;
};
p._swapSelfInParams = function(params) {
var i = params.length,
copy = params.concat();
while (--i > -1) {
if (params[i] === "{self}") {
copy[i] = this;
}
}
return copy;
};
p._callback = function(type) {
var v = this.vars;
v[type].apply(v[type + "Scope"] || v.callbackScope || this, v[type + "Params"] || _blankArray);
};
//----Animation getters/setters --------------------------------------------------------
p.eventCallback = function(type, callback, params, scope) {
if ((type || "").substr(0,2) === "on") {
var v = this.vars;
if (arguments.length === 1) {
return v[type];
}
if (callback == null) {
delete v[type];
} else {
v[type] = callback;
v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
v[type + "Scope"] = scope;
}
if (type === "onUpdate") {
this._onUpdate = callback;
}
}
return this;
};
p.delay = function(value) {
if (!arguments.length) {
return this._delay;
}
if (this._timeline.smoothChildTiming) {
this.startTime( this._startTime + value - this._delay );
}
this._delay = value;
return this;
};
p.duration = function(value) {
if (!arguments.length) {
this._dirty = false;
return this._duration;
}
this._duration = this._totalDuration = value;
this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
this.totalTime(this._totalTime * (value / this._duration), true);
}
return this;
};
p.totalDuration = function(value) {
this._dirty = false;
return (!arguments.length) ? this._totalDuration : this.duration(value);
};
p.time = function(value, suppressEvents) {
if (!arguments.length) {
return this._time;
}
if (this._dirty) {
this.totalDuration();
}
return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
};
p.totalTime = function(time, suppressEvents, uncapped) {
if (!_tickerActive) {
_ticker.wake();
}
if (!arguments.length) {
return this._totalTime;
}
if (this._timeline) {
if (time < 0 && !uncapped) {
time += this.totalDuration();
}
if (this._timeline.smoothChildTiming) {
if (this._dirty) {
this.totalDuration();
}
var totalDuration = this._totalDuration,
tl = this._timeline;
if (time > totalDuration && !uncapped) {
time = totalDuration;
}
this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the ancestors as dirty too, so skip the function call here.
this._uncache(false);
}
//in case any of the ancestor timelines had completed but should now be enabled, we should reset their totalTime() which will also ensure that they're lined up properly and enabled. Skip for animations that are on the root (wasteful). Example: a TimelineLite.exportRoot() is performed when there's a paused tween on the root, the export will not complete until that tween is unpaused, but imagine a child gets restarted later, after all [unpaused] tweens have completed. The startTime of that child would get pushed out, but one of the ancestors may have completed.
if (tl._timeline) {
while (tl._timeline) {
if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
tl.totalTime(tl._totalTime, true);
}
tl = tl._timeline;
}
}
}
if (this._gc) {
this._enabled(true, false);
}
if (this._totalTime !== time || this._duration === 0) {
if (_lazyTweens.length) {
_lazyRender();
}
this.render(time, suppressEvents, false);
if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when someone calls seek() or time() or progress(), they expect an immediate render.
_lazyRender();
}
}
}
return this;
};
p.progress = p.totalProgress = function(value, suppressEvents) {
var duration = this.duration();
return (!arguments.length) ? (duration ? this._time / duration : this.ratio) : this.totalTime(duration * value, suppressEvents);
};
p.startTime = function(value) {
if (!arguments.length) {
return this._startTime;
}
if (value !== this._startTime) {
this._startTime = value;
if (this.timeline) if (this.timeline._sortChildren) {
this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
}
}
return this;
};
p.endTime = function(includeRepeats) {
return this._startTime + ((includeRepeats != false) ? this.totalDuration() : this.duration()) / this._timeScale;
};
p.timeScale = function(value) {
if (!arguments.length) {
return this._timeScale;
}
value = value || _tinyNum; //can't allow zero because it'll throw the math off
if (this._timeline && this._timeline.smoothChildTiming) {
var pauseTime = this._pauseTime,
t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
this._startTime = t - ((t - this._startTime) * this._timeScale / value);
}
this._timeScale = value;
return this._uncache(false);
};
p.reversed = function(value) {
if (!arguments.length) {
return this._reversed;
}
if (value != this._reversed) {
this._reversed = value;
this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
}
return this;
};
p.paused = function(value) {
if (!arguments.length) {
return this._paused;
}
var tl = this._timeline,
raw, elapsed;
if (value != this._paused) if (tl) {
if (!_tickerActive && !value) {
_ticker.wake();
}
raw = tl.rawTime();
elapsed = raw - this._pauseTime;
if (!value && tl.smoothChildTiming) {
this._startTime += elapsed;
this._uncache(false);
}
this._pauseTime = value ? raw : null;
this._paused = value;
this._active = this.isActive();
if (!value && elapsed !== 0 && this._initted && this.duration()) {
raw = tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale;
this.render(raw, (raw === this._totalTime), true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render.
}
}
if (this._gc && !value) {
this._enabled(true, false);
}
return this;
};
/*
* ----------------------------------------------------------------
* SimpleTimeline
* ----------------------------------------------------------------
*/
var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
Animation.call(this, 0, vars);
this.autoRemoveChildren = this.smoothChildTiming = true;
});
p = SimpleTimeline.prototype = new Animation();
p.constructor = SimpleTimeline;
p.kill()._gc = false;
p._first = p._last = p._recent = null;
p._sortChildren = false;
p.add = p.insert = function(child, position, align, stagger) {
var prevTween, st;
child._startTime = Number(position || 0) + child._delay;
if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order).
child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
}
if (child.timeline) {
child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
}
child.timeline = child._timeline = this;
if (child._gc) {
child._enabled(true, true);
}
prevTween = this._last;
if (this._sortChildren) {
st = child._startTime;
while (prevTween && prevTween._startTime > st) {
prevTween = prevTween._prev;
}
}
if (prevTween) {
child._next = prevTween._next;
prevTween._next = child;
} else {
child._next = this._first;
this._first = child;
}
if (child._next) {
child._next._prev = child;
} else {
this._last = child;
}
child._prev = prevTween;
this._recent = child;
if (this._timeline) {
this._uncache(true);
}
return this;
};
p._remove = function(tween, skipDisable) {
if (tween.timeline === this) {
if (!skipDisable) {
tween._enabled(false, true);
}
if (tween._prev) {
tween._prev._next = tween._next;
} else if (this._first === tween) {
this._first = tween._next;
}
if (tween._next) {
tween._next._prev = tween._prev;
} else if (this._last === tween) {
this._last = tween._prev;
}
tween._next = tween._prev = tween.timeline = null;
if (tween === this._recent) {
this._recent = this._last;
}
if (this._timeline) {
this._uncache(true);
}
}
return this;
};
p.render = function(time, suppressEvents, force) {
var tween = this._first,
next;
this._totalTime = this._time = this._rawPrevTime = time;
while (tween) {
next = tween._next; //record it here because the value could change after rendering...
if (tween._active || (time >= tween._startTime && !tween._paused)) {
if (!tween._reversed) {
tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
} else {
tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
}
}
tween = next;
}
};
p.rawTime = function() {
if (!_tickerActive) {
_ticker.wake();
}
return this._totalTime;
};
/*
* ----------------------------------------------------------------
* TweenLite
* ----------------------------------------------------------------
*/
var TweenLite = _class("TweenLite", function(target, duration, vars) {
Animation.call(this, duration, vars);
this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
if (target == null) {
throw "Cannot tween a null target.";
}
this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
overwrite = this.vars.overwrite,
i, targ, targets;
this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
this._targets = targets = _slice(target); //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
this._propLookup = [];
this._siblings = [];
for (i = 0; i < targets.length; i++) {
targ = targets[i];
if (!targ) {
targets.splice(i--, 1);
continue;
} else if (typeof(targ) === "string") {
targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
if (typeof(targ) === "string") {
targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
}
continue;
} else if (targ.length && targ !== window && targ[0] && (targ[0] === window || (targ[0].nodeType && targ[0].style && !targ.nodeType))) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that