1 angular.module("att.abs", ["att.abs.tpls", "att.abs.position","att.abs.transition","att.abs.accordion","att.abs.alert","att.abs.breadCrumbs","att.abs.utilities","att.abs.buttons","att.abs.checkbox","att.abs.colorselector","att.abs.datepicker","att.abs.devNotes","att.abs.dividerLines","att.abs.dragdrop","att.abs.drawer","att.abs.message","att.abs.formField","att.abs.hourpicker","att.abs.iconButtons","att.abs.links","att.abs.loading","att.abs.modal","att.abs.pagination","att.abs.paneSelector","att.abs.profileCard","att.abs.progressBars","att.abs.radio","att.abs.scrollbar","att.abs.search","att.abs.select","att.abs.slider","att.abs.splitButtonDropdown","att.abs.splitIconButton","att.abs.stepSlider","att.abs.steptracker","att.abs.table","att.abs.tabs","att.abs.tagBadges","att.abs.textOverflow","att.abs.toggle","att.abs.tooltip","att.abs.treeview","att.abs.typeAhead","att.abs.userMessages","att.abs.verticalSteptracker","att.abs.videoControls"]);
2 angular.module("att.abs.tpls", ["app/scripts/ng_js_att_tpls/accordion/accordion.html","app/scripts/ng_js_att_tpls/accordion/accordion_alt.html","app/scripts/ng_js_att_tpls/accordion/attAccord.html","app/scripts/ng_js_att_tpls/accordion/attAccordBody.html","app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html","app/scripts/ng_js_att_tpls/alert/alert.html","app/scripts/ng_js_att_tpls/colorselector/colorselector.html","app/scripts/ng_js_att_tpls/datepicker/dateFilter.html","app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html","app/scripts/ng_js_att_tpls/datepicker/datepicker.html","app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html","app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html","app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html","app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html","app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html","app/scripts/ng_js_att_tpls/links/readMore.html","app/scripts/ng_js_att_tpls/loading/loading.html","app/scripts/ng_js_att_tpls/modal/backdrop.html","app/scripts/ng_js_att_tpls/modal/window.html","app/scripts/ng_js_att_tpls/pagination/pagination.html","app/scripts/ng_js_att_tpls/paneSelector/innerPane.html","app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html","app/scripts/ng_js_att_tpls/paneSelector/sidePane.html","app/scripts/ng_js_att_tpls/profileCard/addUser.html","app/scripts/ng_js_att_tpls/profileCard/profileCard.html","app/scripts/ng_js_att_tpls/progressBars/progressBars.html","app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html","app/scripts/ng_js_att_tpls/search/search.html","app/scripts/ng_js_att_tpls/search/search_2.html","app/scripts/ng_js_att_tpls/select/select.html","app/scripts/ng_js_att_tpls/select/textDropdown.html","app/scripts/ng_js_att_tpls/slider/maxContent.html","app/scripts/ng_js_att_tpls/slider/minContent.html","app/scripts/ng_js_att_tpls/slider/slider.html","app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html","app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html","app/scripts/ng_js_att_tpls/steptracker/step-tracker.html","app/scripts/ng_js_att_tpls/steptracker/step.html","app/scripts/ng_js_att_tpls/steptracker/timeline.html","app/scripts/ng_js_att_tpls/steptracker/timelineBar.html","app/scripts/ng_js_att_tpls/steptracker/timelineDot.html","app/scripts/ng_js_att_tpls/table/attTable.html","app/scripts/ng_js_att_tpls/table/attTableBody.html","app/scripts/ng_js_att_tpls/table/attTableHeader.html","app/scripts/ng_js_att_tpls/tabs/floatingTabs.html","app/scripts/ng_js_att_tpls/tabs/genericTabs.html","app/scripts/ng_js_att_tpls/tabs/menuTab.html","app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html","app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html","app/scripts/ng_js_att_tpls/tabs/submenuTab.html","app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html","app/scripts/ng_js_att_tpls/toggle/demoToggle.html","app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html","app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html","app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html","app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html","app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html","app/scripts/ng_js_att_tpls/videoControls/photoControls.html","app/scripts/ng_js_att_tpls/videoControls/videoControls.html"]);
3 angular.module('att.abs.position', [])
5 .factory('$position', ['$document', '$window', function ($document, $window) {
6 function getStyle(el, cssprop) {
7 if (el.currentStyle) { //IE
8 return el.currentStyle[cssprop];
9 } else if ($window.getComputedStyle) {
10 return $window.getComputedStyle(el)[cssprop];
12 // finally try and get inline style
13 return el.style[cssprop];
17 * Checks if a given element is statically positioned
18 * @param element - raw DOM element
20 function isStaticPositioned(element) {
21 return (getStyle(element, "position") || 'static') === 'static';
25 * returns the closest, non-statically positioned parentOffset of a given element
28 var parentOffsetEl = function (element) {
29 var docDomEl = $document[0];
30 var offsetParent = element.offsetParent || docDomEl;
31 while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
32 offsetParent = offsetParent.offsetParent;
34 return offsetParent || docDomEl;
39 * Provides read-only equivalent of jQuery's position function:
40 * http://api.jquery.com/position/
42 position: function (element) {
43 var elBCR = this.offset(element);
44 var offsetParentBCR = {
48 var offsetParentEl = parentOffsetEl(element[0]);
49 if (offsetParentEl !== $document[0]) {
50 offsetParentBCR = this.offset(angular.element(offsetParentEl));
51 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
52 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
56 width: element.prop('offsetWidth'),
57 height: element.prop('offsetHeight'),
58 top: elBCR.top - offsetParentBCR.top,
59 left: elBCR.left - offsetParentBCR.left
64 * Provides read-only equivalent of jQuery's offset function:
65 * http://api.jquery.com/offset/
67 offset: function (element) {
68 var boundingClientRect = element[0].getBoundingClientRect();
70 width: element.prop('offsetWidth'),
71 height: element.prop('offsetHeight'),
72 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
73 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
79 .factory('$isElement', [function () {
80 var isElement = function (currentElem, targetElem, alternateElem) {
81 if (currentElem[0] === targetElem[0]) {
83 } else if (currentElem[0] === alternateElem[0]) {
86 return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
96 * UPDATES AND DOCS AT: http://www.greensock.com
98 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
99 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
100 * Club GreenSock members, the software agreement that was issued with your membership.
102 * @author: Jack Doyle, jack@greensock.com
104 (window._gsQueue || (window._gsQueue = [])).push( function() {
108 var _doc = document.documentElement,
110 _max = function(element, axis) {
111 var dim = (axis === "x") ? "Width" : "Height",
112 scroll = "scroll" + dim,
113 client = "client" + dim,
114 body = document.body;
115 return (element === _window || element === _doc || element === body) ? Math.max(_doc[scroll], body[scroll]) - (_window["inner" + dim] || Math.max(_doc[client], body[client])) : element[scroll] - element["offset" + dim];
118 ScrollToPlugin = window._gsDefine.plugin({
119 propName: "scrollTo",
123 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
124 init: function(target, value, tween) {
125 this._wdw = (target === _window);
126 this._target = target;
128 if (typeof(value) !== "object") {
129 value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
131 this._autoKill = (value.autoKill !== false);
132 this.x = this.xPrev = this.getX();
133 this.y = this.yPrev = this.getY();
134 if (value.x != null) {
135 this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
136 this._overwriteProps.push("scrollTo_x");
140 if (value.y != null) {
141 this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
142 this._overwriteProps.push("scrollTo_y");
149 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
151 this._super.setRatio.call(this, v);
153 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
154 y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
155 yDif = y - this.yPrev,
156 xDif = x - this.xPrev;
158 if (this._autoKill) {
159 //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match.
160 if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
161 this.skipX = true; //if the user scrolls separately, we should stop tweening!
163 if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
164 this.skipY = true; //if the user scrolls separately, we should stop tweening!
166 if (this.skipX && this.skipY) {
171 _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
174 this._target.scrollTop = this.y;
177 this._target.scrollLeft = this.x;
185 p = ScrollToPlugin.prototype;
187 ScrollToPlugin.max = _max;
189 p.getX = function() {
190 return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
193 p.getY = function() {
194 return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
197 p._kill = function(lookup) {
198 if (lookup.scrollTo_x) {
201 if (lookup.scrollTo_y) {
204 return this._super._kill.call(this, lookup);
207 }); if (window._gsDefine) { window._gsQueue.pop()(); }
211 * UPDATES AND DOCS AT: http://www.greensock.com
213 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
215 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
216 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
217 * Club GreenSock members, the software agreement that was issued with your membership.
219 * @author: Jack Doyle, jack@greensock.com
222 (window._gsQueue || (window._gsQueue = [])).push( function() {
226 window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
228 var _slice = [].slice,
229 TweenMax = function(target, duration, vars) {
230 TweenLite.call(this, target, duration, vars);
232 this._yoyo = (this.vars.yoyo === true);
233 this._repeat = this.vars.repeat || 0;
234 this._repeatDelay = this.vars.repeatDelay || 0;
235 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
236 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
238 _tinyNum = 0.0000000001,
239 TweenLiteInternals = TweenLite._internals,
240 _isSelector = TweenLiteInternals.isSelector,
241 _isArray = TweenLiteInternals.isArray,
242 p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
245 TweenMax.version = "1.12.1";
246 p.constructor = TweenMax;
247 p.kill()._gc = false;
248 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
249 TweenMax.getTweensOf = TweenLite.getTweensOf;
250 TweenMax.lagSmoothing = TweenLite.lagSmoothing;
251 TweenMax.ticker = TweenLite.ticker;
252 TweenMax.render = TweenLite.render;
254 p.invalidate = function() {
255 this._yoyo = (this.vars.yoyo === true);
256 this._repeat = this.vars.repeat || 0;
257 this._repeatDelay = this.vars.repeatDelay || 0;
259 return TweenLite.prototype.invalidate.call(this);
262 p.updateTo = function(vars, resetDuration) {
263 var curRatio = this.ratio, p;
264 if (resetDuration && this._startTime < this._timeline._time) {
265 this._startTime = this._timeline._time;
266 this._uncache(false);
268 this._enabled(true, false);
270 this._timeline.insert(this, this._startTime - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
274 this.vars[p] = vars[p];
278 this._initted = false;
281 this._enabled(true, false);
283 if (this._notifyPluginsOfEnabled && this._firstPT) {
284 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
286 if (this._time / this._duration > 0.998) { //if the tween has finished (or come extremely close to finishing), we just need to rewind it to 0 and then render it again at the end which forces it to re-initialize (parsing the new vars). We allow tweens that are close to finishing (but haven't quite finished) to work this way too because otherwise, the values are so small when determining where to project the starting values that binary math issues creep in and can make the tween appear to render incorrectly when run backwards.
287 var prevTime = this._time;
288 this.render(0, true, false);
289 this._initted = false;
290 this.render(prevTime, true, false);
291 } else if (this._time > 0) {
292 this._initted = false;
294 var inv = 1 / (1 - curRatio),
295 pt = this._firstPT, endValue;
297 endValue = pt.s + pt.c;
299 pt.s = endValue - pt.c;
308 p.render = function(time, suppressEvents, force) {
309 if (!this._initted) if (this._duration === 0 && this.vars.repeat) { //zero duration tweens that render immediately have render() called from TweenLite's constructor, before TweenMax's constructor has finished setting _repeat, _repeatDelay, and _yoyo which are critical in determining totalDuration() so we need to call invalidate() which is a low-kb way to get those set properly.
312 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
313 prevTime = this._time,
314 prevTotalTime = this._totalTime,
315 prevCycle = this._cycle,
316 duration = this._duration,
317 prevRawPrevTime = this._rawPrevTime,
318 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
319 if (time >= totalDur) {
320 this._totalTime = totalDur;
321 this._cycle = this._repeat;
322 if (this._yoyo && (this._cycle & 1) !== 0) {
324 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
326 this._time = duration;
327 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
329 if (!this._reversed) {
331 callback = "onComplete";
333 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
334 if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate.
337 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
339 if (prevRawPrevTime > _tinyNum) {
340 callback = "onReverseComplete";
343 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
346 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
347 this._totalTime = this._time = this._cycle = 0;
348 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
349 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
350 callback = "onReverseComplete";
351 isComplete = this._reversed;
354 this._active = false;
355 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
356 if (prevRawPrevTime >= 0) {
359 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
361 } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
365 this._totalTime = this._time = time;
367 if (this._repeat !== 0) {
368 cycleDuration = duration + this._repeatDelay;
369 this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but Flash reports it as 0.79999999!)
370 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
371 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
373 this._time = this._totalTime - (this._cycle * cycleDuration);
374 if (this._yoyo) if ((this._cycle & 1) !== 0) {
375 this._time = duration - this._time;
377 if (this._time > duration) {
378 this._time = duration;
379 } else if (this._time < 0) {
384 if (this._easeType) {
385 r = this._time / duration;
386 type = this._easeType;
387 pow = this._easePower;
388 if (type === 1 || (type === 3 && r >= 0.5)) {
396 } else if (pow === 2) {
398 } else if (pow === 3) {
400 } else if (pow === 4) {
406 } else if (type === 2) {
408 } else if (this._time / duration < 0.5) {
411 this.ratio = 1 - (r / 2);
415 this.ratio = this._ease.getRatio(this._time / duration);
420 if (prevTime === this._time && !force && prevCycle === this._cycle) {
421 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
422 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
425 } else if (!this._initted) {
427 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example.
429 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) { //we stick it in the queue for rendering at the very end of the tick - this is a performance optimization because browsers invalidate styles and force a recalculation if you read, write, and then read style data (so it's better to read/read/read/write/write/write than read/write/read/write/read/write). The down side, of course, is that usually you WANT things to render immediately because you may have code running right after that which depends on the change. Like imagine running TweenLite.set(...) and then immediately after that, creating a nother tween that animates the same property to another value; the starting values of that 2nd tween wouldn't be accurate if lazy is true.
430 this._time = prevTime;
431 this._totalTime = prevTotalTime;
432 this._rawPrevTime = prevRawPrevTime;
433 this._cycle = prevCycle;
434 TweenLiteInternals.lazyTweens.push(this);
438 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
439 if (this._time && !isComplete) {
440 this.ratio = this._ease.getRatio(this._time / duration);
441 } else if (isComplete && this._ease._calcEnd) {
442 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
445 if (this._lazy !== false) {
449 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
450 this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
452 if (prevTotalTime === 0) {
453 if (this._initted === 2 && time > 0) {
455 this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
459 this._startAt.render(time, suppressEvents, force);
460 } else if (!callback) {
461 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
464 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
465 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
472 pt.t[pt.p](pt.c * this.ratio + pt.s);
474 pt.t[pt.p] = pt.c * this.ratio + pt.s;
479 if (this._onUpdate) {
480 if (time < 0) if (this._startAt && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
481 this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
483 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
484 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
487 if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
488 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
490 if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
491 if (time < 0 && this._startAt && !this._onUpdate && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
492 this._startAt.render(time, suppressEvents, force);
495 if (this._timeline.autoRemoveChildren) {
496 this._enabled(false, false);
498 this._active = false;
500 if (!suppressEvents && this.vars[callback]) {
501 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
503 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless.
504 this._rawPrevTime = 0;
509 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
511 TweenMax.to = function(target, duration, vars) {
512 return new TweenMax(target, duration, vars);
515 TweenMax.from = function(target, duration, vars) {
516 vars.runBackwards = true;
517 vars.immediateRender = (vars.immediateRender != false);
518 return new TweenMax(target, duration, vars);
521 TweenMax.fromTo = function(target, duration, fromVars, toVars) {
522 toVars.startAt = fromVars;
523 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
524 return new TweenMax(target, duration, toVars);
527 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
528 stagger = stagger || 0;
529 var delay = vars.delay || 0,
531 finalComplete = function() {
532 if (vars.onComplete) {
533 vars.onComplete.apply(vars.onCompleteScope || this, arguments);
535 onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
538 if (!_isArray(targets)) {
539 if (typeof(targets) === "string") {
540 targets = TweenLite.selector(targets) || targets;
542 if (_isSelector(targets)) {
543 targets = _slice.call(targets, 0);
547 for (i = 0; i < l; i++) {
553 if (i === l - 1 && onCompleteAll) {
554 copy.onComplete = finalComplete;
556 a[i] = new TweenMax(targets[i], duration, copy);
562 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
563 vars.runBackwards = true;
564 vars.immediateRender = (vars.immediateRender != false);
565 return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
568 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
569 toVars.startAt = fromVars;
570 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
571 return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
574 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
575 return new TweenMax(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
578 TweenMax.set = function(target, vars) {
579 return new TweenMax(target, 0, vars);
582 TweenMax.isTweening = function(target) {
583 return (TweenLite.getTweensOf(target, true).length > 0);
586 var _getChildrenOf = function(timeline, includeTimelines) {
589 tween = timeline._first;
591 if (tween instanceof TweenLite) {
594 if (includeTimelines) {
597 a = a.concat(_getChildrenOf(tween, includeTimelines));
604 getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
605 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
608 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
609 if (tweens == null) {
612 if (delayedCalls == null) {
615 var a = getAllTweens((timelines != false)),
617 allTrue = (tweens && delayedCalls && timelines),
619 for (i = 0; i < l; i++) {
621 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
623 tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
625 tween._enabled(false, false);
631 TweenMax.killChildTweensOf = function(parent, complete) {
632 if (parent == null) {
635 var tl = TweenLiteInternals.tweenLookup,
636 a, curParent, p, i, l;
637 if (typeof(parent) === "string") {
638 parent = TweenLite.selector(parent) || parent;
640 if (_isSelector(parent)) {
641 parent = _slice.call(parent, 0);
643 if (_isArray(parent)) {
646 TweenMax.killChildTweensOf(parent[i], complete);
652 curParent = tl[p].target.parentNode;
654 if (curParent === parent) {
655 a = a.concat(tl[p].tweens);
657 curParent = curParent.parentNode;
661 for (i = 0; i < l; i++) {
663 a[i].totalTime(a[i].totalDuration());
665 a[i]._enabled(false, false);
669 var _changePause = function(pause, tweens, delayedCalls, timelines) {
670 tweens = (tweens !== false);
671 delayedCalls = (delayedCalls !== false);
672 timelines = (timelines !== false);
673 var a = getAllTweens(timelines),
674 allTrue = (tweens && delayedCalls && timelines),
679 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
685 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
686 _changePause(true, tweens, delayedCalls, timelines);
689 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
690 _changePause(false, tweens, delayedCalls, timelines);
693 TweenMax.globalTimeScale = function(value) {
694 var tl = Animation._rootTimeline,
695 t = TweenLite.ticker.time;
696 if (!arguments.length) {
697 return tl._timeScale;
699 value = value || _tinyNum; //can't allow zero because it'll throw the math off
700 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
701 tl = Animation._rootFramesTimeline;
702 t = TweenLite.ticker.frame;
703 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
704 tl._timeScale = Animation._rootTimeline._timeScale = value;
709 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
711 p.progress = function(value) {
712 return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
715 p.totalProgress = function(value) {
716 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
719 p.time = function(value, suppressEvents) {
720 if (!arguments.length) {
724 this.totalDuration();
726 if (value > this._duration) {
727 value = this._duration;
729 if (this._yoyo && (this._cycle & 1) !== 0) {
730 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
731 } else if (this._repeat !== 0) {
732 value += this._cycle * (this._duration + this._repeatDelay);
734 return this.totalTime(value, suppressEvents);
737 p.duration = function(value) {
738 if (!arguments.length) {
739 return this._duration; //don't set _dirty = false because there could be repeats that haven't been factored into the _totalDuration yet. Otherwise, if you create a repeated TweenMax and then immediately check its duration(), it would cache the value and the totalDuration would not be correct, thus repeats wouldn't take effect.
741 return Animation.prototype.duration.call(this, value);
744 p.totalDuration = function(value) {
745 if (!arguments.length) {
747 //instead of Infinity, we use 999999999999 so that we can accommodate reverses
748 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
751 return this._totalDuration;
753 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
756 p.repeat = function(value) {
757 if (!arguments.length) {
760 this._repeat = value;
761 return this._uncache(true);
764 p.repeatDelay = function(value) {
765 if (!arguments.length) {
766 return this._repeatDelay;
768 this._repeatDelay = value;
769 return this._uncache(true);
772 p.yoyo = function(value) {
773 if (!arguments.length) {
793 * ----------------------------------------------------------------
795 * ----------------------------------------------------------------
797 window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
799 var TimelineLite = function(vars) {
800 SimpleTimeline.call(this, vars);
802 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
803 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
804 this._sortChildren = true;
805 this._onUpdate = this.vars.onUpdate;
810 if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
811 v[p] = this._swapSelfInParams(val);
814 if (_isArray(v.tweens)) {
815 this.add(v.tweens, 0, v.align, v.stagger);
818 _tinyNum = 0.0000000001,
819 _isSelector = TweenLite._internals.isSelector,
820 _isArray = TweenLite._internals.isArray,
822 _globals = window._gsDefine.globals,
823 _copy = function(vars) {
830 _pauseCallback = function(tween, callback, params, scope) {
831 tween._timeline.pause(tween._startTime);
833 callback.apply(scope || tween._timeline, params || _blankArray);
836 _slice = _blankArray.slice,
837 p = TimelineLite.prototype = new SimpleTimeline();
839 TimelineLite.version = "1.12.1";
840 p.constructor = TimelineLite;
841 p.kill()._gc = false;
843 p.to = function(target, duration, vars, position) {
844 var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
845 return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
848 p.from = function(target, duration, vars, position) {
849 return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
852 p.fromTo = function(target, duration, fromVars, toVars, position) {
853 var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
854 return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
857 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
858 var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
860 if (typeof(targets) === "string") {
861 targets = TweenLite.selector(targets) || targets;
863 if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
864 targets = _slice.call(targets, 0);
866 stagger = stagger || 0;
867 for (i = 0; i < targets.length; i++) {
869 vars.startAt = _copy(vars.startAt);
871 tl.to(targets[i], duration, _copy(vars), i * stagger);
873 return this.add(tl, position);
876 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
877 vars.immediateRender = (vars.immediateRender != false);
878 vars.runBackwards = true;
879 return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
882 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
883 toVars.startAt = fromVars;
884 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
885 return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
888 p.call = function(callback, params, scope, position) {
889 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
892 p.set = function(target, vars, position) {
893 position = this._parseTimeOrLabel(position, 0, true);
894 if (vars.immediateRender == null) {
895 vars.immediateRender = (position === this._time && !this._paused);
897 return this.add( new TweenLite(target, 0, vars), position);
900 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
902 if (vars.smoothChildTiming == null) {
903 vars.smoothChildTiming = true;
905 var tl = new TimelineLite(vars),
908 if (ignoreDelayedCalls == null) {
909 ignoreDelayedCalls = true;
911 root._remove(tl, true);
913 tl._rawPrevTime = tl._time = tl._totalTime = root._time;
917 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
918 tl.add(tween, tween._startTime - tween._delay);
926 p.add = function(value, position, align, stagger) {
927 var curTime, l, i, child, tl, beforeRawTime;
928 if (typeof(position) !== "number") {
929 position = this._parseTimeOrLabel(position, 0, true, value);
931 if (!(value instanceof Animation)) {
932 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
933 align = align || "normal";
934 stagger = stagger || 0;
937 for (i = 0; i < l; i++) {
938 if (_isArray(child = value[i])) {
939 child = new TimelineLite({tweens:child});
941 this.add(child, curTime);
942 if (typeof(child) !== "string" && typeof(child) !== "function") {
943 if (align === "sequence") {
944 curTime = child._startTime + (child.totalDuration() / child._timeScale);
945 } else if (align === "start") {
946 child._startTime -= child.delay();
951 return this._uncache(true);
952 } else if (typeof(value) === "string") {
953 return this.addLabel(value, position);
954 } else if (typeof(value) === "function") {
955 value = TweenLite.delayedCall(0, value);
957 throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
961 SimpleTimeline.prototype.add.call(this, value, position);
963 //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate.
964 if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
965 //in case any of the ancestors had completed but should now be enabled...
967 beforeRawTime = (tl.rawTime() > value._startTime); //if the tween is placed on the timeline so that it starts BEFORE the current rawTime, we should align the playhead (move the timeline). This is because sometimes users will create a timeline, let it finish, and much later append a tween and expect it to run instead of jumping to its end state. While technically one could argue that it should jump to its end state, that's not what users intuitively expect.
968 while (tl._timeline) {
969 if (beforeRawTime && tl._timeline.smoothChildTiming) {
970 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
972 tl._enabled(true, false);
981 p.remove = function(value) {
982 if (value instanceof Animation) {
983 return this._remove(value, false);
984 } else if (value instanceof Array || (value && value.push && _isArray(value))) {
985 var i = value.length;
987 this.remove(value[i]);
990 } else if (typeof(value) === "string") {
991 return this.removeLabel(value);
993 return this.kill(null, value);
996 p._remove = function(tween, skipDisable) {
997 SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
998 var last = this._last;
1000 this._time = this._totalTime = this._duration = this._totalDuration = 0;
1001 } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
1002 this._time = this.duration();
1003 this._totalTime = this._totalDuration;
1008 p.append = function(value, offsetOrLabel) {
1009 return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
1012 p.insert = p.insertMultiple = function(value, position, align, stagger) {
1013 return this.add(value, position || 0, align, stagger);
1016 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
1017 return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
1020 p.addLabel = function(label, position) {
1021 this._labels[label] = this._parseTimeOrLabel(position);
1025 p.addPause = function(position, callback, params, scope) {
1026 return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
1029 p.removeLabel = function(label) {
1030 delete this._labels[label];
1034 p.getLabelTime = function(label) {
1035 return (this._labels[label] != null) ? this._labels[label] : -1;
1038 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
1040 //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
1041 if (ignore instanceof Animation && ignore.timeline === this) {
1042 this.remove(ignore);
1043 } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
1046 if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
1047 this.remove(ignore[i]);
1051 if (typeof(offsetOrLabel) === "string") {
1052 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
1054 offsetOrLabel = offsetOrLabel || 0;
1055 if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
1056 i = timeOrLabel.indexOf("=");
1058 if (this._labels[timeOrLabel] == null) {
1059 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
1061 return this._labels[timeOrLabel] + offsetOrLabel;
1063 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
1064 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
1065 } else if (timeOrLabel == null) {
1066 timeOrLabel = this.duration();
1068 return Number(timeOrLabel) + offsetOrLabel;
1071 p.seek = function(position, suppressEvents) {
1072 return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
1075 p.stop = function() {
1076 return this.paused(true);
1079 p.gotoAndPlay = function(position, suppressEvents) {
1080 return this.play(position, suppressEvents);
1083 p.gotoAndStop = function(position, suppressEvents) {
1084 return this.pause(position, suppressEvents);
1087 p.render = function(time, suppressEvents, force) {
1089 this._enabled(true, false);
1091 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
1092 prevTime = this._time,
1093 prevStart = this._startTime,
1094 prevTimeScale = this._timeScale,
1095 prevPaused = this._paused,
1096 tween, isComplete, next, callback, internalForce;
1097 if (time >= totalDur) {
1098 this._totalTime = this._time = totalDur;
1099 if (!this._reversed) if (!this._hasPausedChild()) {
1101 callback = "onComplete";
1102 if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
1103 internalForce = true;
1104 if (this._rawPrevTime > _tinyNum) {
1105 callback = "onReverseComplete";
1109 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
1110 time = totalDur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7.
1112 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
1113 this._totalTime = this._time = 0;
1114 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
1115 callback = "onReverseComplete";
1116 isComplete = this._reversed;
1119 this._active = false;
1120 if (this._duration === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
1121 internalForce = true;
1123 this._rawPrevTime = time;
1125 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
1127 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
1128 if (!this._initted) {
1129 internalForce = true;
1134 this._totalTime = this._time = this._rawPrevTime = time;
1136 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
1138 } else if (!this._initted) {
1139 this._initted = true;
1142 if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
1143 this._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example.
1146 if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
1147 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1150 if (this._time >= prevTime) {
1151 tween = this._first;
1153 next = tween._next; //record it here because the value could change after rendering...
1154 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1156 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
1157 if (!tween._reversed) {
1158 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1160 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1168 next = tween._prev; //record it here because the value could change after rendering...
1169 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1171 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
1172 if (!tween._reversed) {
1173 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1175 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1182 if (this._onUpdate) if (!suppressEvents) {
1183 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1186 if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
1188 if (this._timeline.autoRemoveChildren) {
1189 this._enabled(false, false);
1191 this._active = false;
1193 if (!suppressEvents && this.vars[callback]) {
1194 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1199 p._hasPausedChild = function() {
1200 var tween = this._first;
1202 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
1205 tween = tween._next;
1210 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
1211 ignoreBeforeTime = ignoreBeforeTime || -9999999999;
1213 tween = this._first,
1216 if (tween._startTime < ignoreBeforeTime) {
1218 } else if (tween instanceof TweenLite) {
1219 if (tweens !== false) {
1223 if (timelines !== false) {
1226 if (nested !== false) {
1227 a = a.concat(tween.getChildren(true, tweens, timelines));
1231 tween = tween._next;
1236 p.getTweensOf = function(target, nested) {
1237 var disabled = this._gc,
1242 this._enabled(true, true); //getTweensOf() filters out disabled tweens, and we have to mark them as _gc = true when the timeline completes in order to allow clean garbage collection, so temporarily re-enable the timeline here.
1244 tweens = TweenLite.getTweensOf(target);
1247 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
1248 a[cnt++] = tweens[i];
1252 this._enabled(false, true);
1257 p._contains = function(tween) {
1258 var tl = tween.timeline;
1268 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
1269 ignoreBeforeTime = ignoreBeforeTime || 0;
1270 var tween = this._first,
1271 labels = this._labels,
1274 if (tween._startTime >= ignoreBeforeTime) {
1275 tween._startTime += amount;
1277 tween = tween._next;
1281 if (labels[p] >= ignoreBeforeTime) {
1282 labels[p] += amount;
1286 return this._uncache(true);
1289 p._kill = function(vars, target) {
1290 if (!vars && !target) {
1291 return this._enabled(false, false);
1293 var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
1297 if (tweens[i]._kill(vars, target)) {
1304 p.clear = function(labels) {
1305 var tweens = this.getChildren(false, true, true),
1307 this._time = this._totalTime = 0;
1309 tweens[i]._enabled(false, false);
1311 if (labels !== false) {
1314 return this._uncache(true);
1317 p.invalidate = function() {
1318 var tween = this._first;
1321 tween = tween._next;
1326 p._enabled = function(enabled, ignoreTimeline) {
1327 if (enabled === this._gc) {
1328 var tween = this._first;
1330 tween._enabled(enabled, true);
1331 tween = tween._next;
1334 return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
1337 p.duration = function(value) {
1338 if (!arguments.length) {
1340 this.totalDuration(); //just triggers recalculation
1342 return this._duration;
1344 if (this.duration() !== 0 && value !== 0) {
1345 this.timeScale(this._duration / value);
1350 p.totalDuration = function(value) {
1351 if (!arguments.length) {
1355 prevStart = 999999999999,
1358 prev = tween._prev; //record it here in case the tween changes position in the sequence...
1360 tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
1362 if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
1363 this.add(tween, tween._startTime - tween._delay);
1365 prevStart = tween._startTime;
1367 if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
1368 max -= tween._startTime;
1369 if (this._timeline.smoothChildTiming) {
1370 this._startTime += tween._startTime / this._timeScale;
1372 this.shiftChildren(-tween._startTime, false, -9999999999);
1375 end = tween._startTime + (tween._totalDuration / tween._timeScale);
1381 this._duration = this._totalDuration = max;
1382 this._dirty = false;
1384 return this._totalDuration;
1386 if (this.totalDuration() !== 0) if (value !== 0) {
1387 this.timeScale(this._totalDuration / value);
1392 p.usesFrames = function() {
1393 var tl = this._timeline;
1394 while (tl._timeline) {
1397 return (tl === Animation._rootFramesTimeline);
1400 p.rawTime = function() {
1401 return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
1404 return TimelineLite;
1421 * ----------------------------------------------------------------
1423 * ----------------------------------------------------------------
1425 window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
1427 var TimelineMax = function(vars) {
1428 TimelineLite.call(this, vars);
1429 this._repeat = this.vars.repeat || 0;
1430 this._repeatDelay = this.vars.repeatDelay || 0;
1432 this._yoyo = (this.vars.yoyo === true);
1435 _tinyNum = 0.0000000001,
1437 _easeNone = new Ease(null, null, 1, 0),
1438 p = TimelineMax.prototype = new TimelineLite();
1440 p.constructor = TimelineMax;
1441 p.kill()._gc = false;
1442 TimelineMax.version = "1.12.1";
1444 p.invalidate = function() {
1445 this._yoyo = (this.vars.yoyo === true);
1446 this._repeat = this.vars.repeat || 0;
1447 this._repeatDelay = this.vars.repeatDelay || 0;
1448 this._uncache(true);
1449 return TimelineLite.prototype.invalidate.call(this);
1452 p.addCallback = function(callback, position, params, scope) {
1453 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
1456 p.removeCallback = function(callback, position) {
1458 if (position == null) {
1459 this._kill(null, callback);
1461 var a = this.getTweensOf(callback, false),
1463 time = this._parseTimeOrLabel(position);
1465 if (a[i]._startTime === time) {
1466 a[i]._enabled(false, false);
1474 p.tweenTo = function(position, vars) {
1476 var copy = {ease:_easeNone, overwrite:(vars.delay ? 2 : 1), useFrames:this.usesFrames(), immediateRender:false},//note: set overwrite to 1 (true/all) by default unless there's a delay so that we avoid a racing situation that could happen if, for example, an onmousemove creates the same tweenTo() over and over again.
1481 copy.time = this._parseTimeOrLabel(position);
1482 duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
1483 t = new TweenLite(this, duration, copy);
1484 copy.onStart = function() {
1485 t.target.paused(true);
1486 if (t.vars.time !== t.target.time() && duration === t.duration()) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all.
1487 t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
1489 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
1490 vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
1496 p.tweenFromTo = function(fromPosition, toPosition, vars) {
1498 fromPosition = this._parseTimeOrLabel(fromPosition);
1499 vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
1500 vars.immediateRender = (vars.immediateRender !== false);
1501 var t = this.tweenTo(toPosition, vars);
1502 return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
1505 p.render = function(time, suppressEvents, force) {
1507 this._enabled(true, false);
1509 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
1510 dur = this._duration,
1511 prevTime = this._time,
1512 prevTotalTime = this._totalTime,
1513 prevStart = this._startTime,
1514 prevTimeScale = this._timeScale,
1515 prevRawPrevTime = this._rawPrevTime,
1516 prevPaused = this._paused,
1517 prevCycle = this._cycle,
1518 tween, isComplete, next, callback, internalForce, cycleDuration;
1519 if (time >= totalDur) {
1520 if (!this._locked) {
1521 this._totalTime = totalDur;
1522 this._cycle = this._repeat;
1524 if (!this._reversed) if (!this._hasPausedChild()) {
1526 callback = "onComplete";
1527 if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
1528 internalForce = true;
1529 if (prevRawPrevTime > _tinyNum) {
1530 callback = "onReverseComplete";
1534 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
1535 if (this._yoyo && (this._cycle & 1) !== 0) {
1536 this._time = time = 0;
1539 time = dur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. We cannot do less then 0.0001 because the same issue can occur when the duration is extremely large like 999999999999 in which case adding 0.00000001, for example, causes it to act like nothing was added.
1542 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
1543 if (!this._locked) {
1544 this._totalTime = this._cycle = 0;
1547 if (prevTime !== 0 || (dur === 0 && prevRawPrevTime !== _tinyNum && (prevRawPrevTime > 0 || (time < 0 && prevRawPrevTime >= 0)) && !this._locked)) { //edge case for checking time < 0 && prevRawPrevTime >= 0: a zero-duration fromTo() tween inside a zero-duration timeline (yeah, very rare)
1548 callback = "onReverseComplete";
1549 isComplete = this._reversed;
1552 this._active = false;
1553 if (dur === 0) if (prevRawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
1554 internalForce = true;
1556 this._rawPrevTime = time;
1558 this._rawPrevTime = (dur || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
1559 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
1560 if (!this._initted) {
1561 internalForce = true;
1566 if (dur === 0 && prevRawPrevTime < 0) { //without this, zero-duration repeating timelines (like with a simple callback nested at the very beginning and a repeatDelay) wouldn't render the first time through.
1567 internalForce = true;
1569 this._time = this._rawPrevTime = time;
1570 if (!this._locked) {
1571 this._totalTime = time;
1572 if (this._repeat !== 0) {
1573 cycleDuration = dur + this._repeatDelay;
1574 this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!)
1575 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
1576 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
1578 this._time = this._totalTime - (this._cycle * cycleDuration);
1579 if (this._yoyo) if ((this._cycle & 1) !== 0) {
1580 this._time = dur - this._time;
1582 if (this._time > dur) {
1584 time = dur + 0.0001; //to avoid occasional floating point rounding error
1585 } else if (this._time < 0) {
1586 this._time = time = 0;
1594 if (this._cycle !== prevCycle) if (!this._locked) {
1596 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
1597 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
1598 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
1599 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
1600 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
1601 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
1603 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
1604 wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
1605 recTotalTime = this._totalTime,
1606 recCycle = this._cycle,
1607 recRawPrevTime = this._rawPrevTime,
1608 recTime = this._time;
1610 this._totalTime = prevCycle * dur;
1611 if (this._cycle < prevCycle) {
1612 backwards = !backwards;
1614 this._totalTime += dur;
1616 this._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method.
1618 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
1619 this._cycle = prevCycle;
1620 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
1621 prevTime = (backwards) ? 0 : dur;
1622 this.render(prevTime, suppressEvents, (dur === 0));
1623 if (!suppressEvents) if (!this._gc) {
1624 if (this.vars.onRepeat) {
1625 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
1629 prevTime = (backwards) ? dur + 0.0001 : -0.0001;
1630 this.render(prevTime, true, false);
1632 this._locked = false;
1633 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
1636 this._time = recTime;
1637 this._totalTime = recTotalTime;
1638 this._cycle = recCycle;
1639 this._rawPrevTime = recRawPrevTime;
1642 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
1643 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
1644 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1647 } else if (!this._initted) {
1648 this._initted = true;
1651 if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
1652 this._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example.
1655 if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
1656 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1659 if (this._time >= prevTime) {
1660 tween = this._first;
1662 next = tween._next; //record it here because the value could change after rendering...
1663 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1665 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
1666 if (!tween._reversed) {
1667 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1669 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1678 next = tween._prev; //record it here because the value could change after rendering...
1679 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1681 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
1682 if (!tween._reversed) {
1683 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1685 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1692 if (this._onUpdate) if (!suppressEvents) {
1693 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1695 if (callback) if (!this._locked) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
1697 if (this._timeline.autoRemoveChildren) {
1698 this._enabled(false, false);
1700 this._active = false;
1702 if (!suppressEvents && this.vars[callback]) {
1703 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1708 p.getActive = function(nested, tweens, timelines) {
1709 if (nested == null) {
1712 if (tweens == null) {
1715 if (timelines == null) {
1719 all = this.getChildren(nested, tweens, timelines),
1723 for (i = 0; i < l; i++) {
1725 if (tween.isActive()) {
1733 p.getLabelAfter = function(time) {
1734 if (!time) if (time !== 0) { //faster than isNan()
1737 var labels = this.getLabelsArray(),
1740 for (i = 0; i < l; i++) {
1741 if (labels[i].time > time) {
1742 return labels[i].name;
1748 p.getLabelBefore = function(time) {
1752 var labels = this.getLabelsArray(),
1755 if (labels[i].time < time) {
1756 return labels[i].name;
1762 p.getLabelsArray = function() {
1766 for (p in this._labels) {
1767 a[cnt++] = {time:this._labels[p], name:p};
1769 a.sort(function(a,b) {
1770 return a.time - b.time;
1776 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
1778 p.progress = function(value) {
1779 return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
1782 p.totalProgress = function(value) {
1783 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
1786 p.totalDuration = function(value) {
1787 if (!arguments.length) {
1789 TimelineLite.prototype.totalDuration.call(this); //just forces refresh
1790 //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
1791 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
1793 return this._totalDuration;
1795 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
1798 p.time = function(value, suppressEvents) {
1799 if (!arguments.length) {
1803 this.totalDuration();
1805 if (value > this._duration) {
1806 value = this._duration;
1808 if (this._yoyo && (this._cycle & 1) !== 0) {
1809 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
1810 } else if (this._repeat !== 0) {
1811 value += this._cycle * (this._duration + this._repeatDelay);
1813 return this.totalTime(value, suppressEvents);
1816 p.repeat = function(value) {
1817 if (!arguments.length) {
1818 return this._repeat;
1820 this._repeat = value;
1821 return this._uncache(true);
1824 p.repeatDelay = function(value) {
1825 if (!arguments.length) {
1826 return this._repeatDelay;
1828 this._repeatDelay = value;
1829 return this._uncache(true);
1832 p.yoyo = function(value) {
1833 if (!arguments.length) {
1840 p.currentLabel = function(value) {
1841 if (!arguments.length) {
1842 return this.getLabelBefore(this._time + 0.00000001);
1844 return this.seek(value, true);
1863 * ----------------------------------------------------------------
1865 * ----------------------------------------------------------------
1869 var _RAD2DEG = 180 / Math.PI,
1874 Segment = function(a, b, c, d) {
1883 _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
1884 cubicToQuadratic = function(a, b, c, d) {
1892 mabc = (mab + mbc) / 2,
1893 mbcd = (mbc + mcd) / 2,
1894 m8 = (mbcd - mabc) / 8;
1895 q1.b = mab + (a - mab) / 4;
1897 q1.c = q2.a = (q1.b + q2.b) / 2;
1898 q2.c = q3.a = (mabc + mbcd) / 2;
1900 q4.b = mcd + (d - mcd) / 4;
1901 q3.c = q4.a = (q3.b + q4.b) / 2;
1902 return [q1, q2, q3, q4];
1904 _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
1905 var l = a.length - 1,
1908 i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
1909 for (i = 0; i < l; i++) {
1918 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
1919 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
1920 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
1921 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
1923 m1 = p2 - (p2 - p1) * curviness * 0.5;
1924 m2 = p2 + (p3 - p2) * curviness * 0.5;
1925 mm = p2 - (m1 + m2) / 2;
1934 seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly.
1942 qb = cubicToQuadratic(p1, cp1, cp2, p2);
1943 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
1953 seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly.
1954 seg.da = seg.d - seg.a;
1955 seg.ca = seg.c - seg.a;
1956 seg.ba = cp1 - seg.a;
1958 qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
1959 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
1962 _parseAnchors = function(values, p, correlate, prepend) {
1964 l, i, p1, p2, p3, tmp;
1966 values = [prepend].concat(values);
1969 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
1970 values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons
1974 l = values.length - 2;
1976 a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
1979 for (i = 0; i < l; i++) {
1981 p2 = values[i+1][p];
1982 a[i] = new Segment(p1, 0, 0, p2);
1984 p3 = values[i+2][p];
1985 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
1986 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
1989 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
1992 bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
1995 first = prepend || values[0],
1996 i, p, a, j, r, l, seamless, last;
1997 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
1998 if (curviness == null) {
2001 for (p in values[0]) {
2004 //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later)
2005 if (values.length > 1) {
2006 last = values[values.length - 1];
2011 if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9
2017 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
2019 values.unshift(prepend);
2021 values.push(values[1]);
2022 prepend = values[values.length - 3];
2025 _r1.length = _r2.length = _r3.length = 0;
2029 _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
2030 obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
2034 _r1[i] = Math.sqrt(_r1[i]);
2035 _r2[i] = Math.sqrt(_r2[i]);
2043 for (j = 0; j < l; j++) {
2044 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
2045 _r3[j] = (_r3[j] || 0) + r * r;
2051 _r3[i] = Math.sqrt(_r3[i]);
2055 j = quadratic ? 4 : 1;
2059 _calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties
2062 a.splice(a.length - j, j);
2067 _parseBezierData = function(values, type, prepend) {
2068 type = type || "soft";
2070 inc = (type === "cubic") ? 3 : 2,
2071 soft = (type === "soft"),
2073 a, b, c, d, cur, i, j, l, p, cnt, tmp;
2074 if (soft && prepend) {
2075 values = [prepend].concat(values);
2077 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
2078 for (p in values[0]) {
2087 for (j = 0; j < l; j++) {
2088 a = (prepend == null) ? values[j][p] : (typeof( (tmp = values[j][p]) ) === "string" && tmp.charAt(1) === "=") ? prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)) : Number(tmp);
2089 if (soft) if (j > 1) if (j < l - 1) {
2090 cur[cnt++] = (a + cur[cnt-2]) / 2;
2096 for (j = 0; j < l; j += inc) {
2100 d = (inc === 2) ? 0 : cur[j+3];
2101 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2107 _addCubicLengths = function(a, steps, resolution) {
2108 var inc = 1 / resolution,
2110 d, d1, s, da, ca, ba, p, i, inv, bez, index;
2118 for (i = 1; i <= resolution; i++) {
2121 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
2122 index = j * resolution + i - 1;
2123 steps[index] = (steps[index] || 0) + d * d;
2127 _parseLengthData = function(obj, resolution) {
2128 resolution = resolution >> 0 || 6;
2133 threshold = resolution - 1,
2135 curLS = [], //current length segments array
2138 _addCubicLengths(obj[p], a, resolution);
2141 for (i = 0; i < l; i++) {
2142 d += Math.sqrt(a[i]);
2143 index = i % resolution;
2145 if (index === threshold) {
2147 index = (i / resolution) >> 0;
2148 segments[index] = curLS;
2149 lengths[index] = total;
2154 return {length:total, lengths:lengths, segments:segments};
2159 BezierPlugin = window._gsDefine.plugin({
2166 //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
2167 init: function(target, vars, tween) {
2168 this._target = target;
2169 if (vars instanceof Array) {
2170 vars = {values:vars};
2175 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
2176 var values = vars.values || [],
2179 autoRotate = vars.autoRotate || tween.vars.orientToBezier,
2180 p, isFunc, i, j, prepend;
2182 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
2184 this._props.push(p);
2187 i = this._props.length;
2191 this._overwriteProps.push(p);
2192 isFunc = this._func[p] = (typeof(target[p]) === "function");
2193 first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
2194 if (!prepend) if (first[p] !== values[0][p]) {
2198 this._beziers = (vars.type !== "cubic" && vars.type !== "quadratic" && vars.type !== "soft") ? bezierThrough(values, isNaN(vars.curviness) ? 1 : vars.curviness, false, (vars.type === "thruBasic"), vars.correlate, prepend) : _parseBezierData(values, vars.type, first);
2199 this._segCount = this._beziers[p].length;
2201 if (this._timeRes) {
2202 var ld = _parseLengthData(this._beziers, this._timeRes);
2203 this._length = ld.length;
2204 this._lengths = ld.lengths;
2205 this._segments = ld.segments;
2206 this._l1 = this._li = this._s1 = this._si = 0;
2207 this._l2 = this._lengths[0];
2208 this._curSeg = this._segments[0];
2209 this._s2 = this._curSeg[0];
2210 this._prec = 1 / this._curSeg.length;
2213 if ((autoRotate = this._autoRotate)) {
2214 this._initialRotations = [];
2215 if (!(autoRotate[0] instanceof Array)) {
2216 this._autoRotate = autoRotate = [autoRotate];
2218 i = autoRotate.length;
2220 for (j = 0; j < 3; j++) {
2221 p = autoRotate[i][j];
2222 this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
2224 p = autoRotate[i][2];
2225 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
2228 this._startRatio = tween.vars.runBackwards ? 1 : 0; //we determine the starting ratio when the tween inits which is always 0 unless the tween has runBackwards:true (indicating it's a from() tween) in which case it's 1.
2232 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
2234 var segments = this._segCount,
2236 target = this._target,
2237 notStart = (v !== this._startRatio),
2238 curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
2239 if (!this._timeRes) {
2240 curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
2241 t = (v - (curIndex * (1 / segments))) * segments;
2243 lengths = this._lengths;
2244 curSeg = this._curSeg;
2247 //find the appropriate segment (if the currently cached one isn't correct)
2248 if (v > this._l2 && i < segments - 1) {
2250 while (i < l && (this._l2 = lengths[++i]) <= v) { }
2251 this._l1 = lengths[i-1];
2253 this._curSeg = curSeg = this._segments[i];
2254 this._s2 = curSeg[(this._s1 = this._si = 0)];
2255 } else if (v < this._l1 && i > 0) {
2256 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
2257 if (i === 0 && v < this._l1) {
2262 this._l2 = lengths[i];
2264 this._curSeg = curSeg = this._segments[i];
2265 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
2266 this._s2 = curSeg[this._si];
2269 //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
2272 if (v > this._s2 && i < curSeg.length - 1) {
2273 l = curSeg.length - 1;
2274 while (i < l && (this._s2 = curSeg[++i]) <= v) { }
2275 this._s1 = curSeg[i-1];
2277 } else if (v < this._s1 && i > 0) {
2278 while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
2279 if (i === 0 && v < this._s1) {
2284 this._s2 = curSeg[i];
2287 t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
2291 i = this._props.length;
2294 b = this._beziers[p][curIndex];
2295 val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
2296 if (this._round[p]) {
2297 val = Math.round(val);
2306 if (this._autoRotate) {
2307 var ar = this._autoRotate,
2308 b2, x1, y1, x2, y2, add, conv;
2312 add = ar[i][3] || 0;
2313 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
2314 b = this._beziers[ar[i][0]];
2315 b2 = this._beziers[ar[i][1]];
2317 if (b && b2) { //in case one of the properties got overwritten.
2321 x1 = b.a + (b.b - b.a) * t;
2322 x2 = b.b + (b.c - b.b) * t;
2323 x1 += (x2 - x1) * t;
2324 x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
2326 y1 = b2.a + (b2.b - b2.a) * t;
2327 y2 = b2.b + (b2.c - b2.b) * t;
2328 y1 += (y2 - y1) * t;
2329 y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
2331 val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
2343 p = BezierPlugin.prototype;
2346 BezierPlugin.bezierThrough = bezierThrough;
2347 BezierPlugin.cubicToQuadratic = cubicToQuadratic;
2348 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
2349 BezierPlugin.quadraticToCubic = function(a, b, c) {
2350 return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2353 BezierPlugin._cssRegister = function() {
2354 var CSSPlugin = window._gsDefine.globals.CSSPlugin;
2358 var _internals = CSSPlugin._internals,
2359 _parseToProxy = _internals._parseToProxy,
2360 _setPluginRatio = _internals._setPluginRatio,
2361 CSSPropTween = _internals.CSSPropTween;
2362 _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
2363 if (e instanceof Array) {
2366 plugin = new BezierPlugin();
2367 var values = e.values,
2368 l = values.length - 1,
2375 for (i = 0; i <= l; i++) {
2376 data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
2377 pluginValues[i] = data.end;
2380 v[p] = e[p]; //duplicate the vars object because we need to alter some things which would cause problems if the user plans to reuse the same vars object for another tween.
2382 v.values = pluginValues;
2383 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
2386 pt.setRatio = _setPluginRatio;
2387 if (v.autoRotate === 0) {
2388 v.autoRotate = true;
2390 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
2391 i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
2392 v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
2395 if (!cssp._transform) {
2396 cssp._enableTransforms(false);
2398 data.autoRotate = cssp._target._gsTransform;
2400 plugin._onInitTween(data.proxy, v, cssp._tween);
2405 p._roundProps = function(lookup, value) {
2406 var op = this._overwriteProps,
2409 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
2410 this._round[op[i]] = value;
2415 p._kill = function(lookup) {
2416 var a = this._props,
2418 for (p in this._beziers) {
2420 delete this._beziers[p];
2421 delete this._func[p];
2430 return this._super._kill.call(this, lookup);
2449 * ----------------------------------------------------------------
2451 * ----------------------------------------------------------------
2453 window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
2455 /** @constructor **/
2456 var CSSPlugin = function() {
2457 TweenPlugin.call(this, "css");
2458 this._overwriteProps.length = 0;
2459 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
2461 _hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called.
2462 _suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance
2463 _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
2464 _overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification.
2466 p = CSSPlugin.prototype = new TweenPlugin("css");
2468 p.constructor = CSSPlugin;
2469 CSSPlugin.version = "1.12.1";
2471 CSSPlugin.defaultTransformPerspective = 0;
2472 CSSPlugin.defaultSkewType = "compensated";
2473 p = "px"; //we'll reuse the "p" variable to keep file size down
2474 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
2477 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
2478 _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
2479 _valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
2480 _NaNExp = /[^\d\-\.]/g,
2481 _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
2482 _opacityExp = /opacity *= *([^)]*)/i,
2483 _opacityValExp = /opacity:([^;]*)/i,
2484 _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
2485 _rgbhslExp = /^(rgb|hsl)/,
2486 _capsExp = /([A-Z])/g,
2487 _camelExp = /-([a-z])/gi,
2488 _urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage)
2489 _camelFunc = function(s, g) { return g.toUpperCase(); },
2490 _horizExp = /(?:Left|Right|Width)/i,
2491 _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
2492 _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
2493 _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
2494 _DEG2RAD = Math.PI / 180,
2495 _RAD2DEG = 180 / Math.PI,
2498 _tempDiv = _doc.createElement("div"),
2499 _tempImg = _doc.createElement("img"),
2500 _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
2501 _agent = navigator.userAgent,
2503 _reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance).
2506 _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
2507 _isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!)
2509 _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
2510 var i = _agent.indexOf("Android"),
2511 d = _doc.createElement("div"), a;
2513 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
2514 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
2515 _isFirefox = (_agent.indexOf("Firefox") !== -1);
2517 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
2518 _ieVers = parseFloat( RegExp.$1 );
2521 d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>";
2522 a = d.getElementsByTagName("a")[0];
2523 return a ? /^0.55/.test(a.style.opacity) : false;
2525 _getIEOpacity = function(v) {
2526 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
2528 _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
2529 if (window.console) {
2533 _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
2534 _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
2536 // @private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all)
2537 _checkPropPrefix = function(p, e) {
2541 if (s[p] !== undefined) {
2544 p = p.charAt(0).toUpperCase() + p.substr(1);
2545 a = ["O","Moz","ms","Ms","Webkit"];
2547 while (--i > -1 && s[a[i]+p] === undefined) { }
2549 _prefix = (i === 3) ? "ms" : a[i];
2550 _prefixCSS = "-" + _prefix.toLowerCase() + "-";
2556 _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
2559 * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do:
2560 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
2562 * @param {!Object} t Target element whose style property you want to query
2563 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
2564 * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call.
2565 * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value.
2566 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
2567 * @return {?string} The current property value
2569 _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
2571 if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here.
2572 return _getIEOpacity(t);
2574 if (!calc && t.style[p]) {
2576 } else if ((cs = cs || _getComputedStyle(t))) {
2577 rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
2578 } else if (t.currentStyle) {
2579 rv = t.currentStyle[p];
2581 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
2585 * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number.
2586 * @param {!Object} t Target element
2587 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
2588 * @param {!number} v Value
2589 * @param {string=} sfx Suffix (like "px" or "%" or "em")
2590 * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect.
2591 * @return {number} value in pixels
2593 _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
2594 if (sfx === "px" || !sfx) { return v; }
2595 if (sfx === "auto" || !v) { return 0; }
2596 var horiz = _horizExp.test(p),
2598 style = _tempDiv.style,
2604 if (sfx === "%" && p.indexOf("border") !== -1) {
2605 pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
2607 style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
2608 if (sfx === "%" || !node.appendChild) {
2609 node = t.parentNode || _doc.body;
2610 cache = node._gsCache;
2611 time = TweenLite.ticker.frame;
2612 if (cache && horiz && cache.time === time) { //performance optimization: we record the width of elements along with the ticker frame so that we can quickly get it again on the same tick (seems relatively safe to assume it wouldn't change on the same tick)
2613 return cache.width * v / 100;
2615 style[(horiz ? "width" : "height")] = v + sfx;
2617 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
2619 node.appendChild(_tempDiv);
2620 pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
2621 node.removeChild(_tempDiv);
2622 if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
2623 cache = node._gsCache = node._gsCache || {};
2625 cache.width = pix / v * 100;
2627 if (pix === 0 && !recurse) {
2628 pix = _convertToPixels(t, p, v, sfx, true);
2631 return neg ? -pix : pix;
2633 _calculateOffset = _internals.calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop
2634 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
2635 var dim = ((p === "left") ? "Left" : "Top"),
2636 v = _getStyle(t, "margin" + dim, cs);
2637 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
2640 // @private returns at object containing ALL of the style properties in camelCase and their associated values.
2641 _getAllStyles = function(t, cs) {
2644 if ((cs = cs || _getComputedStyle(t, null))) {
2645 if ((i = cs.length)) {
2647 s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
2649 } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
2654 } else if ((cs = t.currentStyle || t.style)) {
2656 if (typeof(i) === "string" && s[i] === undefined) {
2657 s[i.replace(_camelExp, _camelFunc)] = cs[i];
2661 if (!_supportsOpacity) {
2662 s.opacity = _getIEOpacity(t);
2664 tr = _getTransform(t, cs, false);
2665 s.rotation = tr.rotation;
2667 s.scaleX = tr.scaleX;
2668 s.scaleY = tr.scaleY;
2673 s.rotationX = tr.rotationX;
2674 s.rotationY = tr.rotationY;
2675 s.scaleZ = tr.scaleZ;
2683 // @private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object containing only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details.
2684 _cssDif = function(t, s1, s2, vars, forceLookup) {
2689 if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") {
2690 difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween.
2691 if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes.
2692 mpt = new MiniPropTween(style, p, style[p], mpt);
2697 for (p in vars) { //copy properties (except className)
2698 if (p !== "className") {
2703 return {difs:difs, firstMPT:mpt};
2705 _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
2706 _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
2709 * @private Gets the width or height of an element
2710 * @param {!Object} t Target element
2711 * @param {!string} p Property name ("width" or "height")
2712 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
2713 * @return {number} Dimension (in pixels)
2715 _getDimension = function(t, p, cs) {
2716 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
2719 cs = cs || _getComputedStyle(t, null);
2721 v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
2722 v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
2727 // @private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value)
2728 _parsePosition = function(v, recObj) {
2729 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
2732 var a = v.split(" "),
2733 x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
2734 y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
2737 } else if (y === "center") {
2740 if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
2744 recObj.oxp = (x.indexOf("%") !== -1);
2745 recObj.oyp = (y.indexOf("%") !== -1);
2746 recObj.oxr = (x.charAt(1) === "=");
2747 recObj.oyr = (y.charAt(1) === "=");
2748 recObj.ox = parseFloat(x.replace(_NaNExp, ""));
2749 recObj.oy = parseFloat(y.replace(_NaNExp, ""));
2751 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
2755 * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!)
2756 * @param {(number|string)} e End value which is typically a string, but could be a number
2757 * @param {(number|string)} b Beginning value which is typically a string but could be a number
2758 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
2760 _parseChange = function(e, b) {
2761 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
2765 * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
2766 * @param {Object} v Value to be parsed
2767 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
2768 * @return {number} Parsed value
2770 _parseVal = function(v, d) {
2771 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
2775 * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly.
2776 * @param {Object} v Value to be parsed
2777 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
2778 * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY"
2779 * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation.
2780 * @return {number} parsed angle in radians
2782 _parseAngle = function(v, d, p, directionalEnd) {
2784 cap, split, dif, result;
2787 } else if (typeof(v) === "number") {
2791 split = v.split("_");
2792 dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
2794 if (directionalEnd) {
2795 directionalEnd[p] = d + dif;
2797 if (v.indexOf("short") !== -1) {
2799 if (dif !== dif % (cap / 2)) {
2800 dif = (dif < 0) ? dif + cap : dif - cap;
2803 if (v.indexOf("_cw") !== -1 && dif < 0) {
2804 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
2805 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
2806 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
2811 if (result < min && result > -min) {
2817 _colorLookup = {aqua:[0,255,255],
2819 silver:[192,192,192],
2825 white:[255,255,255],
2826 fuchsia:[255,0,255],
2836 transparent:[255,255,255,0]},
2838 _hue = function(h, m1, m2) {
2839 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
2840 return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
2844 * @private Parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course)
2845 * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc.
2846 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
2848 _parseColor = function(v) {
2849 var c1, c2, c3, h, s, l;
2850 if (!v || v === "") {
2851 return _colorLookup.black;
2853 if (typeof(v) === "number") {
2854 return [v >> 16, (v >> 8) & 255, v & 255];
2856 if (v.charAt(v.length - 1) === ",") { //sometimes a trailing commma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.
2857 v = v.substr(0, v.length - 1);
2859 if (_colorLookup[v]) {
2860 return _colorLookup[v];
2862 if (v.charAt(0) === "#") {
2863 if (v.length === 4) { //for shorthand like #9F0
2867 v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
2869 v = parseInt(v.substr(1), 16);
2870 return [v >> 16, (v >> 8) & 255, v & 255];
2872 if (v.substr(0, 3) === "hsl") {
2873 v = v.match(_numExp);
2874 h = (Number(v[0]) % 360) / 360;
2875 s = Number(v[1]) / 100;
2876 l = Number(v[2]) / 100;
2877 c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
2880 v[3] = Number(v[3]);
2882 v[0] = _hue(h + 1 / 3, c1, c2);
2883 v[1] = _hue(h, c1, c2);
2884 v[2] = _hue(h - 1 / 3, c1, c2);
2887 v = v.match(_numExp) || _colorLookup.transparent;
2888 v[0] = Number(v[0]);
2889 v[1] = Number(v[1]);
2890 v[2] = Number(v[2]);
2892 v[3] = Number(v[3]);
2896 _colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.
2898 for (p in _colorLookup) {
2899 _colorExp += "|" + p + "\\b";
2901 _colorExp = new RegExp(_colorExp+")", "gi");
2904 * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned.
2905 * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned.
2906 * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't.
2907 * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc.
2908 * @return {Function} formatter function
2910 var _getFormatter = function(dflt, clr, collapsible, multi) {
2912 return function(v) {return v;};
2914 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
2915 dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
2916 pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
2917 sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
2918 delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
2919 numVals = dVals.length,
2920 dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
2923 return function(v) {return v;};
2926 formatter = function(v) {
2927 var color, vals, i, a;
2928 if (typeof(v) === "number") {
2930 } else if (multi && _commasOutsideParenExp.test(v)) {
2931 a = v.replace(_commasOutsideParenExp, "|").split("|");
2932 for (i = 0; i < a.length; i++) {
2933 a[i] = formatter(a[i]);
2937 color = (v.match(_colorExp) || [dColor])[0];
2938 vals = v.split(color).join("").match(_valuesExp) || [];
2940 if (numVals > i--) {
2941 while (++i < numVals) {
2942 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
2945 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
2950 formatter = function(v) {
2952 if (typeof(v) === "number") {
2954 } else if (multi && _commasOutsideParenExp.test(v)) {
2955 a = v.replace(_commasOutsideParenExp, "|").split("|");
2956 for (i = 0; i < a.length; i++) {
2957 a[i] = formatter(a[i]);
2961 vals = v.match(_valuesExp) || [];
2963 if (numVals > i--) {
2964 while (++i < numVals) {
2965 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
2968 return pfx + vals.join(delim) + sfx;
2974 * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges.
2975 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
2976 * @return {Function} a formatter function
2978 _getEdgeParser = function(props) {
2979 props = props.split(",");
2980 return function(t, e, p, cssp, pt, plugin, vars) {
2981 var a = (e + "").split(" "),
2984 for (i = 0; i < 4; i++) {
2985 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
2987 return cssp.parse(t, vars, pt, plugin);
2991 // @private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color.
2992 _setPluginRatio = _internals._setPluginRatio = function(v) {
2993 this.plugin.setRatio(v);
3002 val = Math.round(val);
3003 } else if (val < min && val > -min) {
3010 d.autoRotate.rotation = proxy.rotation;
3012 //at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method.
3018 pt.e = pt.s + pt.xs0;
3019 } else if (pt.type === 1) {
3020 str = pt.xs0 + pt.s + pt.xs1;
3021 for (i = 1; i < pt.l; i++) {
3022 str += pt["xn"+i] + pt["xs"+(i+1)];
3032 * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value.
3033 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
3034 * @param {!string} p property name
3035 * @param {(number|string|object)} v value
3036 * @param {MiniPropTween=} next next MiniPropTween in the linked list
3037 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
3039 MiniPropTween = function(t, p, v, next, r) {
3051 * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be rounded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element.
3052 * This method returns an object that has the following properties:
3053 * - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin. This is what we feed to the external _onInitTween() as the target
3054 * - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values
3055 * - firstMPT: the first MiniPropTween in the linked list
3056 * - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter.
3057 * @param {!Object} t target object to be tweened
3058 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
3059 * @param {!CSSPlugin} cssp The CSSPlugin instance
3060 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
3061 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
3062 * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter.
3063 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
3065 _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
3069 transform = cssp._transform,
3070 oldForce = _forcePT,
3071 i, p, xp, mpt, firstPT;
3072 cssp._transform = null;
3074 pt = firstPT = cssp.parse(t, vars, pt, plugin);
3075 _forcePT = oldForce;
3076 //break off from the linked list so the new ones are isolated.
3078 cssp._transform = transform;
3082 bpt._prev._next = null;
3086 while (pt && pt !== bpt) {
3089 end[p] = pt.s + pt.c;
3092 mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
3095 if (pt.type === 1) {
3099 p = pt.p + "_" + xp;
3100 end[p] = pt.data[xp];
3103 mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
3110 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
3116 * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory.
3117 * CSSPropTweens have the following optional properties as well (not defined through the constructor):
3118 * - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc.
3119 * - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list)
3120 * - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subtweens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request.
3121 * - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target.
3122 * - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible.
3123 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
3124 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
3125 * @param {number} s Starting numeric value
3126 * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95.
3127 * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it.
3128 * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update.
3129 * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip"
3130 * @param {boolean=} r If true, the value(s) should be rounded
3131 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
3132 * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues.
3133 * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues.
3135 CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
3136 this.t = t; //target
3137 this.p = p; //property
3138 this.s = s; //starting value
3139 this.c = c; //change value
3140 this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at)
3141 if (!(t instanceof CSSPropTween)) {
3142 _overwriteProps.push(this.n);
3144 this.r = r; //round (boolean)
3145 this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work
3148 _hasPriority = true;
3150 this.b = (b === undefined) ? s : b;
3151 this.e = (e === undefined) ? s + c : e;
3159 * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
3160 * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
3161 * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio().
3162 * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method.
3164 * @param {!Object} t Target whose property will be tweened
3165 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
3166 * @param {string} b Beginning value
3167 * @param {string} e Ending value
3168 * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization)
3169 * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match
3170 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
3171 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
3172 * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300}
3173 * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here.
3174 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
3176 _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
3177 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
3178 b = b || dflt || "";
3179 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
3180 e += ""; //ensures it's a string
3181 var ba = b.split(", ").join(",").split(" "), //beginning array
3182 ea = e.split(", ").join(",").split(" "), //ending array
3184 autoRound = (_autoRound !== false),
3185 i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
3186 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
3187 ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3188 ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3191 if (l !== ea.length) {
3192 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3193 ba = (dflt || "").split(" ");
3197 pt.setRatio = setRatio;
3198 for (i = 0; i < l; i++) {
3201 bn = parseFloat(bv);
3203 //if the value begins with a number (most common). It's fine if it has a suffix like px
3204 if (bn || bn === 0) {
3205 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
3207 //if the value is a color
3208 } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
3209 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
3210 bv = _parseColor(bv);
3211 ev = _parseColor(ev);
3212 rgba = (bv.length + ev.length > 6);
3213 if (rgba && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color
3214 pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
3215 pt.e = pt.e.split(ea[i]).join("transparent");
3217 if (!_supportsOpacity) { //old versions of IE don't support rgba().
3220 pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
3221 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
3222 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
3224 bv = (bv.length < 4) ? 1 : bv[3];
3225 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
3230 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
3232 //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
3234 pt["xs" + pt.l] += pt.l ? " " + bv : bv;
3236 //loop through all the numbers that are found and construct the extra values on the pt.
3238 enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5
3239 if (!enums || enums.length !== bnums.length) {
3240 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3244 for (xi = 0; xi < bnums.length; xi++) {
3246 temp = bv.indexOf(cv, ni);
3247 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
3248 ni = temp + cv.length;
3250 pt["xs" + pt.l] += bv.substr(ni);
3254 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
3255 if (e.indexOf("=") !== -1) if (pt.data) {
3256 str = pt.xs0 + pt.data.s;
3257 for (i = 1; i < pt.l; i++) {
3258 str += pt["xs" + i] + pt.data["xn" + i];
3260 pt.e = str + pt["xs" + i];
3266 return pt.xfirst || pt;
3271 p = CSSPropTween.prototype;
3272 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
3278 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
3282 * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this:
3283 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
3284 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
3285 * @param {string=} pfx Prefix (if any)
3286 * @param {!number} s Starting value
3287 * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95.
3288 * @param {string=} sfx Suffix (if any)
3289 * @param {boolean=} r Round (if true).
3290 * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space.
3291 * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
3293 p.appendXtra = function(pfx, s, c, sfx, r, pad) {
3296 pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
3297 if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value!
3298 pt["xs" + l] += s + (sfx || "");
3302 pt.type = pt.setRatio ? 2 : 1;
3303 pt["xs" + pt.l] = sfx || "";
3305 pt.data["xn" + l] = s + c;
3306 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
3309 pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
3310 pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly.
3314 pt.data = {s:s + c};
3323 * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly.
3324 * @param {!string} p Property name (like "boxShadow" or "throwProps")
3325 * @param {Object=} options An object containing any of the following configuration options:
3326 * - defaultValue: the default value
3327 * - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker)
3328 * - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.)
3329 * - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
3330 * - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
3331 * - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
3332 * - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
3333 * - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc.
3334 * - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default).
3336 var SpecialProp = function(p, options) {
3337 options = options || {};
3338 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
3339 _specialProps[p] = _specialProps[this.p] = this;
3340 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
3341 if (options.parser) {
3342 this.parse = options.parser;
3344 this.clrs = options.color;
3345 this.multi = options.multi;
3346 this.keyword = options.keyword;
3347 this.dflt = options.defaultValue;
3348 this.pr = options.priority || 0;
3351 //shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin.
3352 _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
3353 if (typeof(options) !== "object") {
3354 options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
3356 var a = p.split(","),
3357 d = options.defaultValue,
3359 defaults = defaults || [d];
3360 for (i = 0; i < a.length; i++) {
3361 options.prefix = (i === 0 && options.prefix);
3362 options.defaultValue = defaults[i] || d;
3363 temp = new SpecialProp(a[i], options);
3367 //creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file.
3368 _registerPluginProp = function(p) {
3369 if (!_specialProps[p]) {
3370 var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
3371 _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
3372 var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
3374 _log("Error: " + pluginName + " js file not loaded.");
3377 pluginClass._cssRegister();
3378 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
3384 p = SpecialProp.prototype;
3387 * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxShadow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list)
3388 * @param {!Object} t target element
3389 * @param {(string|number|object)} b beginning value
3390 * @param {(string|number|object)} e ending (destination) value
3391 * @param {CSSPropTween=} pt next CSSPropTween in the linked list
3392 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
3393 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
3394 * @return {CSSPropTween=} First CSSPropTween in the linked list
3396 p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
3397 var kwd = this.keyword,
3398 i, ba, ea, l, bi, ei;
3399 //if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example)
3400 if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
3401 ba = b.replace(_commasOutsideParenExp, "|").split("|");
3402 ea = e.replace(_commasOutsideParenExp, "|").split("|");
3408 l = (ea.length > ba.length) ? ea.length : ba.length;
3409 for (i = 0; i < l; i++) {
3410 b = ba[i] = ba[i] || this.dflt;
3411 e = ea[i] = ea[i] || this.dflt;
3413 bi = b.indexOf(kwd);
3414 ei = e.indexOf(kwd);
3416 e = (ei === -1) ? ea : ba;
3424 return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
3428 * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call:
3429 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
3430 * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that).
3431 * @param {!Object} t Target object whose property is being tweened
3432 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
3433 * @param {!string} p Property name
3434 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
3435 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
3436 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
3437 * @param {Object=} vars Original vars object that contains the data for parsing.
3438 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
3440 p.parse = function(t, e, p, cssp, pt, plugin, vars) {
3441 return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
3445 * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters:
3446 * 1) Target object whose property should be tweened (typically a DOM element)
3447 * 2) The end/destination value (could be a string, number, object, or whatever you want)
3448 * 3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration)
3450 * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example:
3452 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
3453 * var start = target.style.width;
3454 * return function(ratio) {
3455 * target.style.width = (start + value * ratio) + "px";
3456 * console.log("set width to " + target.style.width);
3460 * Then, when I do this tween, it will trigger my special property:
3462 * TweenLite.to(element, 1, {css:{myCustomProp:100}});
3464 * In the example, of course, we're just changing the width, but you can do anything you want.
3466 * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}})
3467 * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function.
3468 * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones.
3470 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
3471 _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
3472 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
3474 rv.setRatio = onInitTween(t, e, cssp._tween, p);
3476 }, priority:priority});
3486 //transform-related methods and properties
3487 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
3488 _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
3489 _transformPropCSS = _prefixCSS + "transform",
3490 _transformOriginProp = _checkPropPrefix("transformOrigin"),
3491 _supports3D = (_checkPropPrefix("perspective") !== null),
3492 Transform = _internals.Transform = function() {
3497 * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
3498 * @param {!Object} t target element
3499 * @param {Object=} cs computed style object (optional)
3500 * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...}
3501 * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style)
3502 * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
3504 _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
3505 if (t._gsTransform && rec && !parse) {
3506 return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things.
3508 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
3509 invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
3513 minPI = minAngle * _DEG2RAD,
3514 zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0,
3515 s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
3516 if (_transformProp) {
3517 s = _getStyle(t, _transformPropCSS, cs, true);
3518 } else if (t.currentStyle) {
3519 //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
3520 s = t.currentStyle.filter.match(_ieGetMatrixExp);
3521 s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
3523 //split the matrix values out into an array (m for matrix)
3524 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
3528 m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
3530 if (m.length === 16) {
3532 //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
3533 var a13 = m[8], a23 = m[9], a33 = m[10],
3534 a14 = m[12], a24 = m[13], a34 = m[14];
3536 //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
3539 a14 = a13*a34-m[12];
3540 a24 = a23*a34-m[13];
3541 a34 = a33*a34+tm.zOrigin-m[14];
3544 //only parse from the matrix if we MUST because not only is it usually unnecessary due to the fact that we store the values in the _gsTransform object, but also because it's impossible to accurately interpret rotationX, rotationY, rotationZ, scaleX, and scaleY if all are applied, so it's much better to rely on what we store. However, we must parse the first time that an object is tweened. We also assume that if the position has changed, the user must have done some styling changes outside of CSSPlugin, thus we force a parse in that scenario.
3545 if (!rec || parse || tm.rotationX == null) {
3546 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
3547 a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
3549 angle = Math.atan2(a32, a33),
3550 xFlip = (angle < -minPI || angle > minPI),
3551 t1, t2, t3, cos, sin, yFlip, zFlip;
3552 tm.rotationX = angle * _RAD2DEG;
3555 cos = Math.cos(-angle);
3556 sin = Math.sin(-angle);
3557 t1 = a12*cos+a13*sin;
3558 t2 = a22*cos+a23*sin;
3559 t3 = a32*cos+a33*sin;
3560 a13 = a12*-sin+a13*cos;
3561 a23 = a22*-sin+a23*cos;
3562 a33 = a32*-sin+a33*cos;
3563 a43 = a42*-sin+a43*cos;
3569 angle = Math.atan2(a13, a11);
3570 tm.rotationY = angle * _RAD2DEG;
3572 yFlip = (angle < -minPI || angle > minPI);
3573 cos = Math.cos(-angle);
3574 sin = Math.sin(-angle);
3575 t1 = a11*cos-a13*sin;
3576 t2 = a21*cos-a23*sin;
3577 t3 = a31*cos-a33*sin;
3578 a23 = a21*sin+a23*cos;
3579 a33 = a31*sin+a33*cos;
3580 a43 = a41*sin+a43*cos;
3586 angle = Math.atan2(a21, a22);
3587 tm.rotation = angle * _RAD2DEG;
3589 zFlip = (angle < -minPI || angle > minPI);
3590 cos = Math.cos(-angle);
3591 sin = Math.sin(-angle);
3592 a11 = a11*cos+a12*sin;
3593 t2 = a21*cos+a22*sin;
3594 a22 = a21*-sin+a22*cos;
3595 a32 = a31*-sin+a32*cos;
3599 if (zFlip && xFlip) {
3600 tm.rotation = tm.rotationX = 0;
3601 } else if (zFlip && yFlip) {
3602 tm.rotation = tm.rotationY = 0;
3603 } else if (yFlip && xFlip) {
3604 tm.rotationY = tm.rotationX = 0;
3607 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
3608 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
3609 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
3611 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
3617 } else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those.
3618 var k = (m.length >= 6),
3625 scaleX = Math.sqrt(a * a + b * b);
3626 scaleY = Math.sqrt(d * d + c * c);
3627 rotation = (a || b) ? Math.atan2(b, a) * _RAD2DEG : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
3628 skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
3629 difX = scaleX - Math.abs(tm.scaleX || 0);
3630 difY = scaleY - Math.abs(tm.scaleY || 0);
3631 if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
3634 skewX += (rotation <= 0) ? 180 : -180;
3635 rotation += (rotation <= 0) ? 180 : -180;
3638 skewX += (skewX <= 0) ? 180 : -180;
3641 difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
3642 difS = (skewX - tm.skewX) % 180;
3643 //if there's already a recorded _gsTransform in place for the target, we should leave those values in place unless we know things changed for sure (beyond a super small amount). This gets around ambiguous interpretations, like if scaleX and scaleY are both -1, the matrix would be the same as if the rotation was 180 with normal scaleX/scaleY. If the user tweened to particular values, those must be prioritized to ensure animation is consistent.
3644 if (tm.skewX === undefined || difX > min || difX < -min || difY > min || difY < -min || (difR > -minAngle && difR < minAngle && (difR * rnd) | 0 !== 0) || (difS > -minAngle && difS < minAngle && (difS * rnd) | 0 !== 0)) {
3647 tm.rotation = rotation;
3651 tm.rotationX = tm.rotationY = tm.z = 0;
3652 tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
3656 tm.zOrigin = zOrigin;
3658 //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate.
3660 if (tm[i] < min) if (tm[i] > -min) {
3664 //DEBUG: _log("parsed rotation: "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective);
3666 t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
3671 //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
3672 _setIETransformRatio = function(v) {
3673 var t = this.data, //refers to the element's _gsTransform object
3674 ang = -t.rotation * _DEG2RAD,
3675 skew = ang + t.skewX * _DEG2RAD,
3677 a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
3678 b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
3679 c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
3680 d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
3681 style = this.t.style,
3682 cs = this.t.currentStyle,
3687 val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted)
3690 filters = cs.filter;
3691 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
3692 var w = this.t.offsetWidth,
3693 h = this.t.offsetHeight,
3694 clip = (cs.position !== "absolute"),
3695 m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
3700 //if transformOrigin is being used, adjust the offset x and y
3702 dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
3703 dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
3704 ox += dx - (dx * a + dy * b);
3705 oy += dy - (dx * c + dy * d);
3709 m += ", sizingMethod='auto expand')";
3713 //translate to ensure that transformations occur around the correct origin (default is center).
3714 m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
3716 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
3717 style.filter = filters.replace(_ieSetMatrixExp, m);
3719 style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha.
3722 //at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance.
3723 if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(" && filters.indexOf("Alpha")) === -1) {
3724 style.removeAttribute("filter");
3727 //we must set the margins AFTER applying the filter in order to avoid some bugs in IE8 that could (in rare scenarios) cause them to be ignored intermittently (vibration).
3729 var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom
3731 dx = t.ieOffsetX || 0;
3732 dy = t.ieOffsetY || 0;
3733 t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
3734 t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
3735 for (i = 0; i < 4; i++) {
3738 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
3739 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
3740 if (val !== t[prop]) {
3741 dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible.
3743 dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
3745 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
3750 _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
3751 var t = this.data, //refers to the element's _gsTransform object
3752 style = this.t.style,
3753 angle = t.rotation * _DEG2RAD,
3757 perspective = t.perspective,
3758 a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
3759 zOrigin, rnd, cos, sin, t1, t2, t3, t4;
3760 if (v === 1 || v === 0) if (t.force3D === "auto") if (!t.rotationY && !t.rotationX && sz === 1 && !perspective && !t.z) { //on the final render (which could be 0 for a from tween), if there are no 3D aspects, render in 2D to free up memory and improve performance especially on mobile devices
3761 _set2DTransformRatio.call(this, v);
3766 if (sx < n && sx > -n) { //Firefox has a bug (at least in v25) that causes it to render the transparent part of 32-bit PNG images as black when displayed inside an iframe and the 3D scale is very small and doesn't change sufficiently enough between renders (like if you use a Power4.easeInOut to scale from 0 to 1 where the beginning values only change a tiny amount to begin the tween before accelerating). In this case, we force the scale to be 0.00002 instead which is visually the same but works around the Firefox issue.
3769 if (sy < n && sy > -n) {
3772 if (perspective && !t.z && !t.rotationX && !t.rotationY) { //Firefox has a bug that causes elements to have an odd super-thin, broken/dotted black border on elements that have a perspective set but aren't utilizing 3D space (no rotationX, rotationY, or z).
3776 if (angle || t.skewX) {
3777 cos = Math.cos(angle);
3778 sin = Math.sin(angle);
3782 angle -= t.skewX * _DEG2RAD;
3783 cos = Math.cos(angle);
3784 sin = Math.sin(angle);
3785 if (t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does
3786 t1 = Math.tan(t.skewX * _DEG2RAD);
3787 t1 = Math.sqrt(1 + t1 * t1);
3795 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
3796 style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
3803 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
3804 a43 = (perspective) ? -1 / perspective : 0;
3805 zOrigin = t.zOrigin;
3807 angle = t.rotationY * _DEG2RAD;
3809 cos = Math.cos(angle);
3810 sin = Math.sin(angle);
3820 angle = t.rotationX * _DEG2RAD;
3822 cos = Math.cos(angle);
3823 sin = Math.sin(angle);
3824 t1 = a12*cos+a13*sin;
3825 t2 = a22*cos+a23*sin;
3826 t3 = a32*cos+a33*sin;
3827 t4 = a42*cos+a43*sin;
3828 a13 = a12*-sin+a13*cos;
3829 a23 = a22*-sin+a23*cos;
3830 a33 = a32*-sin+a33*cos;
3831 a43 = a42*-sin+a43*cos;
3859 a34 = a33*a34+zOrigin;
3861 //we round the x, y, and z slightly differently to allow even larger values.
3862 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
3863 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
3864 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
3865 style[_transformProp] = "matrix3d(" + [ (((a11 * rnd) | 0) / rnd), (((a21 * rnd) | 0) / rnd), (((a31 * rnd) | 0) / rnd), (((a41 * rnd) | 0) / rnd), (((a12 * rnd) | 0) / rnd), (((a22 * rnd) | 0) / rnd), (((a32 * rnd) | 0) / rnd), (((a42 * rnd) | 0) / rnd), (((a13 * rnd) | 0) / rnd), (((a23 * rnd) | 0) / rnd), (((a33 * rnd) | 0) / rnd), (((a43 * rnd) | 0) / rnd), a14, a24, a34, (perspective ? (1 + (-a34 / perspective)) : 1) ].join(",") + ")";
3868 _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
3869 var t = this.data, //refers to the element's _gsTransform object
3872 ang, skew, rnd, sx, sy;
3873 if (t.rotationX || t.rotationY || t.z || t.force3D === true || (t.force3D === "auto" && v !== 1 && v !== 0)) { //if a 3D tween begins while a 2D one is running, we need to kick the rendering over to the 3D method. For example, imagine a yoyo-ing, infinitely repeating scale tween running, and then the object gets rotated in 3D space with a different tween.
3874 this.setRatio = _set3DTransformRatio;
3875 _set3DTransformRatio.call(this, v);
3878 if (!t.rotation && !t.skewX) {
3879 style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
3881 ang = t.rotation * _DEG2RAD;
3882 skew = ang - t.skewX * _DEG2RAD;
3884 sx = t.scaleX * rnd;
3885 sy = t.scaleY * rnd;
3886 //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places.
3887 style[_transformProp] = "matrix(" + (((Math.cos(ang) * sx) | 0) / rnd) + "," + (((Math.sin(ang) * sx) | 0) / rnd) + "," + (((Math.sin(skew) * -sy) | 0) / rnd) + "," + (((Math.cos(skew) * sy) | 0) / rnd) + "," + t.x + "," + t.y + ")";
3891 _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType", {parser:function(t, e, p, cssp, pt, plugin, vars) {
3892 if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
3893 var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
3896 i = _transformProps.length,
3899 m2, skewY, copy, orig, has3D, hasChange, dr;
3900 if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
3901 copy = _tempDiv.style; //don't use the original target because it might be SVG in which case some browsers don't report computed style correctly.
3902 copy[_transformProp] = v.transform;
3903 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
3904 copy.position = "absolute";
3905 _doc.body.appendChild(_tempDiv);
3906 m2 = _getTransform(_tempDiv, null, false);
3907 _doc.body.removeChild(_tempDiv);
3908 } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
3909 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
3910 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
3911 scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
3912 x:_parseVal(v.x, m1.x),
3913 y:_parseVal(v.y, m1.y),
3914 z:_parseVal(v.z, m1.z),
3915 perspective:_parseVal(v.transformPerspective, m1.perspective)};
3916 dr = v.directionalRotation;
3918 if (typeof(dr) === "object") {
3926 m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : m1.rotation, m1.rotation, "rotation", endRotations);
3928 m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
3929 m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
3931 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
3933 //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
3934 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
3935 if ((skewY = m2.skewY - m1.skewY)) {
3937 m2.rotation += skewY;
3941 if (_supports3D && v.force3D != null) {
3942 m1.force3D = v.force3D;
3946 m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
3948 has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
3949 if (!has3D && v.scale != null) {
3950 m2.scaleZ = 1; //no need to tween scaleZ.
3954 p = _transformProps[i];
3955 orig = m2[p] - m1[p];
3956 if (orig > min || orig < -min || _forcePT[p] != null) {
3958 pt = new CSSPropTween(m1, p, m1[p], orig, pt);
3959 if (p in endRotations) {
3960 pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested
3962 pt.xs0 = 0; //ensures the value stays numeric in setRatio()
3964 cssp._overwriteProps.push(pt.n);
3968 orig = v.transformOrigin;
3969 if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
3970 if (_transformProp) {
3972 p = _transformOriginProp;
3973 orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
3974 pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
3979 orig = orig.split(" ");
3980 m1.zOrigin = ((orig.length > 2 && !(copy !== 0 && orig[2] === "0px")) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method.
3981 pt.xs0 = pt.e = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)!
3982 pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here)
3984 pt.xs0 = pt.e = m1.zOrigin;
3986 pt.xs0 = pt.e = orig;
3989 //for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp).
3991 _parsePosition(orig + "", m1);
3996 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
4001 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
4003 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
4005 var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
4007 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
4008 w = parseFloat(t.offsetWidth);
4009 h = parseFloat(t.offsetHeight);
4011 for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
4012 if (this.p.indexOf("border")) { //older browsers used a prefix
4013 props[i] = _checkPropPrefix(props[i]);
4015 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
4016 if (bs.indexOf(" ") !== -1) {
4017 bs2 = bs.split(" ");
4022 bn = parseFloat(bs);
4023 bsfx = bs.substr((bn + "").length);
4024 rel = (es.charAt(1) === "=");
4026 en = parseInt(es.charAt(0)+"1", 10);
4028 en *= parseFloat(es);
4029 esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
4031 en = parseFloat(es);
4032 esfx = es.substr((en + "").length);
4035 esfx = _suffixMap[p] || bsfx;
4037 if (esfx !== bsfx) {
4038 hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent.
4039 vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
4041 bs = (hn / w * 100) + "%";
4042 bs2 = (vn / h * 100) + "%";
4043 } else if (esfx === "em") {
4044 em = _convertToPixels(t, "borderLeft", 1, "em");
4045 bs = (hn / em) + "em";
4046 bs2 = (vn / em) + "em";
4052 es = (parseFloat(bs) + en) + esfx;
4053 es2 = (parseFloat(bs2) + en) + esfx;
4056 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
4059 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
4060 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
4061 var bp = "background-position",
4062 cs = (_cs || _getComputedStyle(t, null)),
4063 bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase
4064 es = this.format(e),
4065 ba, ea, i, pct, overlap, src;
4066 if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
4067 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
4068 if (src && src !== "none") {
4071 _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
4075 pct = (bs.indexOf("%") !== -1);
4076 if (pct !== (ea[i].indexOf("%") !== -1)) {
4077 overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
4078 ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
4084 return this.parseComplex(t.style, bs, es, pt, plugin);
4085 }, formatter:_parsePosition});
4086 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
4087 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
4088 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
4089 _registerComplexSpecialProp("transformStyle", {prefix:true});
4090 _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
4091 _registerComplexSpecialProp("userSelect", {prefix:true});
4092 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
4093 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
4094 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
4096 if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited.
4097 cs = t.currentStyle;
4098 delim = _ieVers < 8 ? " " : ",";
4099 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
4100 e = this.format(e).split(",").join(delim);
4102 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
4105 return this.parseComplex(t.style, b, e, pt, plugin);
4107 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
4108 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
4109 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
4110 return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin);
4111 }, color:true, formatter:function(v) {
4112 var a = v.split(" ");
4113 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
4115 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
4116 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
4118 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
4119 return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
4123 var _setIEOpacityRatio = function(v) {
4124 var t = this.t, //refers to the element's style property
4125 filters = t.filter || _getStyle(this.data, "filter"),
4126 val = (this.s + this.c * v) | 0,
4128 if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters.
4129 if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
4130 t.removeAttribute("filter");
4131 skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check.
4133 t.filter = filters.replace(_alphaFilterExp, "");
4139 t.filter = filters = filters || ("alpha(opacity=" + val + ")"); //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame.
4141 if (filters.indexOf("pacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8). We omit the "O" to avoid case-sensitivity issues
4142 if (val !== 0 || !this.xn1) { //bugs in IE7/8 won't render the filter properly if opacity is ADDED on the same frame/render as "visibility" changes (this.xn1 is 1 if this tween is an "autoAlpha" tween)
4143 t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
4146 t.filter = filters.replace(_opacityExp, "opacity=" + val);
4150 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
4151 var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
4153 isAutoAlpha = (p === "autoAlpha");
4154 if (typeof(e) === "string" && e.charAt(1) === "=") {
4155 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
4157 if (isAutoAlpha && b === 1 && _getStyle(t, "visibility", _cs) === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience)
4160 if (_supportsOpacity) {
4161 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
4163 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
4164 pt.xn1 = isAutoAlpha ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug.
4165 style.zoom = 1; //helps correct an IE issue.
4167 pt.b = "alpha(opacity=" + pt.s + ")";
4168 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
4171 pt.setRatio = _setIEOpacityRatio;
4173 if (isAutoAlpha) { //we have to create the "visibility" PropTween after the opacity one in the linked list so that they run in the order that works properly in IE8 and earlier
4174 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
4176 cssp._overwriteProps.push(pt.n);
4177 cssp._overwriteProps.push(p);
4183 var _removeProp = function(s, p) {
4185 if (s.removeProperty) {
4186 if (p.substr(0,2) === "ms") { //Microsoft browsers don't conform to the standard of capping the first prefix character, so we adjust so that when we prefix the caps with a dash, it's correct (otherwise it'd be "ms-transform" instead of "-ms-transform" for IE9, for example)
4187 p = "M" + p.substr(1);
4189 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
4190 } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
4191 s.removeAttribute(p);
4195 _setClassNameRatio = function(v) {
4196 this.t._gsClassPT = this;
4197 if (v === 1 || v === 0) {
4198 this.t.setAttribute("class", (v === 0) ? this.b : this.e);
4199 var mpt = this.data, //first MiniPropTween
4203 _removeProp(s, mpt.p);
4209 if (v === 1 && this.t._gsClassPT === this) {
4210 this.t._gsClassPT = null;
4212 } else if (this.t.getAttribute("class") !== this.e) {
4213 this.t.setAttribute("class", this.e);
4216 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
4217 var b = t.getAttribute("class") || "", //don't use t.className because it doesn't work consistently on SVG elements; getAttribute("class") and setAttribute("class", value") is more reliable.
4218 cssText = t.style.cssText,
4219 difData, bs, cnpt, cnptLookup, mpt;
4220 pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
4221 pt.setRatio = _setClassNameRatio;
4223 _hasPriority = true;
4225 bs = _getAllStyles(t, _cs);
4226 //if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfering that were there just for class-specific values)
4227 cnpt = t._gsClassPT;
4230 mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned.
4232 cnptLookup[mpt.p] = 1;
4238 pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
4239 if (cssp._tween._duration) { //if it's a zero-duration tween, there's no need to tween anything or parse the data. In fact, if we switch classes temporarily (which we must do for proper parsing) and the class has a transition applied, it could cause a quick flash to the end state and back again initially in some browsers.
4240 t.setAttribute("class", pt.e);
4241 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
4242 t.setAttribute("class", b);
4243 pt.data = difData.firstMPT;
4244 t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
4245 pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
4251 var _setClearPropsRatio = function(v) {
4252 if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration && this.data.data !== "isFromStart") { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that and if the tween is the zero-duration one that's created internally to render the starting values in a from() tween, ignore that because otherwise, for example, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in).
4253 var s = this.t.style,
4254 transformParse = _specialProps.transform.parse,
4255 a, p, i, clearTransform;
4256 if (this.e === "all") {
4258 clearTransform = true;
4260 a = this.e.split(",");
4264 if (_specialProps[p]) {
4265 if (_specialProps[p].parse === transformParse) {
4266 clearTransform = true;
4268 p = (p === "transformOrigin") ? _transformOriginProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow"
4274 if (clearTransform) {
4275 _removeProp(s, _transformProp);
4276 if (this.t._gsTransform) {
4277 delete this.t._gsTransform;
4283 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
4284 pt = new CSSPropTween(t, p, 0, 0, pt, 2);
4285 pt.setRatio = _setClearPropsRatio;
4288 pt.data = cssp._tween;
4289 _hasPriority = true;
4293 p = "bezier,throwProps,physicsProps,physics2D".split(",");
4296 _registerPluginProp(p[i]);
4306 p = CSSPlugin.prototype;
4309 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
4310 p._onInitTween = function(target, vars, tween) {
4311 if (!target.nodeType) { //css is only for dom elements
4314 this._target = target;
4315 this._tween = tween;
4317 _autoRound = vars.autoRound;
4318 _hasPriority = false;
4319 _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
4320 _cs = _getComputedStyle(target, "");
4321 _overwriteProps = this._overwriteProps;
4322 var style = target.style,
4323 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
4324 if (_reqSafariFix) if (style.zIndex === "") {
4325 v = _getStyle(target, "zIndex", _cs);
4326 if (v === "auto" || v === "") {
4327 //corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive.
4328 this._addLazySet(style, "zIndex", 0);
4332 if (typeof(vars) === "string") {
4333 first = style.cssText;
4334 v = _getAllStyles(target, _cs);
4335 style.cssText = first + ";" + vars;
4336 v = _cssDif(target, v, _getAllStyles(target)).difs;
4337 if (!_supportsOpacity && _opacityValExp.test(vars)) {
4338 v.opacity = parseFloat( RegExp.$1 );
4341 style.cssText = first;
4343 this._firstPT = pt = this.parse(target, vars, null);
4345 if (this._transformType) {
4346 threeD = (this._transformType === 3);
4347 if (!_transformProp) {
4348 style.zoom = 1; //helps correct an IE issue.
4349 } else if (_isSafari) {
4350 _reqSafariFix = true;
4351 //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
4352 if (style.zIndex === "") {
4353 zIndex = _getStyle(target, "zIndex", _cs);
4354 if (zIndex === "auto" || zIndex === "") {
4355 this._addLazySet(style, "zIndex", 0);
4358 //Setting WebkitBackfaceVisibility corrects 3 bugs:
4359 // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
4360 // 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly.
4361 // 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug.
4362 //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
4364 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
4368 while (pt2 && pt2._next) {
4371 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
4372 this._linkCSSP(tpt, null, pt2);
4373 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
4374 tpt.data = this._transform || _getTransform(target, _cs, true);
4375 _overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here.
4379 //reorders the linked list in order of pr (priority)
4383 while (pt2 && pt2.pr > pt.pr) {
4386 if ((pt._prev = pt2 ? pt2._prev : last)) {
4387 pt._prev._next = pt;
4391 if ((pt._next = pt2)) {
4398 this._firstPT = first;
4404 p.parse = function(target, vars, pt, plugin) {
4405 var style = target.style,
4406 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
4408 es = vars[p]; //ending value string
4409 sp = _specialProps[p]; //SpecialProp lookup.
4411 pt = sp.parse(target, es, p, this, pt, plugin, vars);
4414 bs = _getStyle(target, p, _cs) + "";
4415 isStr = (typeof(es) === "string");
4416 if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor:
4418 es = _parseColor(es);
4419 es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
4421 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
4423 } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
4424 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
4427 bn = parseFloat(bs);
4428 bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case.
4430 if (bs === "" || bs === "auto") {
4431 if (p === "width" || p === "height") {
4432 bn = _getDimension(target, p, _cs);
4434 } else if (p === "left" || p === "top") {
4435 bn = _calculateOffset(target, p, _cs);
4438 bn = (p !== "opacity") ? 0 : 1;
4443 rel = (isStr && es.charAt(1) === "=");
4445 en = parseInt(es.charAt(0) + "1", 10);
4447 en *= parseFloat(es);
4448 esfx = es.replace(_suffixExp, "");
4450 en = parseFloat(es);
4451 esfx = isStr ? es.substr((en + "").length) || "" : "";
4455 esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
4458 es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix.
4460 //if the beginning/ending suffixes don't match, normalize them...
4461 if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn) { //note: if the beginning value (bn) is 0, we don't need to convert units!
4462 bn = _convertToPixels(target, p, bn, bsfx);
4464 bn /= _convertToPixels(target, p, 100, "%") / 100;
4465 if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens.
4469 } else if (esfx === "em") {
4470 bn /= _convertToPixels(target, p, 1, "em");
4472 //otherwise convert to pixels.
4473 } else if (esfx !== "px") {
4474 en = _convertToPixels(target, p, en, esfx);
4475 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
4477 if (rel) if (en || en === 0) {
4478 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
4486 if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly.
4487 pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
4489 //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
4490 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
4491 _log("invalid " + p + " tween value: " + vars[p]);
4493 pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
4494 pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween.
4495 //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
4499 if (plugin) if (pt && !pt.plugin) {
4507 //gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
4508 p.setRatio = function(v) {
4509 var pt = this._firstPT,
4513 //at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards).
4514 if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
4516 if (pt.type !== 2) {
4524 } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
4526 val = pt.c * v + pt.s;
4528 val = Math.round(val);
4529 } else if (val < min) if (val > -min) {
4533 pt.t[pt.p] = val + pt.xs0;
4534 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
4537 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
4538 } else if (i === 3) {
4539 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
4540 } else if (i === 4) {
4541 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
4542 } else if (i === 5) {
4543 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5;
4545 str = pt.xs0 + val + pt.xs1;
4546 for (i = 1; i < pt.l; i++) {
4547 str += pt["xn"+i] + pt["xs"+(i+1)];
4552 } else if (pt.type === -1) { //non-tweening value
4553 pt.t[pt.p] = pt.xs0;
4555 } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
4561 //if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever).
4564 if (pt.type !== 2) {
4576 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
4577 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
4578 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
4579 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
4580 * doesn't have any transform-related properties of its own. You can call this method as many times as you
4581 * want and it won't create duplicate CSSPropTweens.
4583 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
4585 p._enableTransforms = function(threeD) {
4586 this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
4587 this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
4590 var lazySet = function(v) {
4591 this.t[this.p] = this.e;
4592 this.data._linkCSSP(this, this._next, null, true); //we purposefully keep this._next even though it'd make sense to null it, but this is a performance optimization, as this happens during the while (pt) {} loop in setRatio() at the bottom of which it sets pt = pt._next, so if we null it, the linked list will be broken in that loop.
4594 /** @private Gives us a way to set a value on the first render (and only the first render). **/
4595 p._addLazySet = function(t, p, v) {
4596 var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
4598 pt.setRatio = lazySet;
4603 p._linkCSSP = function(pt, next, prev, remove) {
4609 pt._next._prev = pt._prev;
4612 pt._prev._next = pt._next;
4613 } else if (this._firstPT === pt) {
4614 this._firstPT = pt._next;
4615 remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
4619 } else if (!remove && this._firstPT === null) {
4628 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
4629 p._kill = function(lookup) {
4632 if (lookup.autoAlpha || lookup.alpha) {
4634 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
4635 copy[p] = lookup[p];
4638 if (copy.autoAlpha) {
4639 copy.visibility = 1;
4642 if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst".
4644 if (xfirst && xfirst._prev) {
4645 this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
4646 } else if (xfirst === this._firstPT) {
4647 this._firstPT = pt._next;
4650 this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
4652 this._classNamePT = null;
4654 return TweenPlugin.prototype._kill.call(this, copy);
4659 //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
4660 var _getChildStyles = function(e, props, targets) {
4661 var children, i, child, type;
4665 _getChildStyles(e[i], props, targets);
4669 children = e.childNodes;
4670 i = children.length;
4672 child = children[i];
4675 props.push(_getAllStyles(child));
4677 targets.push(child);
4680 if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
4681 _getChildStyles(child, props, targets);
4687 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
4688 * and then compares the style properties of all the target's child elements at the tween's start and end, and
4689 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
4690 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
4691 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
4692 * is because it creates entirely new tweens that may have completely different targets than the original tween,
4693 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
4694 * and it would create other problems. For example:
4695 * - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted)
4696 * - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others.
4697 * - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed.
4699 * @param {Object} target object to be tweened
4700 * @param {number} Duration in seconds (or frames for frames-based tweens)
4701 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
4702 * @return {Array} An array of TweenLite instances
4704 CSSPlugin.cascadeTo = function(target, duration, vars) {
4705 var tween = TweenLite.to(target, duration, vars),
4710 _reservedProps = TweenLite._internals.reservedProps,
4712 target = tween._targets || tween.target;
4713 _getChildStyles(target, b, targets);
4714 tween.render(duration, true);
4715 _getChildStyles(target, e);
4716 tween.render(0, true);
4717 tween._enabled(true);
4720 difs = _cssDif(targets[i], b[i], e[i]);
4721 if (difs.firstMPT) {
4724 if (_reservedProps[p]) {
4728 results.push( TweenLite.to(targets[i], duration, difs) );
4734 TweenPlugin.activate([CSSPlugin]);
4750 * ----------------------------------------------------------------
4752 * ----------------------------------------------------------------
4756 var RoundPropsPlugin = window._gsDefine.plugin({
4757 propName: "roundProps",
4761 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4762 init: function(target, value, tween) {
4763 this._tween = tween;
4768 p = RoundPropsPlugin.prototype;
4770 p._onInitAllProps = function() {
4771 var tween = this._tween,
4772 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
4775 rpt = tween._propLookup.roundProps,
4783 pt = tween._firstPT;
4785 next = pt._next; //record here, because it may get removed
4787 pt.t._roundProps(lookup, true);
4788 } else if (pt.n === prop) {
4789 this._add(pt.t, prop, pt.s, pt.c);
4790 //remove from linked list
4792 next._prev = pt._prev;
4795 pt._prev._next = next;
4796 } else if (tween._firstPT === pt) {
4797 tween._firstPT = next;
4799 pt._next = pt._prev = null;
4800 tween._propLookup[prop] = rpt;
4808 p._add = function(target, p, s, c) {
4809 this._addTween(target, p, s, s + c, p, true);
4810 this._overwriteProps.push(p);
4825 * ----------------------------------------------------------------
4827 * ----------------------------------------------------------------
4829 window._gsDefine.plugin({
4834 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4835 init: function(target, value, tween) {
4837 if (typeof(target.setAttribute) !== "function") {
4840 this._target = target;
4842 this._start = {}; // we record start and end values exactly as they are in case they're strings (not numbers) - we need to be able to revert to them cleanly.
4845 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
4846 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
4847 this._end[p] = end ? end.s + end.c : value[p];
4848 this._overwriteProps.push(p);
4853 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
4854 set: function(ratio) {
4855 this._super.setRatio.call(this, ratio);
4856 var props = this._overwriteProps,
4858 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
4862 this._target.setAttribute(p, lookup[p] + "");
4878 * ----------------------------------------------------------------
4879 * DirectionalRotationPlugin
4880 * ----------------------------------------------------------------
4882 window._gsDefine.plugin({
4883 propName: "directionalRotation",
4887 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4888 init: function(target, value, tween) {
4889 if (typeof(value) !== "object") {
4890 value = {rotation:value};
4893 var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
4895 p, v, start, end, dif, split;
4897 if (p !== "useRadians") {
4898 split = (value[p] + "").split("_");
4900 start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
4901 end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
4904 v = split.join("_");
4905 if (v.indexOf("short") !== -1) {
4907 if (dif !== dif % (cap / 2)) {
4908 dif = (dif < 0) ? dif + cap : dif - cap;
4911 if (v.indexOf("_cw") !== -1 && dif < 0) {
4912 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
4913 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
4914 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
4917 if (dif > min || dif < -min) {
4918 this._addTween(target, p, start, start + dif, p);
4919 this._overwriteProps.push(p);
4926 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
4927 set: function(ratio) {
4930 this._super.setRatio.call(this, ratio);
4935 pt.t[pt.p](this.finals[pt.p]);
4937 pt.t[pt.p] = this.finals[pt.p];
4957 * ----------------------------------------------------------------
4959 * ----------------------------------------------------------------
4961 window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
4963 var w = (window.GreenSockGlobals || window),
4964 gs = w.com.greensock,
4966 _HALF_PI = Math.PI / 2,
4968 _create = function(n, f) {
4969 var C = _class("easing." + n, function(){}, true),
4970 p = C.prototype = new Ease();
4975 _easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist.
4976 _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
4977 var C = _class("easing."+name, {
4978 easeOut:new EaseOut(),
4979 easeIn:new EaseIn(),
4980 easeInOut:new EaseInOut()
4985 EasePoint = function(time, value, next) {
4991 this.c = next.v - value;
4992 this.gap = next.t - time;
4997 _createBack = function(n, f) {
4998 var C = _class("easing." + n, function(overshoot) {
4999 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
5000 this._p2 = this._p1 * 1.525;
5002 p = C.prototype = new Ease();
5005 p.config = function(overshoot) {
5006 return new C(overshoot);
5011 Back = _wrap("Back",
5012 _createBack("BackOut", function(p) {
5013 return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
5015 _createBack("BackIn", function(p) {
5016 return p * p * ((this._p1 + 1) * p - this._p1);
5018 _createBack("BackInOut", function(p) {
5019 return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2);
5025 SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
5026 power = (power || power === 0) ? power : 0.7;
5027 if (linearRatio == null) {
5029 } else if (linearRatio > 1) {
5032 this._p = (linearRatio !== 1) ? power : 0;
5033 this._p1 = (1 - linearRatio) / 2;
5034 this._p2 = linearRatio;
5035 this._p3 = this._p1 + this._p2;
5036 this._calcEnd = (yoyoMode === true);
5038 p = SlowMo.prototype = new Ease(),
5039 SteppedEase, RoughEase, _createElastic;
5041 p.constructor = SlowMo;
5042 p.getRatio = function(p) {
5043 var r = p + (0.5 - p) * this._p;
5045 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
5046 } else if (p > this._p3) {
5047 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
5049 return this._calcEnd ? 1 : r;
5051 SlowMo.ease = new SlowMo(0.7, 0.7);
5053 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
5054 return new SlowMo(linearRatio, power, yoyoMode);
5059 SteppedEase = _class("easing.SteppedEase", function(steps) {
5061 this._p1 = 1 / steps;
5062 this._p2 = steps + 1;
5064 p = SteppedEase.prototype = new Ease();
5065 p.constructor = SteppedEase;
5066 p.getRatio = function(p) {
5069 } else if (p >= 1) {
5072 return ((this._p2 * p) >> 0) * this._p1;
5074 p.config = SteppedEase.config = function(steps) {
5075 return new SteppedEase(steps);
5080 RoughEase = _class("easing.RoughEase", function(vars) {
5082 var taper = vars.taper || "none",
5085 points = (vars.points || 20) | 0,
5087 randomize = (vars.randomize !== false),
5088 clamp = (vars.clamp === true),
5089 template = (vars.template instanceof Ease) ? vars.template : null,
5090 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
5091 x, y, bump, invX, obj, pnt;
5093 x = randomize ? Math.random() : (1 / points) * i;
5094 y = template ? template.getRatio(x) : x;
5095 if (taper === "none") {
5097 } else if (taper === "out") {
5099 bump = invX * invX * strength;
5100 } else if (taper === "in") {
5101 bump = x * x * strength;
5102 } else if (x < 0.5) { //"both" (start)
5104 bump = invX * invX * 0.5 * strength;
5105 } else { //"both" (end)
5107 bump = invX * invX * 0.5 * strength;
5110 y += (Math.random() * bump) - (bump * 0.5);
5123 a[cnt++] = {x:x, y:y};
5125 a.sort(function(a, b) {
5129 pnt = new EasePoint(1, 1, null);
5133 pnt = new EasePoint(obj.x, obj.y, pnt);
5136 this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
5138 p = RoughEase.prototype = new Ease();
5139 p.constructor = RoughEase;
5140 p.getRatio = function(p) {
5141 var pnt = this._prev;
5143 while (pnt.next && p >= pnt.t) {
5148 while (pnt.prev && p <= pnt.t) {
5153 return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
5155 p.config = function(vars) {
5156 return new RoughEase(vars);
5158 RoughEase.ease = new RoughEase();
5163 _create("BounceOut", function(p) {
5165 return 7.5625 * p * p;
5166 } else if (p < 2 / 2.75) {
5167 return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5168 } else if (p < 2.5 / 2.75) {
5169 return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5171 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5173 _create("BounceIn", function(p) {
5174 if ((p = 1 - p) < 1 / 2.75) {
5175 return 1 - (7.5625 * p * p);
5176 } else if (p < 2 / 2.75) {
5177 return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
5178 } else if (p < 2.5 / 2.75) {
5179 return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
5181 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
5183 _create("BounceInOut", function(p) {
5184 var invert = (p < 0.5);
5192 } else if (p < 2 / 2.75) {
5193 p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5194 } else if (p < 2.5 / 2.75) {
5195 p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5197 p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5199 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
5206 _create("CircOut", function(p) {
5207 return Math.sqrt(1 - (p = p - 1) * p);
5209 _create("CircIn", function(p) {
5210 return -(Math.sqrt(1 - (p * p)) - 1);
5212 _create("CircInOut", function(p) {
5213 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
5219 _createElastic = function(n, f, def) {
5220 var C = _class("easing." + n, function(amplitude, period) {
5221 this._p1 = amplitude || 1;
5222 this._p2 = period || def;
5223 this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
5225 p = C.prototype = new Ease();
5228 p.config = function(amplitude, period) {
5229 return new C(amplitude, period);
5234 _createElastic("ElasticOut", function(p) {
5235 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
5237 _createElastic("ElasticIn", function(p) {
5238 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
5240 _createElastic("ElasticInOut", function(p) {
5241 return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ) *0.5 + 1;
5248 _create("ExpoOut", function(p) {
5249 return 1 - Math.pow(2, -10 * p);
5251 _create("ExpoIn", function(p) {
5252 return Math.pow(2, 10 * (p - 1)) - 0.001;
5254 _create("ExpoInOut", function(p) {
5255 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
5262 _create("SineOut", function(p) {
5263 return Math.sin(p * _HALF_PI);
5265 _create("SineIn", function(p) {
5266 return -Math.cos(p * _HALF_PI) + 1;
5268 _create("SineInOut", function(p) {
5269 return -0.5 * (Math.cos(Math.PI * p) - 1);
5273 _class("easing.EaseLookup", {
5279 //register the non-standard eases
5280 _easeReg(w.SlowMo, "SlowMo", "ease,");
5281 _easeReg(RoughEase, "RoughEase", "ease,");
5282 _easeReg(SteppedEase, "SteppedEase", "ease,");
5302 * ----------------------------------------------------------------
5303 * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
5304 * ----------------------------------------------------------------
5309 var _globals = window.GreenSockGlobals || window;
5310 if (_globals.TweenLite) {
5311 return; //in case the core set of classes is already loaded, don't instantiate twice.
5313 var _namespace = function(ns) {
5314 var a = ns.split("."),
5316 for (i = 0; i < a.length; i++) {
5317 p[a[i]] = p = p[a[i]] || {};
5321 gs = _namespace("com.greensock"),
5322 _tinyNum = 0.0000000001,
5324 _emptyFunc = function() {},
5325 _isArray = (function() { //works around issues in iframe environments where the Array global isn't shared, thus if the object originates in a different window/iframe, "(obj instanceof Array)" will evaluate false. We added some speed optimizations to avoid Object.prototype.toString.call() unless it's absolutely necessary because it's VERY slow (like 20x slower)
5326 var toString = Object.prototype.toString,
5327 array = toString.call([]);
5328 return function(obj) {
5329 return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
5332 a, i, p, _ticker, _tickerActive,
5337 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
5338 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
5339 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
5340 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
5342 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
5343 * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere,
5344 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
5345 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
5346 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
5347 * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could
5348 * sandbox the banner one like:
5351 * var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever.
5353 * <script src="js/greensock/v1.7/TweenMax.js"></script>
5355 * window.GreenSockGlobals = null; //reset it back to null so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...)
5357 * <script src="js/greensock/v1.6/TweenMax.js"></script>
5359 * gs.TweenLite.to(...); //would use v1.7
5360 * TweenLite.to(...); //would use v1.6
5363 * @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".
5364 * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
5365 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
5366 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
5368 Definition = function(ns, dependencies, func, global) {
5369 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
5370 _defLookup[ns] = this;
5371 this.gsClass = null;
5374 this.check = function(init) {
5375 var i = dependencies.length,
5379 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
5380 _classes[i] = cur.gsClass;
5386 if (missing === 0 && func) {
5387 a = ("com.greensock." + ns).split(".");
5389 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
5391 //exports to multiple environments
5393 _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.)
5394 if (typeof(define) === "function" && define.amd){ //AMD
5395 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
5396 } else if (typeof(module) !== "undefined" && module.exports){ //node
5397 module.exports = cl;
5400 for (i = 0; i < this.sc.length; i++) {
5408 //used to create Definition instances (which basically registers a class that has dependencies).
5409 _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
5410 return new Definition(ns, dependencies, func, global);
5413 //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).
5414 _class = gs._class = function(ns, func, global) {
5415 func = func || function() {};
5416 _gsDefine(ns, [], function(){ return func; }, global);
5420 _gsDefine.globals = _globals;
5425 * ----------------------------------------------------------------
5427 * ----------------------------------------------------------------
5429 var _baseParams = [0, 0, 1, 1],
5431 Ease = _class("easing.Ease", function(func, extraParams, type, power) {
5433 this._type = type || 0;
5434 this._power = power || 0;
5435 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
5437 _easeMap = Ease.map = {},
5438 _easeReg = Ease.register = function(ease, names, types, create) {
5439 var na = names.split(","),
5441 ta = (types || "easeIn,easeOut,easeInOut").split(","),
5445 e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
5449 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
5456 p.getRatio = function(p) {
5458 this._params[0] = p;
5459 return this._func.apply(null, this._params);
5463 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
5466 } else if (pw === 2) {
5468 } else if (pw === 3) {
5470 } else if (pw === 4) {
5473 return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
5476 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
5477 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
5480 p = a[i]+",Power"+i;
5481 _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
5482 _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
5483 _easeReg(new Ease(null,null,3,i), p, "easeInOut");
5485 _easeMap.linear = gs.easing.Linear.easeIn;
5486 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
5490 * ----------------------------------------------------------------
5492 * ----------------------------------------------------------------
5494 var EventDispatcher = _class("events.EventDispatcher", function(target) {
5495 this._listeners = {};
5496 this._eventTarget = target || this;
5498 p = EventDispatcher.prototype;
5500 p.addEventListener = function(type, callback, scope, useParam, priority) {
5501 priority = priority || 0;
5502 var list = this._listeners[type],
5506 this._listeners[type] = list = [];
5511 if (listener.c === callback && listener.s === scope) {
5513 } else if (index === 0 && listener.pr < priority) {
5517 list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
5518 if (this === _ticker && !_tickerActive) {
5523 p.removeEventListener = function(type, callback) {
5524 var list = this._listeners[type], i;
5528 if (list[i].c === callback) {
5536 p.dispatchEvent = function(type) {
5537 var list = this._listeners[type],
5541 t = this._eventTarget;
5545 listener.c.call(listener.s || t, {type:type, target:t});
5547 listener.c.call(listener.s || t);
5555 * ----------------------------------------------------------------
5557 * ----------------------------------------------------------------
5559 var _reqAnimFrame = window.requestAnimationFrame,
5560 _cancelAnimFrame = window.cancelAnimationFrame,
5561 _getTime = Date.now || function() {return new Date().getTime();},
5562 _lastUpdate = _getTime();
5564 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
5565 a = ["ms","moz","webkit","o"];
5567 while (--i > -1 && !_reqAnimFrame) {
5568 _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
5569 _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
5572 _class("Ticker", function(fps, useRAF) {
5574 _startTime = _getTime(),
5575 _useRAF = (useRAF !== false && _reqAnimFrame),
5576 _lagThreshold = 500,
5578 _fps, _req, _id, _gap, _nextTime,
5579 _tick = function(manual) {
5580 var elapsed = _getTime() - _lastUpdate,
5582 if (elapsed > _lagThreshold) {
5583 _startTime += elapsed - _adjustedLag;
5585 _lastUpdate += elapsed;
5586 _self.time = (_lastUpdate - _startTime) / 1000;
5587 overlap = _self.time - _nextTime;
5588 if (!_fps || overlap > 0 || manual === true) {
5590 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
5593 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.
5597 _self.dispatchEvent("tick");
5601 EventDispatcher.call(_self);
5602 _self.time = _self.frame = 0;
5603 _self.tick = function() {
5607 _self.lagSmoothing = function(threshold, adjustedLag) {
5608 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
5609 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
5612 _self.sleep = function() {
5616 if (!_useRAF || !_cancelAnimFrame) {
5619 _cancelAnimFrame(_id);
5623 if (_self === _ticker) {
5624 _tickerActive = false;
5628 _self.wake = function() {
5631 } 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().
5632 _lastUpdate = _getTime() - _lagThreshold + 5;
5634 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
5635 if (_self === _ticker) {
5636 _tickerActive = true;
5641 _self.fps = function(value) {
5642 if (!arguments.length) {
5646 _gap = 1 / (_fps || 60);
5647 _nextTime = this.time + _gap;
5651 _self.useRAF = function(value) {
5652 if (!arguments.length) {
5661 //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.
5662 setTimeout(function() {
5663 if (_useRAF && (!_id || _self.frame < 5)) {
5664 _self.useRAF(false);
5669 p = gs.Ticker.prototype = new gs.events.EventDispatcher();
5670 p.constructor = gs.Ticker;
5674 * ----------------------------------------------------------------
5676 * ----------------------------------------------------------------
5678 var Animation = _class("core.Animation", function(duration, vars) {
5679 this.vars = vars = vars || {};
5680 this._duration = this._totalDuration = duration || 0;
5681 this._delay = Number(vars.delay) || 0;
5682 this._timeScale = 1;
5683 this._active = (vars.immediateRender === true);
5684 this.data = vars.data;
5685 this._reversed = (vars.reversed === true);
5687 if (!_rootTimeline) {
5690 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.
5694 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
5695 tl.add(this, tl._time);
5697 if (this.vars.paused) {
5702 _ticker = Animation.ticker = new gs.Ticker();
5703 p = Animation.prototype;
5704 p._dirty = p._gc = p._initted = p._paused = false;
5705 p._totalTime = p._time = 0;
5706 p._rawPrevTime = -1;
5707 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
5711 //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.
5712 var _checkTimeout = function() {
5713 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
5716 setTimeout(_checkTimeout, 2000);
5721 p.play = function(from, suppressEvents) {
5723 this.seek(from, suppressEvents);
5725 return this.reversed(false).paused(false);
5728 p.pause = function(atTime, suppressEvents) {
5729 if (atTime != null) {
5730 this.seek(atTime, suppressEvents);
5732 return this.paused(true);
5735 p.resume = function(from, suppressEvents) {
5737 this.seek(from, suppressEvents);
5739 return this.paused(false);
5742 p.seek = function(time, suppressEvents) {
5743 return this.totalTime(Number(time), suppressEvents !== false);
5746 p.restart = function(includeDelay, suppressEvents) {
5747 return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
5750 p.reverse = function(from, suppressEvents) {
5752 this.seek((from || this.totalDuration()), suppressEvents);
5754 return this.reversed(true).paused(false);
5757 p.render = function(time, suppressEvents, force) {
5758 //stub - we override this method in subclasses.
5761 p.invalidate = function() {
5765 p.isActive = function() {
5766 var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
5767 startTime = this._startTime,
5769 return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
5772 p._enabled = function (enabled, ignoreTimeline) {
5773 if (!_tickerActive) {
5776 this._gc = !enabled;
5777 this._active = this.isActive();
5778 if (ignoreTimeline !== true) {
5779 if (enabled && !this.timeline) {
5780 this._timeline.add(this, this._startTime - this._delay);
5781 } else if (!enabled && this.timeline) {
5782 this._timeline._remove(this, true);
5789 p._kill = function(vars, target) {
5790 return this._enabled(false, false);
5793 p.kill = function(vars, target) {
5794 this._kill(vars, target);
5798 p._uncache = function(includeSelf) {
5799 var tween = includeSelf ? this : this.timeline;
5801 tween._dirty = true;
5802 tween = tween.timeline;
5807 p._swapSelfInParams = function(params) {
5808 var i = params.length,
5809 copy = params.concat();
5811 if (params[i] === "{self}") {
5818 //----Animation getters/setters --------------------------------------------------------
5820 p.eventCallback = function(type, callback, params, scope) {
5821 if ((type || "").substr(0,2) === "on") {
5823 if (arguments.length === 1) {
5826 if (callback == null) {
5830 v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
5831 v[type + "Scope"] = scope;
5833 if (type === "onUpdate") {
5834 this._onUpdate = callback;
5840 p.delay = function(value) {
5841 if (!arguments.length) {
5844 if (this._timeline.smoothChildTiming) {
5845 this.startTime( this._startTime + value - this._delay );
5847 this._delay = value;
5851 p.duration = function(value) {
5852 if (!arguments.length) {
5853 this._dirty = false;
5854 return this._duration;
5856 this._duration = this._totalDuration = value;
5857 this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
5858 if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
5859 this.totalTime(this._totalTime * (value / this._duration), true);
5864 p.totalDuration = function(value) {
5865 this._dirty = false;
5866 return (!arguments.length) ? this._totalDuration : this.duration(value);
5869 p.time = function(value, suppressEvents) {
5870 if (!arguments.length) {
5874 this.totalDuration();
5876 return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
5879 p.totalTime = function(time, suppressEvents, uncapped) {
5880 if (!_tickerActive) {
5883 if (!arguments.length) {
5884 return this._totalTime;
5886 if (this._timeline) {
5887 if (time < 0 && !uncapped) {
5888 time += this.totalDuration();
5890 if (this._timeline.smoothChildTiming) {
5892 this.totalDuration();
5894 var totalDuration = this._totalDuration,
5895 tl = this._timeline;
5896 if (time > totalDuration && !uncapped) {
5897 time = totalDuration;
5899 this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
5900 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.
5901 this._uncache(false);
5903 //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.
5905 while (tl._timeline) {
5906 if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
5907 tl.totalTime(tl._totalTime, true);
5914 this._enabled(true, false);
5916 if (this._totalTime !== time || this._duration === 0) {
5917 this.render(time, suppressEvents, false);
5918 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.
5926 p.progress = p.totalProgress = function(value, suppressEvents) {
5927 return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
5930 p.startTime = function(value) {
5931 if (!arguments.length) {
5932 return this._startTime;
5934 if (value !== this._startTime) {
5935 this._startTime = value;
5936 if (this.timeline) if (this.timeline._sortChildren) {
5937 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.
5943 p.timeScale = function(value) {
5944 if (!arguments.length) {
5945 return this._timeScale;
5947 value = value || _tinyNum; //can't allow zero because it'll throw the math off
5948 if (this._timeline && this._timeline.smoothChildTiming) {
5949 var pauseTime = this._pauseTime,
5950 t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
5951 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
5953 this._timeScale = value;
5954 return this._uncache(false);
5957 p.reversed = function(value) {
5958 if (!arguments.length) {
5959 return this._reversed;
5961 if (value != this._reversed) {
5962 this._reversed = value;
5963 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
5968 p.paused = function(value) {
5969 if (!arguments.length) {
5970 return this._paused;
5972 if (value != this._paused) if (this._timeline) {
5973 if (!_tickerActive && !value) {
5976 var tl = this._timeline,
5978 elapsed = raw - this._pauseTime;
5979 if (!value && tl.smoothChildTiming) {
5980 this._startTime += elapsed;
5981 this._uncache(false);
5983 this._pauseTime = value ? raw : null;
5984 this._paused = value;
5985 this._active = this.isActive();
5986 if (!value && elapsed !== 0 && this._initted && this.duration()) {
5987 this.render((tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale), true, true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render.
5990 if (this._gc && !value) {
5991 this._enabled(true, false);
5998 * ----------------------------------------------------------------
6000 * ----------------------------------------------------------------
6002 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
6003 Animation.call(this, 0, vars);
6004 this.autoRemoveChildren = this.smoothChildTiming = true;
6007 p = SimpleTimeline.prototype = new Animation();
6008 p.constructor = SimpleTimeline;
6009 p.kill()._gc = false;
6010 p._first = p._last = null;
6011 p._sortChildren = false;
6013 p.add = p.insert = function(child, position, align, stagger) {
6015 child._startTime = Number(position || 0) + child._delay;
6016 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).
6017 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
6019 if (child.timeline) {
6020 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
6022 child.timeline = child._timeline = this;
6024 child._enabled(true, true);
6026 prevTween = this._last;
6027 if (this._sortChildren) {
6028 st = child._startTime;
6029 while (prevTween && prevTween._startTime > st) {
6030 prevTween = prevTween._prev;
6034 child._next = prevTween._next;
6035 prevTween._next = child;
6037 child._next = this._first;
6038 this._first = child;
6041 child._next._prev = child;
6045 child._prev = prevTween;
6046 if (this._timeline) {
6047 this._uncache(true);
6052 p._remove = function(tween, skipDisable) {
6053 if (tween.timeline === this) {
6055 tween._enabled(false, true);
6057 tween.timeline = null;
6060 tween._prev._next = tween._next;
6061 } else if (this._first === tween) {
6062 this._first = tween._next;
6065 tween._next._prev = tween._prev;
6066 } else if (this._last === tween) {
6067 this._last = tween._prev;
6070 if (this._timeline) {
6071 this._uncache(true);
6077 p.render = function(time, suppressEvents, force) {
6078 var tween = this._first,
6080 this._totalTime = this._time = this._rawPrevTime = time;
6082 next = tween._next; //record it here because the value could change after rendering...
6083 if (tween._active || (time >= tween._startTime && !tween._paused)) {
6084 if (!tween._reversed) {
6085 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
6087 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
6094 p.rawTime = function() {
6095 if (!_tickerActive) {
6098 return this._totalTime;
6102 * ----------------------------------------------------------------
6104 * ----------------------------------------------------------------
6106 var TweenLite = _class("TweenLite", function(target, duration, vars) {
6107 Animation.call(this, duration, vars);
6108 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
6110 if (target == null) {
6111 throw "Cannot tween a null target.";
6114 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
6116 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
6117 overwrite = this.vars.overwrite,
6120 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
6122 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
6123 this._targets = targets = _slice.call(target, 0);
6124 this._propLookup = [];
6125 this._siblings = [];
6126 for (i = 0; i < targets.length; i++) {
6129 targets.splice(i--, 1);
6131 } else if (typeof(targ) === "string") {
6132 targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
6133 if (typeof(targ) === "string") {
6134 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
6137 } 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 <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself.
6138 targets.splice(i--, 1);
6139 this._targets = targets = targets.concat(_slice.call(targ, 0));
6142 this._siblings[i] = _register(targ, this, false);
6143 if (overwrite === 1) if (this._siblings[i].length > 1) {
6144 _applyOverwrite(targ, this, null, 1, this._siblings[i]);
6149 this._propLookup = {};
6150 this._siblings = _register(target, this, false);
6151 if (overwrite === 1) if (this._siblings.length > 1) {
6152 _applyOverwrite(target, this, null, 1, this._siblings);
6155 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
6156 this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render)
6157 this.render(-this._delay);
6160 _isSelector = function(v) {
6161 return (v.length && v !== window && v[0] && (v[0] === window || (v[0].nodeType && v[0].style && !v.nodeType))); //we cannot check "nodeType" if the target is window from within an iframe, otherwise it will trigger a security error in some browsers like Firefox.
6163 _autoCSS = function(vars, target) {
6167 if (!_reservedProps[p] && (!(p in target) || p === "transform" || p === "x" || p === "y" || p === "width" || p === "height" || p === "className" || p === "border") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties.
6175 p = TweenLite.prototype = new Animation();
6176 p.constructor = TweenLite;
6177 p.kill()._gc = false;
6179 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
6182 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
6183 p._notifyPluginsOfEnabled = p._lazy = false;
6185 TweenLite.version = "1.12.1";
6186 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
6187 TweenLite.defaultOverwrite = "auto";
6188 TweenLite.ticker = _ticker;
6189 TweenLite.autoSleep = true;
6190 TweenLite.lagSmoothing = function(threshold, adjustedLag) {
6191 _ticker.lagSmoothing(threshold, adjustedLag);
6193 TweenLite.selector = window.$ || window.jQuery || function(e) { if (window.$) { TweenLite.selector = window.$; return window.$(e); } return window.document ? window.document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e) : e; };
6195 var _lazyTweens = [],
6197 _internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object.
6198 _plugins = TweenLite._plugins = {},
6199 _tweenLookup = _internals.tweenLookup = {},
6200 _tweenLookupNum = 0,
6201 _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1, lazy:1},
6202 _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
6203 _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
6204 _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
6205 _lazyRender = function() {
6206 var i = _lazyTweens.length;
6210 if (a && a._lazy !== false) {
6211 a.render(a._lazy, false, true);
6215 _lazyTweens.length = 0;
6218 _rootTimeline._startTime = _ticker.time;
6219 _rootFramesTimeline._startTime = _ticker.frame;
6220 _rootTimeline._active = _rootFramesTimeline._active = true;
6221 setTimeout(_lazyRender, 1); //on some mobile devices, there isn't a "tick" before code runs which means any lazy renders wouldn't run before the next official "tick".
6223 Animation._updateRoot = TweenLite.render = function() {
6225 if (_lazyTweens.length) { //if code is run outside of the requestAnimationFrame loop, there may be tweens queued AFTER the engine refreshed, so we need to ensure any pending renders occur before we refresh again.
6228 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
6229 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
6230 if (_lazyTweens.length) {
6233 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
6234 for (p in _tweenLookup) {
6235 a = _tweenLookup[p].tweens;
6242 if (a.length === 0) {
6243 delete _tweenLookup[p];
6246 //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly
6247 p = _rootTimeline._first;
6248 if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
6249 while (p && p._paused) {
6259 _ticker.addEventListener("tick", Animation._updateRoot);
6261 var _register = function(target, tween, scrub) {
6262 var id = target._gsTweenID, a, i;
6263 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
6264 _tweenLookup[id] = {target:target, tweens:[]};
6267 a = _tweenLookup[id].tweens;
6268 a[(i = a.length)] = tween;
6271 if (a[i] === tween) {
6277 return _tweenLookup[id].tweens;
6280 _applyOverwrite = function(target, tween, props, mode, siblings) {
6281 var i, changed, curTween, l;
6282 if (mode === 1 || mode >= 4) {
6283 l = siblings.length;
6284 for (i = 0; i < l; i++) {
6285 if ((curTween = siblings[i]) !== tween) {
6286 if (!curTween._gc) if (curTween._enabled(false, false)) {
6289 } else if (mode === 5) {
6295 //NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example)
6296 var startTime = tween._startTime + _tinyNum,
6299 zeroDur = (tween._duration === 0),
6301 i = siblings.length;
6303 if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
6305 } else if (curTween._timeline !== tween._timeline) {
6306 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
6307 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
6308 overlaps[oCount++] = curTween;
6310 } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
6311 overlaps[oCount++] = curTween;
6317 curTween = overlaps[i];
6318 if (mode === 2) if (curTween._kill(props, target)) {
6321 if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
6322 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
6330 _checkOverlap = function(tween, reference, zeroDur) {
6331 var tl = tween._timeline,
6333 t = tween._startTime;
6334 while (tl._timeline) {
6336 ts *= tl._timeScale;
6343 return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * _tinyNum)) ? _tinyNum : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + _tinyNum) ? 0 : t - reference - _tinyNum;
6347 //---- TweenLite instance methods -----------------------------------------------------------------------------
6349 p._init = function() {
6351 op = this._overwrittenProps,
6352 dur = this._duration,
6353 immediate = !!v.immediateRender,
6355 i, initPlugins, pt, p, startVars;
6357 if (this._startAt) {
6358 this._startAt.render(-1, true); //if we've run a startAt previously (when the tween instantiated), we should revert it so that the values re-instantiate correctly particularly for relative tweens. Without this, a TweenLite.fromTo(obj, 1, {x:"+=100"}, {x:"-=100"}), for example, would actually jump to +=200 because the startAt would run twice, doubling the relative change.
6359 this._startAt.kill();
6362 for (p in v.startAt) { //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, 1, from, to).fromTo(e, 1, to, from);
6363 startVars[p] = v.startAt[p];
6365 startVars.overwrite = false;
6366 startVars.immediateRender = true;
6367 startVars.lazy = (immediate && v.lazy !== false);
6368 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
6369 this._startAt = TweenLite.to(this.target, 0, startVars);
6371 if (this._time > 0) {
6372 this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()).
6373 } else if (dur !== 0) {
6374 return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.
6377 } else if (v.runBackwards && dur !== 0) {
6378 //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)
6379 if (this._startAt) {
6380 this._startAt.render(-1, true);
6381 this._startAt.kill();
6382 this._startAt = null;
6385 for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through.
6386 if (!_reservedProps[p] || p === "autoCSS") {
6391 pt.data = "isFromStart"; //we tag the tween with as "isFromStart" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a "from()" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in.
6392 pt.lazy = (immediate && v.lazy !== false);
6393 pt.immediateRender = immediate; //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after)
6394 this._startAt = TweenLite.to(this.target, 0, pt);
6396 this._startAt._init(); //ensures that the initial values are recorded
6397 this._startAt._enabled(false); //no need to have the tween render on the next cycle. Disable it because we'll always manually control the renders of the _startAt tween.
6398 } else if (this._time === 0) {
6404 this._ease = TweenLite.defaultEase;
6405 } else if (ease instanceof Ease) {
6406 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
6408 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
6410 this._easeType = this._ease._type;
6411 this._easePower = this._ease._power;
6412 this._firstPT = null;
6414 if (this._targets) {
6415 i = this._targets.length;
6417 if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
6422 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
6426 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
6428 if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live.
6429 this._enabled(false, false);
6431 if (v.runBackwards) {
6439 this._onUpdate = v.onUpdate;
6440 this._initted = true;
6443 p._initProps = function(target, propLookup, siblings, overwrittenProps) {
6444 var p, i, initPlugins, plugin, pt, v;
6445 if (target == null) {
6449 if (_lazyLookup[target._gsTweenID]) {
6450 _lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end)
6453 if (!this.vars.css) if (target.style) if (target !== window && target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity). Note: we cannot check "nodeType" on the window inside an iframe.
6454 _autoCSS(this.vars, target);
6456 for (p in this.vars) {
6458 if (_reservedProps[p]) {
6459 if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
6460 this.vars[p] = v = this._swapSelfInParams(v, this);
6463 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
6465 //t - target [object]
6466 //p - property [string]
6467 //s - start [number]
6468 //c - change [number]
6469 //f - isFunction [boolean]
6471 //pg - isPlugin [boolean]
6472 //pr - priority [number]
6473 this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
6474 i = plugin._overwriteProps.length;
6476 propLookup[plugin._overwriteProps[i]] = this._firstPT;
6478 if (plugin._priority || plugin._onInitAllProps) {
6481 if (plugin._onDisable || plugin._onEnable) {
6482 this._notifyPluginsOfEnabled = true;
6486 this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
6487 pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
6488 pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
6490 if (pt) if (pt._next) {
6491 pt._next._prev = pt;
6495 if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first)
6496 return this._initProps(target, propLookup, siblings, overwrittenProps);
6498 if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
6499 this._kill(propLookup, target);
6500 return this._initProps(target, propLookup, siblings, overwrittenProps);
6502 if (this._firstPT) if ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration)) { //zero duration tweens don't lazy render by default; everything else does.
6503 _lazyLookup[target._gsTweenID] = true;
6508 p.render = function(time, suppressEvents, force) {
6509 var prevTime = this._time,
6510 duration = this._duration,
6511 prevRawPrevTime = this._rawPrevTime,
6512 isComplete, callback, pt, rawPrevTime;
6513 if (time >= duration) {
6514 this._totalTime = this._time = duration;
6515 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
6516 if (!this._reversed ) {
6518 callback = "onComplete";
6520 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
6521 if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate.
6524 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
6526 if (prevRawPrevTime > _tinyNum) {
6527 callback = "onReverseComplete";
6530 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
6533 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
6534 this._totalTime = this._time = 0;
6535 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
6536 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
6537 callback = "onReverseComplete";
6538 isComplete = this._reversed;
6541 this._active = false;
6542 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
6543 if (prevRawPrevTime >= 0) {
6546 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
6548 } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
6552 this._totalTime = this._time = time;
6554 if (this._easeType) {
6555 var r = time / duration, type = this._easeType, pow = this._easePower;
6556 if (type === 1 || (type === 3 && r >= 0.5)) {
6564 } else if (pow === 2) {
6566 } else if (pow === 3) {
6568 } else if (pow === 4) {
6574 } else if (type === 2) {
6576 } else if (time / duration < 0.5) {
6579 this.ratio = 1 - (r / 2);
6583 this.ratio = this._ease.getRatio(time / duration);
6587 if (this._time === prevTime && !force) {
6589 } else if (!this._initted) {
6591 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example.
6593 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
6594 this._time = this._totalTime = prevTime;
6595 this._rawPrevTime = prevRawPrevTime;
6596 _lazyTweens.push(this);
6600 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
6601 if (this._time && !isComplete) {
6602 this.ratio = this._ease.getRatio(this._time / duration);
6603 } else if (isComplete && this._ease._calcEnd) {
6604 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
6607 if (this._lazy !== false) { //in case a lazy render is pending, we should flush it because the new render is occuring now (imagine a lazy tween instantiating and then immediately the user calls tween.seek(tween.duration()), skipping to the end - the end render would be forced, and then if we didn't flush the lazy render, it'd fire AFTER the seek(), rendering it at the wrong time.
6610 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
6611 this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
6613 if (prevTime === 0) {
6614 if (this._startAt) {
6616 this._startAt.render(time, suppressEvents, force);
6617 } else if (!callback) {
6618 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
6621 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
6622 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
6629 pt.t[pt.p](pt.c * this.ratio + pt.s);
6631 pt.t[pt.p] = pt.c * this.ratio + pt.s;
6636 if (this._onUpdate) {
6637 if (time < 0) if (this._startAt && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
6638 this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
6640 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
6641 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
6645 if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
6646 if (time < 0 && this._startAt && !this._onUpdate && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
6647 this._startAt.render(time, suppressEvents, force);
6650 if (this._timeline.autoRemoveChildren) {
6651 this._enabled(false, false);
6653 this._active = false;
6655 if (!suppressEvents && this.vars[callback]) {
6656 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
6658 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless.
6659 this._rawPrevTime = 0;
6665 p._kill = function(vars, target) {
6666 if (vars === "all") {
6669 if (vars == null) if (target == null || target === this.target) {
6671 return this._enabled(false, false);
6673 target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
6674 var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
6675 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
6678 if (this._kill(vars, target[i])) {
6683 if (this._targets) {
6684 i = this._targets.length;
6686 if (target === this._targets[i]) {
6687 propLookup = this._propLookup[i] || {};
6688 this._overwrittenProps = this._overwrittenProps || [];
6689 overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
6693 } else if (target !== this.target) {
6696 propLookup = this._propLookup;
6697 overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
6701 killProps = vars || propLookup;
6702 record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (typeof(vars) !== "object" || !vars._tempKill)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin)
6703 for (p in killProps) {
6704 if ((pt = propLookup[p])) {
6705 if (pt.pg && pt.t._kill(killProps)) {
6706 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
6708 if (!pt.pg || pt.t._overwriteProps.length === 0) {
6710 pt._prev._next = pt._next;
6711 } else if (pt === this._firstPT) {
6712 this._firstPT = pt._next;
6715 pt._next._prev = pt._prev;
6717 pt._next = pt._prev = null;
6719 delete propLookup[p];
6722 overwrittenProps[p] = 1;
6725 if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.
6726 this._enabled(false, false);
6733 p.invalidate = function() {
6734 if (this._notifyPluginsOfEnabled) {
6735 TweenLite._onPluginEvent("_onDisable", this);
6737 this._firstPT = null;
6738 this._overwrittenProps = null;
6739 this._onUpdate = null;
6740 this._startAt = null;
6741 this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
6742 this._propLookup = (this._targets) ? {} : [];
6746 p._enabled = function(enabled, ignoreTimeline) {
6747 if (!_tickerActive) {
6750 if (enabled && this._gc) {
6751 var targets = this._targets,
6756 this._siblings[i] = _register(targets[i], this, true);
6759 this._siblings = _register(this.target, this, true);
6762 Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
6763 if (this._notifyPluginsOfEnabled) if (this._firstPT) {
6764 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
6770 //----TweenLite static methods -----------------------------------------------------
6772 TweenLite.to = function(target, duration, vars) {
6773 return new TweenLite(target, duration, vars);
6776 TweenLite.from = function(target, duration, vars) {
6777 vars.runBackwards = true;
6778 vars.immediateRender = (vars.immediateRender != false);
6779 return new TweenLite(target, duration, vars);
6782 TweenLite.fromTo = function(target, duration, fromVars, toVars) {
6783 toVars.startAt = fromVars;
6784 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
6785 return new TweenLite(target, duration, toVars);
6788 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
6789 return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
6792 TweenLite.set = function(target, vars) {
6793 return new TweenLite(target, 0, vars);
6796 TweenLite.getTweensOf = function(target, onlyActive) {
6797 if (target == null) { return []; }
6798 target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
6800 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
6804 a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
6807 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
6818 a = _register(target).concat();
6821 if (a[i]._gc || (onlyActive && !a[i].isActive())) {
6829 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
6830 if (typeof(onlyActive) === "object") {
6831 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
6834 var a = TweenLite.getTweensOf(target, onlyActive),
6837 a[i]._kill(vars, target);
6844 * ----------------------------------------------------------------
6845 * TweenPlugin (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another <script> call before loading plugins which is easy to forget)
6846 * ----------------------------------------------------------------
6848 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
6849 this._overwriteProps = (props || "").split(",");
6850 this._propName = this._overwriteProps[0];
6851 this._priority = priority || 0;
6852 this._super = TweenPlugin.prototype;
6855 p = TweenPlugin.prototype;
6856 TweenPlugin.version = "1.10.1";
6857 TweenPlugin.API = 2;
6860 p._addTween = function(target, prop, start, end, overwriteProp, round) {
6862 if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
6863 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
6865 pt._next._prev = pt;
6871 p.setRatio = function(v) {
6872 var pt = this._firstPT,
6876 val = pt.c * v + pt.s;
6878 val = Math.round(val);
6879 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
6891 p._kill = function(lookup) {
6892 var a = this._overwriteProps,
6895 if (lookup[this._propName] != null) {
6896 this._overwriteProps = [];
6900 if (lookup[a[i]] != null) {
6906 if (lookup[pt.n] != null) {
6908 pt._next._prev = pt._prev;
6911 pt._prev._next = pt._next;
6913 } else if (this._firstPT === pt) {
6914 this._firstPT = pt._next;
6922 p._roundProps = function(lookup, value) {
6923 var pt = this._firstPT;
6925 if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here.
6932 TweenLite._onPluginEvent = function(type, tween) {
6933 var pt = tween._firstPT,
6934 changed, pt2, first, last, next;
6935 if (type === "_onInitAllProps") {
6936 //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame.
6940 while (pt2 && pt2.pr > pt.pr) {
6943 if ((pt._prev = pt2 ? pt2._prev : last)) {
6944 pt._prev._next = pt;
6948 if ((pt._next = pt2)) {
6955 pt = tween._firstPT = first;
6958 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
6966 TweenPlugin.activate = function(plugins) {
6967 var i = plugins.length;
6969 if (plugins[i].API === TweenPlugin.API) {
6970 _plugins[(new plugins[i]())._propName] = plugins[i];
6976 //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations.
6977 _gsDefine.plugin = function(config) {
6978 if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
6979 var propName = config.propName,
6980 priority = config.priority || 0,
6981 overwriteProps = config.overwriteProps,
6982 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
6983 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
6985 TweenPlugin.call(this, propName, priority);
6986 this._overwriteProps = overwriteProps || [];
6987 }, (config.global === true)),
6988 p = Plugin.prototype = new TweenPlugin(propName),
6990 p.constructor = Plugin;
6991 Plugin.API = config.API;
6993 if (typeof(config[prop]) === "function") {
6994 p[map[prop]] = config[prop];
6997 Plugin.version = config.version;
6998 TweenPlugin.activate([Plugin]);
7003 //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you.
7004 a = window._gsQueue;
7006 for (i = 0; i < a.length; i++) {
7009 for (p in _defLookup) {
7010 if (!_defLookup[p].func) {
7011 //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
7016 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
7020 angular.module('att.abs.transition', [])
7022 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
7024 var $transition = function(element, trigger, options) {
7025 options = options || {};
7026 var deferred = $q.defer();
7027 var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
7029 var transitionEndHandler = function() {
7030 $rootScope.$apply(function() {
7031 element.unbind(endEventName, transitionEndHandler);
7032 deferred.resolve(element);
7037 element.bind(endEventName, transitionEndHandler);
7040 // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
7041 $timeout(function() {
7042 if ( angular.isString(trigger) ) {
7043 element.addClass(trigger);
7044 } else if ( angular.isFunction(trigger) ) {
7046 } else if ( angular.isObject(trigger) ) {
7047 element.css(trigger);
7049 //If browser does not support transitions, instantly resolve
7050 if ( !endEventName ) {
7051 deferred.resolve(element);
7055 // Add our custom cancel function to the promise that is returned
7056 // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
7057 // i.e. it will therefore never raise a transitionEnd event for that transition
7058 deferred.promise.cancel = function() {
7059 if ( endEventName ) {
7060 element.unbind(endEventName, transitionEndHandler);
7062 deferred.reject('Transition cancelled');
7065 return deferred.promise;
7068 // Work out the name of the transitionEnd event
7069 var transElement = document.createElement('trans');
7070 var transitionEndEventNames = {
7071 'WebkitTransition': 'webkitTransitionEnd',
7072 'MozTransition': 'transitionend',
7073 'OTransition': 'oTransitionEnd',
7074 'transition': 'transitionend'
7076 var animationEndEventNames = {
7077 'WebkitTransition': 'webkitAnimationEnd',
7078 'MozTransition': 'animationend',
7079 'OTransition': 'oAnimationEnd',
7080 'transition': 'animationend'
7082 function findEndEventName(endEventNames) {
7083 for (var name in endEventNames){
7084 if (transElement.style[name] !== undefined) {
7085 return endEventNames[name];
7089 $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
7090 $transition.animationEndEventName = findEndEventName(animationEndEventNames);
7094 .factory('$scrollTo', ['$window', function($window) {
7095 var $scrollTo = function(offsetLeft, offsetTop, duration) {
7096 TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
7100 .factory('animation', function(){
7103 .factory('$progressBar', function(){
7105 //Provides a function to pass in code for closure purposes
7106 var loadingAnimationCreator = function(onUpdateCallback){
7108 //Use closure to setup some resuable code
7109 var loadingAnimation = function(callback, duration){
7110 TweenMax.to({}, duration, {
7111 onUpdateParams: ["{self}"],
7112 onUpdate: onUpdateCallback,
7113 onComplete: callback
7116 //Returns a function that takes a callback function and a duration for the animation
7118 return loadingAnimation;
7122 return loadingAnimationCreator;
7124 .factory('$height', function(){
7125 var heightAnimation = function(element,duration,height,alpha){
7126 TweenMax.to(element,
7128 {height:height, autoAlpha:alpha},
7131 return heightAnimation;
7133 angular.module('att.abs.accordion', ['att.abs.position', 'att.abs.transition'])
7134 .constant('accordionConfig', {
7136 }).controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', '$log',
7137 function ($scope, $attrs, accordionConfig, $log) {
7138 // This array keeps track of the accordion groups
7141 // Keep reference to user's scope to properly assign `is-open`
7142 this.scope = $scope;
7143 $scope.forceExpand = false;
7144 // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
7145 this.closeOthers = function (openGroup) {
7146 var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
7147 if (closeOthers && !$scope.forceExpand) {
7148 angular.forEach(this.groups, function (group) {
7149 if (group !== openGroup) {
7150 group.isOpen = false;
7154 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {
7155 $scope.forceExpand = false;
7158 this.expandAll = function () {
7159 $scope.forceExpand = true;
7160 angular.forEach(this.groups, function (group) {
7161 group.isOpen = true;
7164 this.collapseAll = function () {
7165 angular.forEach(this.groups, function (group) {
7166 group.isOpen = false;
7169 /**function focus @param focusGroup */
7170 this.focus = function (focusGroup) {
7172 angular.forEach(this.groups, function (group, index) {
7173 if (group !== focusGroup) {
7174 group.focused = false;
7177 group.focused = true;
7181 /** @param blurGroup*/
7182 this.blur = function (blurGroup) {
7183 blurGroup.focused = false;
7185 $log.log("accordion.blur()", blurGroup);
7187 /** @param group - the group in current focus @param down - cycling down */
7188 this.cycle = function (group, down, noRecycle) {
7190 if (this.index <= 0 && !noRecycle) {
7191 this.index = this.groups.length - 1;
7196 if (this.index === (this.groups.length - 1))
7200 group.focused = false;
7213 group.focused = false;
7214 this.groups[this.index].setFocus = true;
7215 this.groups[this.index].focused = true;
7218 // This is called from the accordion-group directive to add itself to the accordion
7219 this.addGroup = function (groupScope) {
7221 groupScope.index = this.groups.length;
7222 groupScope.focused = false;
7223 this.groups.push(groupScope);
7225 if(this.groups.length > 0){
7229 groupScope.$on('$destroy', function () {
7230 that.removeGroup(groupScope);
7233 // This is called from the accordion-group directive when to remove itself
7234 this.removeGroup = function (group) {
7235 var index = this.groups.indexOf(group);
7237 this.groups.splice(this.groups.indexOf(group), 1);
7241 // The accordion directive simply sets up the directive controller and adds an accordion CSS class to itself element.
7242 .directive('accordion', function () {
7245 controller: 'AccordionController',
7253 template: '<div class="{{cClass}}" ng-transclude></div>',
7254 link: function (scope, elem, attribute, ctrl) {
7255 scope.$watch("expandAll", function (value) {
7258 scope.expandAll = false;
7261 scope.$watch("collapseAll", function (value) {
7264 scope.collapseAll = false;
7270 // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
7271 .directive('accordionGroup', ['$parse', '$transition', '$scrollTo', '$timeout', '$log', function ($parse, $transition, $scrollTo, $timeout, $log) {
7273 // We need this directive to be inside an accordion
7274 require: ['^accordion', 'accordionGroup'],
7276 // It transcludes the contents of the directive into the template
7278 // The element containing the directive will be replaced with the template
7280 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/accordion.html',
7282 // Create an isolated scope and interpolate the heading attribute onto this scope
7286 controller: ['$scope', function ($scope)
7288 $scope.showico = true;
7289 this.setHeading = function (element)
7291 this.heading = element;
7292 $scope.showico = false;
7294 this.isIsOpen = function ()
7296 return $scope.isOpen;
7299 link: function (scope, element, attrs, ctrl) {
7300 var accordionCtrl = ctrl[0];
7301 var accordionGroupCtrl = ctrl[1];
7302 var keys = {tab: 9, enter: 13, esc: 27, space: 32, pageup: 33, pagedown: 34, end: 35, home: 36, left: 37, up: 38, right: 39, down: 40};
7304 var tab = element.children().eq(0);
7306 scope.setFocus = false;
7308 var handleKeydown = function (ev) {
7309 var boolFlag = true;
7313 ev.preventDefault();
7319 ev.preventDefault();
7320 accordionCtrl.cycle(scope, false);
7324 ev.preventDefault();
7325 accordionCtrl.cycle(scope, true);
7331 ev.stopPropagation();
7335 if (angular.isUndefined(scope.isOpen)) {
7336 scope.isOpen = false;
7339 tab.bind("keydown", handleKeydown);
7341 accordionCtrl.addGroup(scope);
7343 if (scope.index === 0) {
7344 scope.focused = true;
7347 accordionGroupCtrl.toggle = scope.toggle = function () {
7348 scope.isOpen = !scope.isOpen;
7349 accordionCtrl.focus(scope);
7350 return scope.isOpen;
7353 scope.$watch('isOpen', function (value) {
7355 accordionCtrl.closeOthers(scope);
7359 scope.$watch("focused", function (value) {
7361 tab.attr("tabindex", "0");
7367 scope.setFocus = false;
7368 tab.attr("tabindex", "-1");
7374 // Use accordion-heading below an accordion-group to provide a heading containing HTML
7375 // <accordion-group>
7376 // <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
7377 // </accordion-group>
7378 .directive('accordionToggle', function () {
7381 require: '^accordionGroup',
7386 link: function (scope, element, attr, accordionCtrl)
7388 var setIcon = function (isOpen) {
7389 if (scope.expandIcon && scope.collapseIcon)
7392 element.removeClass(scope.expandIcon);
7393 element.addClass(scope.collapseIcon);
7396 element.removeClass(scope.collapseIcon);
7397 element.addClass(scope.expandIcon);
7401 element.bind('click', function ()
7403 accordionCtrl.toggle();
7406 scope.$watch(function () {
7407 return accordionCtrl.isIsOpen();
7408 }, function (value) {
7413 }).directive('accordionHeading', function () {
7418 require: '^accordionGroup',
7419 compile: function (element, attr, transclude) {
7420 var link = function (scope, element, attr, accordionGroupCtrl) {
7421 // Pass the heading to the accordion-group controller
7422 // so that it can be transcluded into the right place in the template
7423 // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
7424 transclude(scope, function (clone) {
7425 element.append(clone);
7426 accordionGroupCtrl.setHeading(element);
7433 // Use in the accordion-group template to indicate where you want the heading to be transcluded
7434 // You must provide the property on the accordion-group controller that will hold the transcluded element
7435 .directive('accordionTransclude', function () {
7437 require: '^accordionGroup',
7438 link: function (scope, element, attr, controller) {
7439 scope.$watch(function () {
7440 return controller[attr.accordionTransclude];
7441 }, function (heading) {
7443 element.find("span").eq(0).prepend(heading);
7449 .directive('attGoTop', ['$scrollTo', function ($scrollTo) {
7453 link: function (scope, elem, attrs)
7455 elem.bind('click', function ()
7457 $scrollTo(0, attrs["attGoTop"]);
7462 .directive('attGoTo', ['$anchorScroll', '$location', function ($anchorScroll, $location) {
7466 link: function (scope, elem, attrs)
7468 elem.bind('click', function ()
7470 var newHash = attrs["attGoTo"];
7471 if ($location.hash() !== newHash)
7473 $location.hash(attrs["attGoTo"]);
7483 .directive('freeStanding', function () {
7489 template: "<div><span class='att-accordion__freestanding' ng-show='showAccordion'></span>\n" +
7490 "<div class='section-toggle'>\n" +
7491 "<button class='section-toggle__button' ng-click='fsToggle()'>\n" +
7492 " {{btnText}}<i style='font-size:0.875rem' ng-class='{\"icon-chevron-up\": showAccordion,\"icon-chevron-down\": !showAccordion, }'></i> \n" +
7495 compile: function (element, attr, transclude)
7497 var link = function (scope, elem, attrs) {
7499 transclude(scope, function (clone)
7501 elem.find("span").append(clone);
7503 scope.showAccordion = false;
7504 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
7505 scope.fsToggle = function ()
7507 scope.showAccordion = !scope.showAccordion;
7508 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
7514 }).directive('expanders', function () {
7519 template: "<div ng-transclude></div>",
7520 controller: [function () {
7521 var bodyScope = null;
7522 this.setScope = function (scope) {
7525 this.toggle = function () {
7526 bodyScope.isOpen = !bodyScope.isOpen;
7527 return bodyScope.isOpen;
7530 link: function (scope, element)
7532 scope.isOpen = false;
7533 element.bind('click', function ()
7535 scope.isOpen = !scope.isOpen;
7539 }).directive('expanderHeading', function () {
7541 require: "^expanders",
7546 template: "<div style='padding:10px !important' ng-transclude></div>"
7548 }).directive('expanderBody', function () {
7551 require: "^expanders",
7555 template: "<div collapse='!isOpen'><div ng-transclude></div></div>",
7556 link: function (scope, elem, attr, myCtrl) {
7557 scope.isOpen = false;
7558 myCtrl.setScope(scope);
7561 }).directive('expanderToggle', function () {
7564 require: "^expanders",
7569 link: function (scope, element, attr, myCtrl)
7572 var setIcon = function () {
7573 if (scope.expandIcon && scope.collapseIcon)
7576 element.removeClass(scope.expandIcon);
7577 element.addClass(scope.collapseIcon);
7580 element.removeClass(scope.collapseIcon);
7581 element.addClass(scope.expandIcon);
7585 element.bind("keydown", function (e) {
7586 if (e.keyCode === 13)
7591 element.bind('click', function ()
7595 scope.toggleit = function ()
7597 isOpen = myCtrl.toggle();
7604 }).directive('collapse', ['$transition', function ($transition) {
7605 // CSS transitions don't work with height: auto, so we have to manually change the height to a
7606 // specific value and then once the animation completes, we can reset the height to auto.
7607 // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
7608 // "collapse") then you trigger a change to height 0 in between.
7609 // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
7615 paddingBottom: null,
7626 var fixUpHeight = function (scope, element, height) {
7627 // We remove the collapse CSS class to prevent a transition when we change to height: auto
7628 element.removeClass('collapse');
7629 element.css({height: height});
7630 //adjusting for any margin or padding
7632 element.css(props.closed);
7634 element.css(props.open);
7636 // It appears that reading offsetWidth makes the browser realise that we have changed the
7637 // height already :-/
7638 element.addClass('collapse');
7641 link: function (scope, element, attrs) {
7643 var initialAnimSkip = true;
7644 scope.$watch(function () {
7645 return element[0].scrollHeight;
7647 //The listener is called when scrollHeight changes
7648 //It actually does on 2 scenarios:
7649 // 1. Parent is set to display none
7650 // 2. angular bindings inside are resolved
7651 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
7652 if (element[0].scrollHeight !== 0 && !isCollapsed) {
7653 if (initialAnimSkip) {
7654 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
7656 fixUpHeight(scope, element, 'auto');
7660 var currentTransition;
7661 var doTransition = function (change) {
7662 if (currentTransition) {
7663 currentTransition.cancel();
7665 currentTransition = $transition(element, change);
7666 currentTransition.then(
7668 currentTransition = undefined;
7671 currentTransition = undefined;
7674 return currentTransition;
7676 var expand = function () {
7677 scope.postTransition = true;
7678 if (initialAnimSkip) {
7679 initialAnimSkip = false;
7681 fixUpHeight(scope, element, 'auto');
7684 doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
7686 // This check ensures that we don't accidentally update the height if the user has closed
7687 // the group while the animation was still running
7690 fixUpHeight(scope, element, 'auto');
7694 isCollapsed = false;
7696 var collapse = function () {
7698 if (initialAnimSkip) {
7699 initialAnimSkip = false;
7700 fixUpHeight(scope, element, 0);
7702 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
7703 doTransition(angular.extend({height: 0}, props.closed)).then(function () {
7704 scope.postTransition = false;
7708 scope.$watch(attrs.collapse, function (value) {
7718 .directive('attAccord', function () {
7724 controller: 'AttAccordCtrl',
7725 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html'
7728 .controller('AttAccordCtrl', [function () {
7729 this.type = 'attAccord';
7733 this.toggleBody = function () {
7738 this.collapseBody();
7742 this.expandBody = function () {
7743 this.bodyCtrl.expand();
7745 this.collapseBody = function () {
7746 this.bodyCtrl.collapse();
7749 .controller('AttAccordHeaderCtrl', [function () {
7750 this.type = 'header';
7752 .directive('attAccordHeader', function () {
7757 require: ['^attAccord', 'attAccordHeader'],
7758 controller: 'AttAccordHeaderCtrl',
7759 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html',
7760 link: function (scope, element, attr, ctrls) {
7761 var attAccordCtrl = ctrls[0];
7762 var attAccordHeaderCtrl = ctrls[1];
7763 attAccordCtrl.headerCtrl = attAccordHeaderCtrl;
7764 scope.clickFunc = function () {
7765 attAccordCtrl.toggleBody();
7770 .controller('AttAccordBodyCtrl', ['$scope', function ($scope) {
7772 this.expand = function () {
7775 this.collapse = function () {
7779 .directive('attAccordBody', ['$timeout', '$height', function ($timeout, $height) {
7784 require: ['^attAccord', 'attAccordBody'],
7785 controller: 'AttAccordBodyCtrl',
7786 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordBody.html',
7787 link: function (scope, element, attr, ctrls) {
7788 var attAccordCtrl = ctrls[0];
7789 var attAccordBodyCtrl = ctrls[1];
7790 attAccordCtrl.bodyCtrl = attAccordBodyCtrl;
7792 $timeout(function () {
7793 originalHeight = element[0].offsetHeight;
7794 $height(element, 0, 0, 0);
7796 scope.expand = function () {
7797 $height(element, 0.05, originalHeight, 1);
7799 scope.collapse = function () {
7800 $height(element, 0.25, 0, 0);
7805 angular.module('att.abs.alert', [])
7806 .directive('attAlert', [function()
7813 alertType : "@type",
7814 showTop : "@topPos",
7817 templateUrl : 'app/scripts/ng_js_att_tpls/alert/alert.html',
7818 link: function(scope)
7820 if(scope.showTop === 'true'){
7821 scope.cssStyle = {'top':'50px'};
7824 scope.cssStyle = {'top':'0px'};
7826 scope.close = function(){
7827 scope.showAlert = false;
7833 angular.module('att.abs.breadCrumbs', [])
7834 .constant("classConstant",{
7835 "defaultClass" : "breadcrumbs__link",
7836 "activeClass": "breadcrumbs__link--active"
7838 .directive('attCrumb', ['classConstant', function(classConstant) {
7841 link: function(scope, elem, attr) {
7842 elem.addClass(classConstant.defaultClass);
7843 if(attr.attCrumb === 'active'){
7844 elem.addClass(classConstant.activeClass);
7846 if(!elem.hasClass('last')){
7847 elem.after('<i class="breadcrumbs__item"></i>');
7853 angular.module('att.abs.utilities', [])
7855 .filter('unsafe',[ '$sce', function ($sce) {
7856 return function(val){
7857 return $sce.trustAsHtml(val);
7861 .filter('highlight', function () {
7862 function escapeRegexp(queryToEscape) {
7863 return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
7865 return function (matchItem, query, className) {
7866 return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
7870 .filter('attLimitTo', function() {
7871 return function(actualArray, _limit, _begin) {
7872 var finalArray = [];
7878 if(actualArray && !isNaN(limit)) {
7879 finalArray = actualArray.slice(begin, begin+limit);
7881 finalArray = actualArray;
7887 .filter('startsWith', function() {
7888 if (typeof String.prototype.startsWith !== 'function') {
7889 // see below for better implementation!
7890 String.prototype.startsWith = function (str){
7891 return this.indexOf(str) === 0;
7895 return function(items, searchString) {
7896 if (searchString === undefined || searchString === "") {
7901 angular.forEach(items, function(item) {
7902 if (item.title.toLowerCase().startsWith(searchString.toLowerCase())) {
7903 filtered.push(item);
7910 .directive('attInputDeny', [function() {
7914 link: function (scope, elem, attr, ctrl) {
7915 var regexExpression = null;
7916 attr.$observe('attInputDeny', function (value) {
7918 regexExpression = new RegExp(value, 'g');
7921 elem.bind('input', function () {
7922 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
7923 if (inputString !== ctrl.$viewValue) {
7924 ctrl.$setViewValue(inputString);
7933 .directive('attAccessibilityClick', [function() {
7936 link: function (scope, elem, attr) {
7938 attr.$observe('attAccessibilityClick', function (value) {
7940 keyCode = value.split(',');
7943 elem.bind('keydown', function (ev) {
7944 var keyCodeCondition = function(){
7948 ev.keyCode = ev.which;
7950 else if(ev.charCode){
7951 ev.keyCode = ev.charCode;
7954 if((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)){
7959 if(keyCode.length > 0 && keyCodeCondition()) {
7961 ev.preventDefault();
7966 }]).directive('attElementFocus', [function() {
7969 link: function(scope, elem, attr) {
7970 scope.$watch(attr.attElementFocus, function (value) {
7979 .factory('events', function(){
7980 var s = function(e){
7981 if(e.stopPropagation) {
7982 e.stopPropagation();
7984 e.returnValue = false;
7992 .factory('$documentBind', ['$document', '$timeout', function($document, $timeout) {
7993 var _click = function (flag, callbackFunc, scope) {
7994 scope.$watch(flag, function (val) {
7995 $timeout(function () {
7997 $document.bind('click', callbackFunc);
7999 $document.unbind('click', callbackFunc);
8010 .factory('keymap', function(){
8032 MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'"
8034 isControl: function (e) {
8037 case this.KEY.COMMAND:
8038 case this.KEY.SHIFT:
8051 isFunctionKey: function (k) {
8052 k = k.keyCode ? k.keyCode : k;
8053 return k >= 112 && k <= 123;
8055 isVerticalMovement: function (k){
8056 return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
8058 isHorizontalMovement: function (k){
8059 return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
8061 isAllowedKey: function (k){
8062 return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
8069 String.prototype.toSnakeCase = function () {
8070 return this.replace(/([A-Z])/g, function ($1) {
8071 return "-" + $1.toLowerCase();
8074 var concat = function (character, times) {
8075 character = character || '';
8076 times = (!isNaN(times) && times) || 0;
8078 for (var i = 0; i < times; i++) {
8079 finalChar += character;
8084 // direction: true for left and false for right
8085 var pad = function (actualString, width, character, direction) {
8086 actualString = actualString || '';
8087 width = (!isNaN(width) && width) || 0;
8088 character = character || '';
8089 direction = (direction !== undefined && direction) || true;
8090 if (width > actualString.length) {
8092 return concat(character, (width - actualString.length)) + actualString;
8094 return actualString + concat(character, (width - actualString.length));
8097 return actualString;
8100 String.prototype.lPad = function (width, character) {
8101 return pad(this, width, character, true);
8104 String.prototype.rPad = function (width, character) {
8105 return pad(this, width, character, false);
8108 if (!Array.prototype.indexOf) {
8109 Array.prototype.indexOf = function (val) {
8110 for (var index = 0; index < this.length; index++) {
8111 if (this[index] === val) {
8120 angular.module('att.abs.buttons', ['att.abs.position', 'att.abs.utilities'])
8121 .constant('btnConfig', {
8123 btnPrimaryClass: 'button--primary',
8124 btnSecondaryClass: 'button--secondary',
8125 btnDisabledClass: 'button--inactive',
8126 btnSmallClass: 'button--small'
8128 .directive('attButton', ['btnConfig', function (btnConfig) {
8131 link: function (scope, element, attrs) {
8132 element.addClass(btnConfig.btnClass);
8133 if (attrs.size === 'small') {
8134 element.addClass(btnConfig.btnSmallClass);
8136 attrs.$observe('btnType', function (value) {
8137 if (value === 'primary') {
8138 element.addClass(btnConfig.btnPrimaryClass);
8139 element.removeClass(btnConfig.btnSecondaryClass);
8140 element.removeClass(btnConfig.btnDisabledClass);
8141 element.removeAttr('disabled');
8142 } else if (value === 'secondary') {
8143 element.addClass(btnConfig.btnSecondaryClass);
8144 element.removeClass(btnConfig.btnPrimaryClass);
8145 element.removeClass(btnConfig.btnDisabledClass);
8146 element.removeAttr('disabled');
8147 } else if (value === 'disabled') {
8148 element.addClass(btnConfig.btnDisabledClass);
8149 element.removeClass(btnConfig.btnPrimaryClass);
8150 element.removeClass(btnConfig.btnSecondaryClass);
8151 element.attr('disabled', 'disabled');
8157 .directive('attButtonLoader', [function () {
8164 template: '<div ng-class="{\'button--loading\': size === \'large\',\'button--loading__small\': size === \'small\'}"><i></i><i></i><i></i></div>',
8165 link: function (scope, element) {
8166 element.addClass('button button--inactive');
8170 .directive('attButtonHero', [function () {
8178 template: '<div class="button--hero__inner"><span ng-transclude></span> <i ng-class="{\'icon-arrow-right\': icon === \'arrow-right\',\'icon-cart\': icon === \'cart\'}"></i></div>',
8179 link: function (scope, element) {
8180 element.addClass('button button--hero');
8181 element.attr("tabindex", "0");
8185 .directive('attBtnDropdown', ['$document', '$isElement', '$documentBind', function ($document, $isElement, $documentBind) {
8189 type: "@dropdowntype"
8193 template: '<div class="att-btn-dropdown"> <div class="buttons-dropdown--small btn-group" ng-class="{\'open\': isOpen}" ng-click="toggleDropdown()"> <button class="button button--secondary button--small buttons-dropdown__drop dropdown-toggle ng-isolate-scope" ng-if="type==\'dots\'"> <div class="circle" ng-click="toggleDropdownCircle()"></div> <div class="circle" ng-click="toggleDropdownCircle()"></div> <div class="circle" ng-click="toggleDropdownCircle()"></div> </button> <button class="button button--secondary button--small buttons-dropdown__drop dropdown-toggle ng-isolate-scope actions-title" ng-if="type==\'actions\'"> Actions </button> <ul ng-class="{\'dropdown-menu dots-dropdwn\':type==\'dots\', \'dropdown-menu actions-dropdwn\':type==\'actions\'}" role="menu" ng-transclude></ul></div></div>',
8194 link: function (scope, element) {
8195 scope.isOpen = false;
8196 var toggle = scope.toggle = function (show) {
8197 if (show === undefined || show === '') {
8198 scope.isOpen = !scope.isOpen;
8201 scope.isOpen = show;
8204 scope.toggleDropdownCircle = function () {
8207 scope.toggleDropdown = function () {
8210 var outsideClick = function (e) {
8211 var isElement = $isElement(angular.element(e.target), element, $document);
8217 $documentBind.click('isOpen', outsideClick, scope);
8222 angular.module('att.abs.checkbox', [])
8223 .constant("attCheckboxConfig", {
8224 activeClass : "att-checkbox--on",
8225 disabledClass : "att-checkbox--disabled"
8227 .directive('checkboxLimit', function () {
8235 require:'checkboxLimit',
8236 controller: ['$scope',function($scope)
8239 this.getMaxLimits=function(){
8240 return $scope.limit;
8242 this.setMaxLimits=function(value){
8245 this.maxCheckboxSelected=function(){
8246 $scope.maxSelected();
8249 link: function (scope, element, attribute, ctrl) {
8250 scope.$watch('checkboxLimit', function()
8253 for (var keys in scope.checkboxLimit) {
8254 if (scope.checkboxLimit.hasOwnProperty(keys) && scope.checkboxLimit[keys]) {
8255 countTrue = countTrue + 1;
8258 if(countTrue>=parseInt(scope.selectLimit)){
8259 ctrl.setMaxLimits(false);
8262 ctrl.setMaxLimits(true);
8268 .directive('attCheckbox', ['$compile', "attCheckboxConfig", function ($compile, attCheckboxConfig) {
8272 require: ['ngModel','^?checkboxLimit'],
8273 link: function (scope, element, attribute, ctrl) {
8274 var ngCtrl = ctrl[0];
8275 var checkboxLimitCtrl = ctrl[1];
8276 var parentDiv = $compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope);
8277 element.css({display:'none'});
8278 element.wrap(parentDiv);
8279 element.parent().append('<div class="att-checkbox__indicator"></div>');
8280 element.parent().attr("title", attribute.title);
8281 element.parent().attr("id", attribute.id);
8282 element.removeAttr("id");
8284 ngCtrl.$render = function () {
8285 var selected = ngCtrl.$modelValue ? true : false;
8286 element.parent().toggleClass(attCheckboxConfig.activeClass, selected);
8287 element.parent().attr("aria-checked", selected);
8291 scope.updateModel = function (evt) {
8292 if (!scope.disabled) {
8293 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? false : true);
8294 if(checkboxLimitCtrl && !(checkboxLimitCtrl.getMaxLimits())){
8295 if(!ngCtrl.$modelValue){
8299 checkboxLimitCtrl.maxCheckboxSelected();
8300 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? true : false);
8307 evt.preventDefault();
8310 attribute.$observe('disabled', function(val) {
8311 scope.disabled = (val || val === "disabled" || val === "true");
8312 element.parent().toggleClass(attCheckboxConfig.disabledClass, scope.disabled);
8313 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
8318 .directive('checkboxGroup', ['$compile',function($compile) {
8322 checkboxGroupValue: "=?"
8325 link: function(scope, element, attribute){
8326 scope.checkboxState = 'none';
8327 scope.checkboxGroupValue="indeterminate";
8328 element.css({display:'none'});
8329 element.wrap($compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope));
8330 element.parent().append('<div class="att-checkbox__indicator"></div>');
8331 element.parent().attr("title", attribute.title);
8332 scope.$watch('checkboxState', function(val) {
8333 if (val === 'all') {
8334 element.parent().addClass('att-checkbox--on');
8335 element.parent().removeClass('att-checkbox--indeterminate');
8336 element.parent().attr("aria-checked", true);
8338 else if (val === 'none') {
8339 element.parent().removeClass('att-checkbox--on');
8340 element.parent().removeClass('att-checkbox--indeterminate');
8341 element.parent().attr("aria-checked", false);
8343 else if (val === 'indeterminate') {
8344 element.parent().removeClass('att-checkbox--on');
8345 element.parent().addClass('att-checkbox--indeterminate');
8346 element.parent().attr("aria-checked", true);
8349 scope.updateModel = function(evt){
8350 if (element.parent().hasClass('att-checkbox--on')) {
8351 element.parent().removeClass('att-checkbox--on');
8352 for (var keys in scope.checkboxGroup) {
8353 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8354 scope.checkboxGroup[keys] = false;
8359 element.parent().addClass('att-checkbox--on');
8360 for (var key in scope.checkboxGroup) {
8361 if (scope.checkboxGroup.hasOwnProperty(key)) {
8362 scope.checkboxGroup[key] = true;
8366 evt.preventDefault();
8368 scope.$watch('checkboxGroupValue', function (value) {
8369 if (value==="false") {
8370 element.parent().removeClass('att-checkbox--on');
8371 for (var keys in scope.checkboxGroup) {
8372 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8373 scope.checkboxGroup[keys] = false;
8377 else if (value === "true"){
8378 element.parent().addClass('att-checkbox--on');
8379 for (var key in scope.checkboxGroup) {
8380 if (scope.checkboxGroup.hasOwnProperty(key)) {
8381 scope.checkboxGroup[key] = true;
8386 scope.$watch('checkboxGroup', function(){
8390 for (var keys in scope.checkboxGroup) {
8391 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8393 if (scope.checkboxGroup[keys]) {
8394 countTrue = countTrue + 1;
8396 else if (!scope.checkboxGroup[keys]) {
8397 countFalse = countFalse + 1;
8401 if (count === countTrue) {
8402 scope.checkboxState = "all";
8403 scope.checkboxGroupValue="true";
8405 else if (count === countFalse) {
8406 scope.checkboxState = "none";
8407 scope.checkboxGroupValue="false";
8410 scope.checkboxState = "indeterminate";
8411 scope.checkboxGroupValue="indeterminate";
8418 angular.module('att.abs.colorselector', [])
8419 .directive('colorSelectorWrapper', [function() {
8427 templateUrl: 'app/scripts/ng_js_att_tpls/colorselector/colorselector.html',
8428 link: function(scope) {
8429 scope.applycolor = {'background-color': scope.iconColor};
8430 scope.selectedcolor = function(iconColor) {
8431 scope.selected = iconColor;
8436 .directive('colorSelector', ['$compile', function($compile) {
8443 link: function(scope, element) {
8444 element.removeAttr('color-selector');
8445 var wrapcont = angular.element('<color-selector-wrapper selected="ngModel" icon-color="{{colorSelector}}">' + element.prop('outerHTML') + '</color-selector-wrapper>');
8446 var newWrapcont = $compile(wrapcont)(scope);
8447 element.replaceWith(newWrapcont);
8451 angular.module('att.abs.datepicker', ['att.abs.position', 'att.abs.utilities'])
8453 .constant('datepickerConfig', {
8454 dateFormat: 'MM/dd/yyyy',
8456 monthFormat: 'MMMM',
8458 dayHeaderFormat: 'EEEE',
8459 dayTitleFormat: 'MMMM yyyy',
8460 disableWeekend: false,
8461 disableSunday: false,
8467 defaultText: 'Select from list'
8469 datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'mode'],
8470 datepickerWatchAttributes: ['min', 'max']
8473 .factory('datepickerService', ['datepickerConfig', 'dateFilter', function (datepickerConfig, dateFilter) {
8474 var setAttributes = function (attr, elem) {
8475 if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
8476 var attributes = datepickerConfig.datepickerEvalAttributes.concat(datepickerConfig.datepickerWatchAttributes);
8477 for (var key in attr) {
8478 var val = attr[key];
8479 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8480 elem.attr(key.toSnakeCase(), key);
8486 var bindScope = function (attr, scope) {
8487 if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
8488 var evalFunction = function (key, val) {
8489 scope[key] = scope.$parent.$eval(val);
8492 var watchFunction = function (key, val) {
8493 scope.$parent.$watch(val, function (value) {
8496 scope.$watch(key, function (value) {
8497 scope.$parent[val] = value;
8501 var evalAttributes = datepickerConfig.datepickerEvalAttributes;
8502 var watchAttributes = datepickerConfig.datepickerWatchAttributes;
8503 for (var key in attr) {
8504 var val = attr[key];
8505 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8506 evalFunction(key, val);
8507 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8508 watchFunction(key, val);
8514 var validateDateString = function (dateString, dateFormat) {
8515 if (dateString && dateFormat) {
8517 if (dateFormat.indexOf('/') !== -1) {
8519 } else if (dateFormat.indexOf('-') !== -1) {
8521 } else if (dateFormat.indexOf('.') !== -1) {
8525 var dateStringArray = dateString.split(delimiter);
8526 var dateFormatArray = dateFormat.split(delimiter);
8527 if (dateStringArray.length !== dateFormatArray.length) {
8531 for (var i = 0; i < dateStringArray.length; i++) {
8532 dateStringArray[i] = dateStringArray[i].lPad(dateFormatArray[i].length, '0');
8534 var intermediateDateString = dateStringArray.join(delimiter);
8536 var actualDateString = dateFilter(new Date(intermediateDateString), dateFormat);
8537 if (intermediateDateString === actualDateString) {
8546 setAttributes: setAttributes,
8547 bindScope: bindScope,
8548 validateDateString: validateDateString
8552 .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
8554 date: getValue($attrs.dateFormat, dtConfig.dateFormat),
8555 day: getValue($attrs.dayFormat, dtConfig.dayFormat),
8556 month: getValue($attrs.monthFormat, dtConfig.monthFormat),
8557 year: getValue($attrs.yearFormat, dtConfig.yearFormat),
8558 dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
8559 dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
8560 disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
8561 disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
8563 startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
8564 $scope.mode = getValue($attrs.mode, dtConfig.mode);
8566 $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
8567 $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
8569 function getValue(value, defaultValue) {
8570 return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
8573 function getDaysInMonth(year, month) {
8574 return new Date(year, month, 0).getDate();
8577 function getDates(startDate, n) {
8578 var dates = new Array(n);
8579 var current = startDate, i = 0;
8581 dates[i++] = new Date(current);
8582 current.setDate(current.getDate() + 1);
8587 function isSelected(dt) {
8588 if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
8594 function isFromDate(dt) {
8595 if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
8601 function isToDate(dt) {
8602 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
8608 function isDateRange(dt) {
8609 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
8615 function isWeekend(date) {
8616 if (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday") {
8622 function isToday(date) {
8623 if (compare(date, $scope.resetTime(new Date())) === 0) {
8628 function isFocused(date) {
8629 if (date && angular.isDate($scope.focusedDate) && compare(date, $scope.focusedDate) === 0) {
8635 var isDisabled = this.isDisabled = function(date) {
8636 if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
8639 if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
8642 return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0));
8645 var compare = this.compare = function(date1, date2) {
8646 return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
8650 function isMinDateAvailable(startDate, endDate) {
8651 if(($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
8659 function isMaxDateAvailable(startDate, endDate) {
8660 if(($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
8668 function getLabel(label) {
8672 pre: label.substr(0, 3),
8680 function makeDate(date, dayFormat, dayHeaderFormat, isFocused, isSelected, isFromDate, isToDate, isDateRange, isOld, isNew, isDisabled, isToday, isWeekend) {
8681 return {date: date, label: dateFilter(date, dayFormat), header: dateFilter(date, dayHeaderFormat), focused: !!isFocused, selected: !!isSelected, from: !!isFromDate, to: !!isToDate, dateRange: !!isDateRange, oldMonth: !!isOld, nextMonth: !!isNew, disabled: !!isDisabled, today: !!isToday, weekend: !!isWeekend};
8687 getVisibleDates: function(date, calendar) {
8688 var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1), lastDayOfMonth = new Date(year, month+1, 0);
8689 var difference = startingDay - firstDayOfMonth.getDay(),
8690 numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
8691 firstDate = new Date(firstDayOfMonth), numDates = 0;
8693 if (numDisplayedFromPreviousMonth > 0) {
8694 firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
8695 numDates += numDisplayedFromPreviousMonth; // Previous
8697 numDates += getDaysInMonth(year, month + 1); // Current
8698 numDates += (7 - numDates % 7) % 7; // Next
8700 var days = getDates(firstDate, numDates), labels = new Array(7);
8701 for (var i = 0; i < numDates; i++) {
8702 var dt = new Date(days[i]);
8703 days[i] = makeDate(dt,
8711 (new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() < new Date(year, month, 1, 0, 0, 0).getTime()),
8712 (new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() > new Date(year, month, 1, 0, 0, 0).getTime()),
8717 for (var j = 0; j < 7; j++) {
8718 labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
8720 if (calendar === 'top') {
8721 $scope.disablePrevTop = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8722 $scope.disableNextTop = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8723 } else if (calendar === 'bottom') {
8724 $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8725 $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8727 $scope.disablePrevTop = $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8728 $scope.disableNextTop = $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8730 $scope.disablePrev = $scope.disablePrevTop || $scope.disablePrevBottom;
8731 $scope.disableNext = $scope.disableNextTop || $scope.disableNextBottom;
8732 return {objects: days, title: dateFilter(date, format.dayTitle), labels: labels};
8739 getVisibleDates: function(date, calendar) {
8740 var months = new Array(12), labels = [], year = date.getFullYear(), month = date.getMonth();
8741 for (var i = 0; i < 12; i++) {
8742 var dt = new Date(year,i,1);
8743 months[i] = makeDate(dt,
8758 return {objects: months, title: dateFilter(date, format.year), labels: labels};
8767 .directive('datepicker', ['$timeout', function ($timeout) {
8772 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepicker.html',
8774 currentDate: "=?current",
8777 require: 'datepicker',
8778 controller: 'DatepickerController',
8779 link: function(scope, element, attrs, ctrl) {
8780 var datepickerCtrl = ctrl;
8781 var selected, calendarSelected = false;
8784 scope.resetTime = function(date) {
8786 if (!isNaN(new Date(date))) {
8787 dt = new Date(date);
8788 if(scope.mode === 1){
8789 dt = new Date(dt.getFullYear(), dt.getMonth());
8791 dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
8800 scope.$parent.$watch(attrs.min, function(value) {
8801 scope.minDate = value ? scope.resetTime(value) : null;
8806 scope.$parent.$watch(attrs.max, function(value) {
8807 scope.maxDate = value ? scope.resetTime(value) : null;
8812 // Split array into smaller arrays
8813 function split(arr, size) {
8815 while (arr.length > 0) {
8816 arrays.push(arr.splice(0, size));
8821 function refill(date) {
8822 if (angular.isDate(date) && !isNaN(date)) {
8823 selected = new Date(date);
8826 selected = new Date();
8831 var selectedCalendar;
8832 if(scope.mode === 1){
8833 selected = new Date();
8834 selectedCalendar = moveMonth(angular.copy(selected), -1);
8836 selectedCalendar = angular.copy(selected);
8839 var currentMode = datepickerCtrl.modes[scope.mode];
8840 var currentData = currentMode.getVisibleDates(selectedCalendar, 'top');
8841 scope.currentRows = split(currentData.objects, currentMode.split);
8842 scope.currentTitle = currentData.title;
8843 scope.labels = currentData.labels || [];
8845 var nextData = currentMode.getVisibleDates(moveMonth(angular.copy(selectedCalendar), 1), 'bottom');
8846 scope.nextRows = split(nextData.objects, currentMode.split);
8847 scope.nextTitle = nextData.title;
8851 scope.select = function(date) {
8852 calendarSelected = true;
8854 if(!(angular.isDate(scope.fromDate) && angular.isDate(scope.currentDate))) {
8855 if(angular.isDate(scope.fromDate)) {
8856 selectCurrentDate(date);
8857 } else if(!angular.isDate(scope.fromDate)) {
8858 selectFromDate(date);
8862 selectCurrentDate(date);
8864 scope.focusedDate = date;
8867 var selectCurrentDate = function(date) {
8868 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
8869 scope.currentDate = dt;
8872 var selectFromDate = function(date) {
8873 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
8874 scope.fromDate = dt;
8877 var swapDate = function(fromDate, currentDate) {
8878 selectFromDate(currentDate);
8879 $timeout(function () {
8880 calendarSelected = true;
8881 scope.focusedDate = currentDate;
8882 selectCurrentDate(fromDate);
8885 var moveMonth = function(selectedDate, direction) {
8886 var step = datepickerCtrl.modes[scope.mode].step;
8887 selectedDate.setDate(1);
8888 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
8889 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
8891 return selectedDate;
8894 scope.move = function(direction) {
8895 selected = moveMonth(angular.copy(selected), direction);
8899 scope.$watch('currentDate', function (value) {
8900 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
8901 scope.currentDate = null;
8905 if (!isNaN(value) && !isNaN(scope.fromDate) && datepickerCtrl.compare(value, scope.fromDate) < 0) {
8906 swapDate(scope.fromDate, value);
8910 if (calendarSelected) {
8912 calendarSelected = false;
8914 if (angular.isDefined(value) && value !== null) {
8920 scope.focusedDate = undefined;
8923 scope.$watch('fromDate', function (value) {
8924 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
8925 scope.fromDate = null;
8929 if (!isNaN(scope.currentDate) && !isNaN(value) && datepickerCtrl.compare(scope.currentDate, value) < 0) {
8930 swapDate(value, scope.currentDate);
8933 if (calendarSelected) {
8935 calendarSelected = false;
8937 if (angular.isDefined(value) && value !== null) {
8944 scope.focusedDate = undefined;
8949 .directive('datepickerPopup', ['$document', 'datepickerService', '$isElement', '$documentBind', function($document, datepickerService, $isElement, $documentBind) {
8950 var link = function (scope, elem, attr, ctrl) {
8951 datepickerService.bindScope(attr, scope);
8953 scope.isOpen = false;
8955 var toggle = scope.toggle = function (show) {
8956 if(show === true || show === false) {
8957 scope.isOpen = show;
8959 scope.isOpen = !scope.isOpen;
8963 scope.$watch('current', function () {
8967 var outsideClick = function (e) {
8968 var isElement = $isElement(angular.element(e.target), elem, $document);
8975 $documentBind.click('isOpen', outsideClick, scope);
8982 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html',
8986 compile: function (elem, attr) {
8987 var wrapperElement = elem.find('span').eq(1);
8988 wrapperElement.attr('current', 'current');
8989 datepickerService.setAttributes(attr, wrapperElement);
8996 .directive('attDatepicker', ['$log', function($log) {
9001 controller: ['$scope', '$element', '$attrs', '$compile', 'datepickerConfig', 'datepickerService', function($scope, $element, $attrs, $compile, datepickerConfig, datepickerService) {
9002 var dateFormatString = angular.isDefined($attrs.dateFormat) ? $scope.$parent.$eval($attrs.dateFormat) : datepickerConfig.dateFormat;
9003 var selectedDateMessage = '<div class="sr-focus hidden-spoken" tabindex="-1">the date you selected is {{$parent.current | date : \'' + dateFormatString + '\'}}</div>';
9005 $element.removeAttr('att-datepicker');
9006 $element.removeAttr('ng-model');
9007 $element.attr('ng-model', '$parent.current');
9008 $element.attr('aria-describedby', 'datepicker');
9009 $element.attr('format-date', dateFormatString);
9010 $element.attr('att-input-deny', '[^0-9\/-]');
9011 $element.attr('maxlength', 10);
9013 var wrapperElement = angular.element('<div></div>');
9014 wrapperElement.attr('datepicker-popup', '');
9015 wrapperElement.attr('current', 'current');
9017 datepickerService.setAttributes($attrs, wrapperElement);
9018 datepickerService.bindScope($attrs, $scope);
9020 wrapperElement.html('');
9021 wrapperElement.append($element.prop('outerHTML'));
9022 if (navigator.userAgent.match(/MSIE 8/) === null) {
9023 wrapperElement.append(selectedDateMessage);
9025 var elm = wrapperElement.prop('outerHTML');
9026 elm = $compile(elm)($scope);
9027 $element.replaceWith(elm);
9029 link: function(scope, elem, attr, ctrl) {
9031 $log.error("ng-model is required.");
9032 return; // do nothing if no ng-model
9035 scope.$watch('current', function(value) {
9036 ctrl.$setViewValue(value);
9038 ctrl.$render = function() {
9039 scope.current = ctrl.$viewValue;
9045 .directive('formatDate', ['dateFilter', 'datepickerService', function(dateFilter, datepickerService) {
9049 link: function(scope, elem, attr, ctrl) {
9050 var formatDate = "";
9051 attr.$observe('formatDate', function (value) {
9054 var dateToString = function(value) {
9056 ctrl.$setValidity('invalidDate', true);
9057 return dateFilter(value, formatDate);
9059 ctrl.$setValidity('invalidDate', false);
9063 var stringToDate = function(value) {
9064 if(datepickerService.validateDateString(value, formatDate)) {
9065 ctrl.$setValidity('invalidDate', true);
9066 return new Date(value);
9068 ctrl.$setValidity('invalidDate', false);
9072 ctrl.$formatters.unshift(dateToString);
9073 ctrl.$parsers.unshift(stringToDate);
9078 .directive('attDateFilter', ['$document', 'dateFilter', 'datepickerConfig', 'datepickerService', '$isElement', '$documentBind', function($document, dateFilter, datepickerConfig, datepickerService, $isElement, $documentBind) {
9080 var link = function (scope, elem, attr, ctrl) {
9081 datepickerService.bindScope(attr, scope);
9083 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9084 scope.showDropdownList = false;
9085 scope.showCalendar = false;
9086 scope.applyButtonType = "disabled";
9088 scope.currentSelection = "";
9089 var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : datepickerConfig.dateFormat;
9090 var inputChange = false;
9094 var showDropdown = scope.showDropdown = function (show) {
9095 if(show === true || show === false) {
9096 scope.showDropdownList = show;
9098 scope.showDropdownList = !scope.showDropdownList;
9101 if (!scope.showDropdownList) {
9102 scope.focusInputButton = true;
9105 if (scope.currentSelection === 'Custom Single Date' || scope.currentSelection === 'Custom Range') {
9111 var resetTime = scope.resetTime = function(date) {
9113 if (!isNaN(new Date(date))) {
9114 dt = new Date(date);
9118 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9121 var addDays = scope.addDays = function (date, days) {
9123 if (!isNaN(new Date(date)) && !isNaN(days)) {
9124 dt = new Date(date);
9125 dt.setDate(dt.getDate() + days);
9131 var addMonth = scope.addMonth = function (date, months) {
9133 if (!isNaN(new Date(date)) && !isNaN(months)) {
9134 dt = new Date(date);
9135 dt.setMonth(dt.getMonth() + months);
9142 var showCalendar = function() {
9143 scope.showCalendar = true;
9146 var hideCalendar = function() {
9147 scope.showCalendar = false;
9148 if(scope.currentSelection !== 'Custom Single Date' && scope.currentSelection !== 'Custom Range') {
9153 var setDropdownText = function(value) {
9158 var fromDateText = dateFormatString.toUpperCase();
9159 var currentDateText = dateFormatString.toUpperCase();
9161 if(!isNaN(new Date(scope.fromDate))) {
9162 fromDateText = dateFilter(scope.fromDate, dateFormatString);
9164 if(!isNaN(new Date(scope.currentDate))) {
9165 currentDateText = dateFilter(scope.currentDate, dateFormatString);
9168 if(value === 'Custom Single Date') {
9169 ctrl.$setValidity('invalidDate', true);
9170 scope.maxLength = 10;
9171 scope.selectedOption = currentDateText;
9172 } else if(value === 'Custom Range') {
9173 ctrl.$setValidity('invalidDate', true);
9174 ctrl.$setValidity('invalidDateRange', true);
9175 scope.maxLength = 21;
9176 scope.selectedOption = fromDateText + '-' + currentDateText;
9180 scope.getDropdownText = function () {
9182 var dropdownText = scope.selectedOption;
9184 if (scope.currentSelection === 'Custom Single Date') {
9185 if (!isNaN(new Date(dropdownText)) && datepickerService.validateDateString(dropdownText, dateFormatString)) {
9186 ctrl.$setValidity('invalidDate', true);
9187 scope.fromDate = undefined;
9188 scope.currentDate = new Date(dropdownText);
9190 ctrl.$setValidity('invalidDate', false);
9193 } else if (scope.currentSelection === 'Custom Range') {
9194 if (dropdownText.indexOf('-') !== -1 && (dropdownText.split('-').length === 2 || dropdownText.split('-').length === 6)) {
9195 ctrl.$setValidity('invalidDateRange', true);
9196 var resultDropdownText = dropdownText.split('-');
9197 if (resultDropdownText.length === 2) {
9198 resultDropdownText[0] = resultDropdownText[0].trim();
9199 resultDropdownText[1] = resultDropdownText[1].trim();
9200 } else if (resultDropdownText.length === 6) {
9201 var firstDateString = resultDropdownText[0].trim() + '-' + resultDropdownText[1].trim() + '-' + resultDropdownText[2].trim();
9202 var secondDateString = resultDropdownText[3].trim() + '-' + resultDropdownText[4].trim() + '-' + resultDropdownText[5].trim();
9203 resultDropdownText[0] = firstDateString;
9204 resultDropdownText[1] = secondDateString;
9207 if (!isNaN(new Date(resultDropdownText[0])) && !isNaN(new Date(resultDropdownText[1])) && datepickerService.validateDateString(resultDropdownText[0], dateFormatString) && datepickerService.validateDateString(resultDropdownText[1], dateFormatString)) {
9208 ctrl.$setValidity('invalidDate', true);
9209 var fromDate = new Date(resultDropdownText[0]);
9210 var currentDate = new Date(resultDropdownText[1]);
9211 if(fromDate.getTime() < currentDate.getTime()) {
9212 ctrl.$setValidity('invalidDateRange', true);
9213 scope.fromDate = fromDate;
9214 scope.currentDate = currentDate;
9216 ctrl.$setValidity('invalidDateRange', false);
9220 ctrl.$setValidity('invalidDate', false);
9224 ctrl.$setValidity('invalidDateRange', false);
9230 scope.untrackInputChange = function(ev) {
9231 inputChange = false;
9234 scope.selectAdvancedOption = function (value, notClearFlag) {
9235 scope.currentSelection = value;
9240 scope.$watch('currentDate', function(val) {
9241 if(!isNaN(new Date(val))) {
9242 scope.applyButtonType = "primary";
9243 setDropdownText(value);
9245 scope.focusApplyButton = true;
9249 scope.$watch('fromDate', function(val) {
9250 if(!isNaN(new Date(val))) {
9251 setDropdownText(value);
9254 if (value === 'Custom Single Date') {
9255 scope.focusSingleDateCalendar = true;
9256 } else if (value === 'Custom Range') {
9257 scope.focusRangeCalendar = true;
9261 scope.resetFocus = function (ev) {
9262 scope.focusSingleDateCalendar = false;
9263 scope.focusRangeCalendar = false;
9264 scope.focusApplyButton = false;
9267 scope.apply = function() {
9268 scope.dateRange.selection = scope.selectedOption;
9269 if(!isNaN(new Date(scope.fromDate))) {
9270 scope.from = scope.fromDate;
9271 scope.dateRange.from = scope.fromDate;
9273 scope.from = undefined;
9274 scope.dateRange.from = undefined;
9276 if(!isNaN(new Date(scope.currentDate))) {
9277 scope.current = scope.currentDate;
9278 scope.dateRange.current = scope.currentDate;
9280 scope.current = undefined;
9281 scope.dateRange.current = undefined;
9287 scope.$watchCollection(function() {
9288 return scope.dateRange;
9289 }, function(value) {
9291 var finalDateRange = angular.copy(value);
9292 ctrl.$setViewValue(finalDateRange);
9296 ctrl.$render = function() {
9297 if (ctrl.$viewValue) {
9298 var inputRange = ctrl.$viewValue;
9299 scope.selectedOption = inputRange.selection;
9300 scope.fromDate = inputRange.from;
9301 scope.currentDate = inputRange.current;
9302 if(scope.fromDate !== undefined && scope.currentDate !== undefined){
9303 scope.selectAdvancedOption('Custom Range',true);
9304 scope.dateRange.from= scope.fromDate;
9305 scope.dateRange.current = scope.currentDate;
9306 }else if(scope.currentDate !== undefined){
9307 scope.selectAdvancedOption('Custom Single Date',true);
9312 var cancel = scope.cancel = function() {
9313 scope.currentSelection = "";
9314 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9318 var clear = scope.clear = function(partial) {
9319 scope.fromDate = undefined;
9320 scope.currentDate = undefined;
9321 scope.applyButtonType = "disabled";
9323 ctrl.$setValidity('invalidDate', true);
9324 ctrl.$setValidity('invalidDateRange', true);
9325 setDropdownText(scope.currentSelection);
9329 var outsideClick = function (e) {
9330 var isElement = $isElement(angular.element(e.target), elem, $document);
9337 $documentBind.click('showDropdownList', outsideClick, scope);
9344 current: "=?current"
9347 require: '?ngModel',
9349 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/dateFilter.html',
9350 controller:['$scope', '$element', '$attrs',function($scope, $element, $attrs){
9351 $scope.dateRange = {
9352 selection: undefined,
9356 this.selectOption = function (fromDate,toDate,caption) {
9357 $scope.selectedOption = caption;
9358 $scope.currentSelection =caption;
9359 $scope.dateRange.selection = caption;
9360 $scope.dateRange.current = $scope.resetTime(toDate);
9361 $scope.dateRange.from = $scope.resetTime(fromDate);
9362 $scope.showDropdown();
9364 $scope.checkCurrentSelection=this.checkCurrentSelection = function(value) {
9365 if(value === $scope.currentSelection) {
9371 compile: function(elem, attr) {
9372 var singleDateCalendar = elem.find('span').eq(4);
9373 var rangeCalendar = elem.find('span').eq(5);
9374 rangeCalendar.attr('from', 'fromDate');
9375 singleDateCalendar.attr('current', 'currentDate');
9376 rangeCalendar.attr('current', 'currentDate');
9377 datepickerService.setAttributes(attr, singleDateCalendar);
9378 datepickerService.setAttributes(attr, rangeCalendar);
9384 .directive('attDateFilterList',function(){
9388 fromDate:'=fromDate',
9391 disabled:'=disabled'
9393 require:'^attDateFilter',
9396 templateUrl:'app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html',
9397 link:function(scope,elem,attr,ctrl){
9398 scope.selectOption=function(fromDate,toDate,caption){
9399 ctrl.selectOption(fromDate,toDate,caption);
9401 scope.checkCurrentSelection=ctrl.checkCurrentSelection;
9406 angular.module('att.abs.devNotes', [])
9408 .directive('attDevNotes', function() {
9413 controller: function($scope){
9414 var panes = $scope.panes = [];
9415 $scope.select = function(pane)
9417 angular.forEach(panes, function(pane)
9419 pane.selected = false;
9421 pane.selected = true;
9423 this.addPane = function(pane) {
9424 if (panes.length === 0) {
9425 $scope.select(pane);
9431 '<ul class="tabs">' +
9432 '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
9433 '<a href="javascript:void(0)" ng-click="select(pane)">{{pane.title}}</a>' +
9436 '<div ng-transclude></div>'+
9442 .directive('pane', function() {
9444 require: '^attDevNotes',
9450 link: function(scope, element, attrs, tabsCtrl) {
9451 tabsCtrl.addPane(scope);
9454 '<div class="tab-pane" ng-class="{active: selected}">' +
9455 '<pre ng-class="{\'language-markup\':title==\'HTML\',\'language-javascript\':title==\'JavaScript\'}" class=" line-numbers">' +
9456 '<code ng-transclude></code>' +
9463 angular.module('att.abs.dividerLines', [])
9464 .directive('attDividerLines', [function()
9468 attDividerLines: '@'
9472 templateUrl: 'app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html',
9473 link: function(scope, element, attribute)
9475 scope.lightContainer = attribute.attDividerLines;
9480 angular.module('att.abs.dragdrop', [])
9481 .directive('attFileDrop', ['$parse', function($parse) {
9489 controller: ['$scope', '$attrs', function($scope, $attrs){
9490 if($attrs.attFileDrop!==""){
9491 $scope.onDrop=$scope.attFileDrop;
9493 this.onDrop = $scope.onDrop;
9495 link: function(scope, element) {
9496 element.addClass('dragdrop');
9500 if(e.originalEvent){
9501 e.dataTransfer = e.originalEvent.dataTransfer;
9503 e.dataTransfer.dropEffect = 'move';
9504 // allows us to drop
9505 if (e.preventDefault) {
9508 element.addClass('dragdrop-over');
9515 // allows us to drop
9516 if (e.preventDefault) {
9519 element.addClass('dragdrop-over');
9526 element.removeClass('dragdrop-over');
9533 // Stops some browsers from redirecting.
9534 if(e.preventDefault) {
9537 if (e.stopPropagation) {
9538 e.stopPropagation();
9540 if(e.originalEvent){
9541 e.dataTransfer = e.originalEvent.dataTransfer;
9543 element.removeClass('dragdrop-over');
9544 if(e.dataTransfer.files && e.dataTransfer.files.length > 0){
9545 scope.fileModel = e.dataTransfer.files[0];
9547 if(typeof scope.onDrop === "function"){
9548 scope.onDrop = $parse(scope.onDrop);
9558 .directive('attFileLink', [ function() {
9561 require: '^?attFileDrop',
9564 templateUrl: 'app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html',
9570 controller: ['$scope', '$parse', function($scope, $parse){
9571 this.setFileModel= function(fileModel){
9572 if($scope.takeFileModelFromParent){
9573 $scope.$parent.fileModel = fileModel;
9574 $scope.$parent.$apply();
9577 $scope.fileModel = fileModel;
9581 this.callbackFunction= function(){
9582 if(typeof $scope.onFileSelect === "function"){
9583 $scope.onFileSelect = $parse($scope.onFileSelect);
9584 $scope.onFileSelect();
9588 link: function(scope, element, attr, attFileDropCtrl) {
9589 scope.takeFileModelFromParent = false;
9590 if(!(attr.fileModel) && attFileDropCtrl){
9591 scope.takeFileModelFromParent = true;
9593 if(attr.attFileLink!==""){
9594 scope.onFileSelect=scope.attFileLink;
9596 else if(!(attr.onFileSelect) && attFileDropCtrl){
9597 scope.onFileSelect = attFileDropCtrl.onDrop;
9602 .directive('attFileChange', [function() {
9605 require: '^attFileLink',
9606 link: function(scope, element, attr, attFileLinkCtrl) {
9610 if(e.target.files && e.target.files.length > 0){
9611 attFileLinkCtrl.setFileModel(e.target.files[0]);
9612 attFileLinkCtrl.callbackFunction();
9615 var strFileName = e.target.value;
9616 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
9617 attFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
9618 attFileLinkCtrl.callbackFunction();
9625 angular.module("att.abs.drawer", [])
9626 .directive('attDrawer', ['$document', '$timeout', function ($document, $timeout) {
9633 drawerAutoClose: "=?"
9635 template: '<div><div class="att-drawer" ng-transclude></div><div ng-class="{\'drawer-backdrop\':drawerOpen}"></div></div>',
9636 link: function ($scope, element, attrs) {
9638 // Override default parameters
9639 param.side = attrs.drawerSlide || 'top';
9640 param.speed = attrs.drawerSpeed || '0.25';
9641 param.size = attrs.drawerSize || '300px';
9642 param.zindex = attrs.drawerZindex || 1000;
9643 param.className = attrs.drawerClass || 'att-drawer';
9644 var slider = element.eq(0).children()[0];
9645 var content = angular.element(slider).children()[0];
9646 slider.className = param.className;
9648 slider.style.transitionDuration = param.speed + 's';
9649 slider.style.webkitTransitionDuration = param.speed + 's';
9650 slider.style.zIndex = param.zindex;
9651 slider.style.position = 'fixed';
9652 slider.style.width = 0;
9653 slider.style.height = 0;
9654 slider.style.transitionProperty = 'width, height';
9655 if(param.side==='right' || param.side==='left'){
9656 slider.style.height = attrs.drawerCustomHeight || '100%';
9657 slider.style.top = attrs.drawerCustomTop || '0px';
9658 slider.style.bottom = attrs.drawerCustomBottom || '0px';
9659 slider.style.right = attrs.drawerCustomRight || '0px';
9661 else if(param.side==='top' || param.side==='bottom'){
9662 slider.style.width = attrs.drawerCustomWidth || '100%';
9663 slider.style.left = attrs.drawerCustomLeft || '0px';
9664 slider.style.top = attrs.drawerCustomTop || '0px';
9665 slider.style.right = attrs.drawerCustomRight || '0px';
9668 function drawerClose(slider, param) {
9669 if (slider && slider.style.width !== 0 && slider.style.height !== 0){
9670 content.style.display = 'none';
9671 if(param.side==='right' || param.side==='left'){
9672 slider.style.width = '0px';
9674 else if(param.side==='top' || param.side==='bottom'){
9675 slider.style.height = '0px';
9678 $scope.drawerOpen = false;
9681 function drawerOpen(slider, param) {
9682 if (slider.style.width !== 0 && slider.style.height !== 0){
9683 if(param.side==='right' || param.side==='left'){
9684 slider.style.width = param.size;
9686 else if(param.side==='top' || param.side==='bottom'){
9687 slider.style.height = param.size;
9689 $timeout(function() {
9690 content.style.display = 'block';
9691 },(param.speed * 1000));
9694 function isFunction(functionToCheck) {
9696 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
9701 if(attrs.drawerSize) {
9702 $scope.$watch(function() {
9703 return attrs.drawerSize;
9704 }, function(newVal) {
9705 param.size = newVal;
9706 if($scope.drawerOpen) {
9707 drawerOpen(slider,param);
9711 $scope.$watch("drawerOpen", function (value){
9714 drawerOpen(slider,param);
9717 drawerClose(slider,param);
9720 // close panel on location change
9721 if($scope.drawerAutoClose) {
9722 $scope.$on("$locationChangeStart", function(){
9723 drawerClose(slider, param);
9724 if(isFunction($scope.drawerAutoClose)) {
9725 $scope.drawerAutoClose();
9728 $scope.$on("$stateChangeStart", function(){
9729 drawerClose(slider, param);
9730 if(isFunction($scope.drawerAutoClose)) {
9731 $scope.drawerAutoClose();
9739 angular.module('att.abs.message', [])
9741 .directive('attMessages', [function() {
9745 controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
9747 $scope.$watchCollection($attrs['for'], function(errors) {
9748 for (var key in errors) {
9753 $scope.error = null;
9756 if ($scope.error === null) {
9757 $scope.messageType = null;
9758 $element.removeAttr('message-type');
9761 this.setMessageType = function(messageType) {
9762 $scope.messageType = messageType;
9764 $scope.$watch('messageType', function(value) {
9765 if (angular.isDefined(value) && value !== null) {
9766 $element.attr('message-type', value);
9773 .directive('attMessage', [function() {
9777 require: '^attMessages',
9778 link: function(scope, elem, attr, ctrl) {
9779 scope.when = attr.when || attr.attMessage;
9780 scope.type = attr.type;
9781 elem.css({display: 'none'});
9782 scope.$parent.$watch('error', function(value) {
9783 if (value === scope.when) {
9784 elem.css({display: 'block'});
9785 ctrl.setMessageType(scope.type);
9787 elem.css({display: 'none'});
9794 angular.module('att.abs.formField', ['att.abs.message'])
9796 .directive('attFormField', [function() {
9800 controller:function() {
9802 link: function(scope, elem, attr) {
9803 elem.wrap('<div class="form-field"></div>');
9804 elem.parent().append('<label class="form-field__label">' + attr.placeholder || attr.attFormField + '</label>');
9805 elem.wrap('<div class="form-field-input-container"></div>');
9807 elem.bind('keyup', function() {
9808 if (this.value !== '') {
9809 elem.parent().parent().find('label').addClass('form-field__label--show').removeClass('form-field__label--hide');
9811 elem.parent().parent().find('label').addClass('form-field__label--hide').removeClass('form-field__label--show');
9815 elem.bind('blur', function() {
9816 if (this.value === '') {
9817 elem.parent().parent().find('label').removeClass('form-field__label--hide');
9824 .directive('attFormFieldValidation', ['$compile', '$log', function($compile, $log) {
9829 require: ['?ngModel', '?attFormField'],
9830 link: function(scope, elem, attr, ctrl) {
9831 var ngCtrl = ctrl[0];
9832 var attFormFieldCtrl = ctrl[1];
9835 $log.error("att-form-field-validation :: ng-model directive is required.");
9838 if (!attFormFieldCtrl) {
9839 $log.error("att-form-field-validation :: att-form-field directive is required.");
9843 elem.parent().append($compile(angular.element('<i class="icon-info-alert error" ng-show="valid===false"> </i>'))(scope));
9844 elem.parent().append($compile(angular.element('<i class="icon-info-success success" ng-show="valid===true"> </i>'))(scope));
9846 scope.$watch('valid', function(value) {
9848 elem.parent().parent().addClass('success');
9849 } else if (value === false) {
9850 elem.parent().parent().addClass('error');
9852 elem.parent().parent().removeClass('success').removeClass('error');
9856 elem.bind('keyup', function() {
9857 if (ngCtrl.$valid) {
9859 } else if (ngCtrl.$invalid) {
9860 scope.valid = false;
9870 .directive('attFormFieldValidationAlert', ['$timeout', function($timeout) {
9876 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html',
9877 link: function(scope, elem) {
9878 scope.showLabel = false;
9879 scope.hideLabel = false;
9880 scope.errorMessage = false;
9881 scope.warningMessage = false;
9882 var checkMessageType = function() {
9883 if (elem.find('att-messages').attr('message-type') === 'error') {
9884 scope.errorMessage = true;
9885 scope.warningMessage = false;
9886 } else if (elem.find('att-messages').attr('message-type') === 'warning') {
9887 scope.errorMessage = false;
9888 scope.warningMessage = true;
9890 scope.errorMessage = false;
9891 scope.warningMessage = false;
9895 elem.find('label').text(elem.find('input').attr('placeholder'));
9896 elem.find('input').bind('keyup', function() {
9897 if (this.value !== '') {
9898 scope.showLabel = true;
9899 scope.hideLabel = false;
9901 scope.showLabel = false;
9902 scope.hideLabel = true;
9908 elem.find('input').bind('blur', function() {
9909 if (this.value === '') {
9910 scope.showLabel = false;
9911 scope.hideLabel = false;
9915 $timeout(function() {
9922 angular.module('att.abs.hourpicker', ['att.abs.utilities'])
9923 .constant('hourpickerConfig', {
9924 days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
9925 customOption: 'Custom'
9928 .controller('hourPickerController', ['$scope', function($scope) {
9930 $scope.options = [];
9931 this.setOptions = function(value, fromtime, totime, preselect, uncheckedFromTime,uncheckedToTime) {
9932 $scope.options.push(value);
9934 if (preselect !== undefined) {
9935 $scope.preselect = preselect;
9940 if (fromtime !== undefined) {
9941 $scope.fromtime = fromtime;
9942 for (daycount in $scope.days) {
9943 if ($scope.days.hasOwnProperty(daycount)) {
9944 $scope.FrtimeList[$scope.days[daycount]] = {};
9945 if(uncheckedFromTime !== undefined){
9946 $scope.FrtimeList[$scope.days[daycount]].value = uncheckedFromTime;
9947 $scope.selectedFromOption[$scope.days[daycount]] = uncheckedFromTime;
9949 $scope.FrtimeList[$scope.days[daycount]].value = fromtime[0].value;
9950 $scope.selectedFromOption[$scope.days[daycount]] = fromtime[0].value;
9955 if (totime !== undefined) {
9956 $scope.totime = totime;
9957 for (daycount in $scope.days) {
9958 if ($scope.days.hasOwnProperty(daycount)) {
9959 $scope.TotimeList[$scope.days[daycount]] = {};
9960 if(uncheckedToTime !== undefined){
9961 $scope.TotimeList[$scope.days[daycount]].value = uncheckedToTime;
9962 $scope.selectedToOption[$scope.days[daycount]] = uncheckedToTime;
9964 $scope.TotimeList[$scope.days[daycount]].value = totime[0].value;
9965 $scope.selectedToOption[$scope.days[daycount]] = totime[0].value;
9971 if(uncheckedFromTime !== undefined){
9972 $scope.uncheckedFromTime = uncheckedFromTime;
9974 if(uncheckedToTime !== undefined){
9975 $scope.uncheckedToTime = uncheckedToTime;
9980 .directive('attHourpickerOption', [function() {
9983 require: '^attHourpicker',
9986 fromtime: "=fromtime",
9988 preselect: "=preselect",
9989 uncheckedFromTime: "=",
9990 uncheckedToTime: "="
9992 link: function(scope, element, attr, ctrl) {
9993 ctrl.setOptions(scope.option,
9997 scope.uncheckedFromTime,
9998 scope.uncheckedToTime);
10003 .directive('attHourpicker', ["hourpickerConfig", "$document", "$log", "$documentBind", "$timeout", function(hourpickerConfig, $document, $log, $documentBind, $timeout) {
10005 require: 'ngModel',
10007 controller: 'hourPickerController',
10013 templateUrl: 'app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html',
10014 link: function(scope, element, attr, ctrl) {
10016 scope.isFromDropDownOpen = false;
10017 scope.isToDropDownOpen = false;
10018 var dropDownOpenValue = "";
10020 scope.days = hourpickerConfig.days;
10021 scope.daysList = {};
10022 scope.FrtimeList = {};
10023 scope.FrtimeListDay = {};
10024 scope.TotimeListDay = {};
10025 scope.selectedFromOption = {};
10026 scope.selectedToOption = {};
10027 scope.TotimeList = {};
10028 scope.selectedIndex = 0;
10029 scope.selectedOption = "Select from list";
10030 scope.customTime = [];
10032 scope.resetFlag = false;
10034 scope.$watch('resetFlag', function(newVal, oldVal){
10035 if(newVal !== oldVal){
10036 if( newVal && scope.selectedOption === hourpickerConfig.customOption ){
10037 //disable and reset all days checkbox
10038 for (day in scope.daysList) {
10039 if (scope.daysList.hasOwnProperty(day)) {
10040 scope.daysList[day] = false;
10041 scope.addSelectedValue(day);
10044 scope.preselectUpdateFxn(scope.preselect);
10046 scope.resetFlag = false;
10050 scope.$watch('selCategory', function(value) {
10052 ctrl.$setViewValue(value);
10055 scope.$watch('model', function(value,oldValue) {
10056 if (value && oldValue && angular.toJson(value) !== angular.toJson(oldValue)) {
10057 scope.updateData(value);
10060 scope.updateData = function(value) {
10061 if (value.constructor === Array) {
10062 scope.showDaysSelector = true;
10063 scope.selectedOption = hourpickerConfig.customOption;
10064 for (var arry in value) {
10065 if (value.hasOwnProperty(arry)) {
10066 var day = value[arry].day;
10067 scope.daysList[day] = true;
10069 for (var fromcount in scope.fromtime) {
10070 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
10071 scope.FrtimeList[day].value = scope.fromtime[fromcount].value;
10072 scope.selectedFromOption[day] = scope.FrtimeList[day].value;
10075 for (var tocount in scope.totime) {
10076 if (scope.totime[tocount].value === value[arry].ToTime) {
10077 scope.TotimeList[day].value = scope.totime[tocount].value;
10078 scope.selectedToOption[day] = scope.TotimeList[day].value;
10081 scope.addSelectedValue(day, value[arry].FromTime, value[arry].ToTime);
10083 if (parseInt(arry) + 1 === value.length) {
10090 scope.selectOption(value.day);
10094 scope.$watch('preselect', function(value){
10095 scope.preselectUpdateFxn(value);
10098 scope.preselectUpdateFxn = function(value){
10099 if (value !== undefined) {
10101 value = scope.validatePreselectData(value);
10103 if (value === "") {
10106 scope.updateData(value);
10110 scope.validatePreselectData = function(value){
10111 if (value.constructor === Array) {
10112 for (var arry in value) {
10113 if (value.hasOwnProperty(arry)) {
10114 var day = value[arry].day;
10115 var isDayFound = false;
10116 var isFrmFound = false;
10117 var isToFound = false;
10118 for (var daycount in scope.days) {
10119 if (scope.days[daycount] === day) {
10125 value.splice(arry, 1);
10128 for (var fromcount in scope.fromtime) {
10129 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
10135 value[arry].FromTime = scope.fromtime[0].value;
10137 for (var tocount in scope.totime) {
10138 if (scope.totime[tocount].value === value[arry].ToTime) {
10144 value[arry].ToTime = scope.totime[0].value;
10147 if (parseInt(arry) + 1 === value.length) {
10154 var isOptionFound = false;
10155 for (var optcount in scope.options) {
10156 if (scope.options[optcount] === value.day) {
10157 isOptionFound = true;
10161 if (!isOptionFound) {
10168 scope.selectPrevNextValue = function($event, arrayValues, currValue) {
10172 if ($event.keyCode === 38) {
10174 } else if ($event.keyCode === 40) {
10180 if (arrayValues.indexOf(currValue) !== -1) {
10181 index = arrayValues.indexOf(currValue) + value;
10183 for (var count in arrayValues) {
10184 if (arrayValues[count].value === currValue) {
10185 index = parseInt(count) + value;
10191 if (index === arrayValues.length) {
10193 } else if (index === -1) {
10197 $event.preventDefault();
10198 if (arrayValues[index].value){
10199 return arrayValues[index].value;
10202 return arrayValues[index];
10206 scope.showDropdown = function()
10208 scope.showlist = !scope.showlist;
10212 scope.showfromDayDropdown = function(value)
10214 //close dropdown if any other From drop down is opened
10215 for (count in scope.FrtimeListDay) {
10216 if (count !== value && scope.FrtimeListDay[count]) {
10217 scope.FrtimeListDay[count] = false;
10220 for (count in scope.TotimeListDay) {
10221 if (scope.TotimeListDay[count]) {
10222 scope.TotimeListDay[count] = false;
10225 scope.FrtimeListDay[value] = !scope.FrtimeListDay[value];
10227 scope.showlist = false;
10229 //save model value so we can close current dropdown on click of other part of the document
10230 if (scope.FrtimeListDay[value]) {
10231 scope.isFromDropDownOpen = true;
10232 dropDownOpenValue = value;
10234 scope.isFromDropDownOpen = false;
10237 $timeout(function () {
10238 if(scope.FrtimeListDay[value]){
10239 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
10240 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
10241 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
10242 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
10247 scope.showtoDayDropdown = function(value)
10249 //close dropdown if any other To drop down is opened
10250 for (count in scope.TotimeListDay) {
10251 if (count !== value && scope.TotimeListDay[count]) {
10252 scope.TotimeListDay[count] = false;
10255 for (count in scope.FrtimeListDay) {
10256 if (scope.FrtimeListDay[count]) {
10257 scope.FrtimeListDay[count] = false;
10260 scope.TotimeListDay[value] = !scope.TotimeListDay[value];
10262 scope.showlist = false;
10264 //save model value so we can close current dropdown on click of other part of the document
10265 if (scope.TotimeListDay[value]) {
10266 scope.isToDropDownOpen = true;
10267 dropDownOpenValue = value;
10270 scope.isToDropDownOpen = false;
10273 $timeout(function () {
10274 if(scope.FrtimeListDay[value]){
10275 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
10276 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
10277 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
10278 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
10283 scope.selectFromDayOption = function(day, value)
10285 scope.selectedFromOption[day] = value;
10286 scope.FrtimeList[day].value = value;
10287 scope.FrtimeListDay[day] = false;
10288 scope.isFromDropDownOpen = false;
10291 scope.selectToDayOption = function(day, value)
10293 scope.selectedToOption[day] = value;
10294 scope.TotimeList[day].value = value;
10295 scope.TotimeListDay[day] = false;
10296 scope.isToDropDownOpen = false;
10299 scope.addSelectedValue = function(value, fromtime, totime) {
10301 if (scope.daysList[value] !== undefined && !scope.daysList[value]) {
10302 for (count = 0, len = scope.customTime.length; count < len; count++) {
10303 if (scope.customTime[count].day === value) {
10304 if(scope.uncheckedFromTime){
10305 scope.selectedFromOption[scope.customTime[count].day] = scope.uncheckedFromTime;
10308 scope.selectedFromOption[scope.customTime[count].day] = scope.FrtimeList[scope.customTime[count].day].value;
10311 if(scope.uncheckedToTime){
10312 scope.selectedToOption[scope.customTime[count].day] = scope.uncheckedToTime;
10315 scope.selectedToOption[scope.customTime[count].day] = scope.TotimeList[scope.customTime[count].day].value;
10318 scope.customTime.splice(count, 1);
10324 if(scope.selectedFromOption[value] === scope.uncheckedFromTime){
10325 scope.selectedFromOption[value] = scope.fromtime[0].value;
10326 fromtime = scope.fromtime[0].value;
10327 scope.FrtimeList[value].value = scope.fromtime[0].value;
10330 if(scope.selectedToOption[value] === scope.uncheckedToTime){
10331 scope.selectedToOption[value] = scope.totime[0].value;
10332 totime = scope.totime[0].value;
10333 scope.TotimeList[value].value = scope.totime[0].value;
10336 custTime["day"] = value;
10337 custTime["FromTime"] = scope.FrtimeList[value].value;
10338 custTime["ToTime"] = scope.TotimeList[value].value;
10340 for (count = 0, len = scope.customTime.length; count < len; count++) {
10341 if (scope.customTime[count].day === value) {
10342 scope.customTime[count].FromTime = custTime["FromTime"];
10343 scope.customTime[count].ToTime = custTime["ToTime"];
10347 if (count === len) {
10348 var x = angular.copy(custTime);
10349 scope.customTime.push(x);
10352 scope.selCategory = scope.customTime;
10356 var outsideClick = function() {
10357 if (scope.showlist) {
10358 scope.$apply(function() {
10359 scope.showlist = false;
10364 $documentBind.click('showlist', outsideClick, scope);
10366 var outsideClickFromDropdown = function() {
10367 scope.$apply(function() {
10368 if (scope.isFromDropDownOpen) {
10369 scope.FrtimeListDay[dropDownOpenValue] = false;
10370 scope.isFromDropDownOpen = false;
10375 $documentBind.click('isFromDropDownOpen', outsideClickFromDropdown, scope);
10377 var outsideClickToDropdown = function() {
10378 scope.$apply(function() {
10379 if (scope.isToDropDownOpen) {
10380 scope.TotimeListDay[dropDownOpenValue] = false;
10381 scope.isToDropDownOpen = false;
10386 $documentBind.click('isToDropDownOpen', outsideClickToDropdown, scope);
10388 scope.selectOption = function(sItem)
10391 if (sItem === hourpickerConfig.customOption) {
10392 scope.showDaysSelector = true;
10393 scope.selCategory = scope.customTime;
10395 scope.showDaysSelector = false;
10396 var fromTime = /[0-9]\s?am/i.exec(sItem);
10397 var toTime = /[0-9]\s?pm/i.exec(sItem);
10398 scope.selCategory = {day: sItem, FromTime: fromTime === null ? 'NA' : fromTime[0], ToTime: toTime === null ? 'NA' : toTime[0]};
10401 scope.showlist = false;
10403 scope.selectedOption = sItem;
10409 angular.module('att.abs.iconButtons', [])
10410 .constant('buttonConfig', {
10411 activeClass: 'active--button',
10412 toggleEvent: 'click'
10414 .directive('attIconBtnRadio', ['buttonConfig', function(buttonConfig) {
10415 var activeClass = buttonConfig.activeClass || 'active--button';
10416 var toggleEvent = buttonConfig.toggleEvent || 'click';
10418 require: 'ngModel',
10419 link: function(scope, element, attrs, ngModelCtrl) {
10420 element.attr("role","button");
10421 element.attr("tabindex","0");
10422 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnRadio+"</span>");
10424 ngModelCtrl.$render = function() {
10425 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, attrs.attIconBtnRadio));
10428 element.parent().bind(toggleEvent, function() {
10429 if (!element.parent().hasClass(activeClass)) {
10430 scope.$apply(function() {
10431 ngModelCtrl.$setViewValue(attrs.attIconBtnRadio);
10432 ngModelCtrl.$render();
10439 .directive('attIconBtnCheckbox', ['buttonConfig', function(buttonConfig) {
10440 var activeClass = buttonConfig.activeClass || 'active--button';
10441 var toggleEvent = buttonConfig.toggleEvent || 'click';
10443 require: 'ngModel',
10444 link: function(scope, element, attrs, ngModelCtrl) {
10445 element.attr("role","button");
10446 element.attr("tabindex","0");
10447 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnCheckbox+"</span>");
10448 function getTrueValue() {
10449 var trueValue = scope.$eval(attrs.btnCheckboxTrue);
10450 return angular.isDefined(trueValue) ? trueValue : true;
10452 function getFalseValue() {
10453 var falseValue = scope.$eval(attrs.btnCheckboxFalse);
10454 return angular.isDefined(falseValue) ? falseValue : false;
10457 ngModelCtrl.$render = function() {
10458 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
10461 element.parent().bind(toggleEvent, function() {
10462 scope.$apply(function() {
10463 ngModelCtrl.$setViewValue(element.parent().hasClass(activeClass) ? getFalseValue() : getTrueValue());
10464 ngModelCtrl.$render();
10471 angular.module('att.abs.links', ['ngSanitize'])
10472 .directive('attLink', [function() {
10475 link: function(scope, elem) {
10476 elem.addClass('link');
10477 if(!(elem.attr('href'))){
10478 elem.attr("tabindex", "0");
10483 .directive('attLinkVisited', [function() {
10486 link: function(scope, elem) {
10487 elem.addClass('link--visited');
10488 if(!(elem.attr('href'))){
10489 elem.attr("tabindex", "0");
10494 .directive('attReadmore', ['$timeout',function($timeout) {
10498 lines:"@noOfLines",
10500 //attribute to use readmore inside accordion
10503 templateUrl: 'app/scripts/ng_js_att_tpls/links/readMore.html',
10504 link: function(scope, elem) {
10506 scope.$watch('textModel', function(val){
10508 scope.textToDisplay = '';
10509 scope.readMoreLink = false;
10510 scope.readLessLink = false;
10511 scope.readFlag = false;
10514 if (typeof String.prototype.trim !== 'function') {
10515 String.prototype.trim = function() {
10516 return this.replace(/^\s+|\s+$/g, '');
10519 scope.textToDisplay = val.trim();
10520 scope.readFlag = true;
10521 $timeout(function() {
10522 var readElem = elem[0].children[0].children[0];
10524 if(window.getComputedStyle){
10525 height = parseInt(scope.lines) * parseFloat(window.getComputedStyle(readElem,null).getPropertyValue("height"));
10528 height = parseInt(scope.lines) * parseFloat(readElem.currentStyle.height);
10530 scope.elemHeight = height;
10531 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
10534 scope.readMoreLink = true;
10535 scope.readLessLink = false;
10538 // Code to use readmore inside accordion
10539 var parentElem = elem.parent();
10540 if (parentElem.hasClass('att-accordion__body')) {
10541 scope.$watch('isOpen', function(val) {
10547 scope.readMore = function() {
10548 scope.readMoreLink = false;
10549 scope.readLessLink = true;
10550 scope.readLinkStyle = {'height': 'auto'};
10551 scope.readFlag = false;
10553 scope.readLess = function() {
10554 scope.readMoreLink = true;
10555 scope.readLessLink = false;
10556 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
10557 scope.readFlag = true;
10562 .directive('attLinksList', [function() {
10565 controller: function() {
10567 link: function(scope, elem) {
10568 elem.addClass('links-list');
10572 .directive('attLinksListItem', [function() {
10575 require: '^attLinksList',
10576 link: function(scope, elem) {
10577 elem.addClass('links-list__item');
10578 if(!(elem.attr('href'))){
10579 elem.attr("tabindex", "0");
10584 angular.module('att.abs.loading', [])
10585 .directive('attLoading', ['$window',function($window) {
10590 icon: '@attLoading',
10591 progressStatus: '=?',
10594 templateUrl: 'app/scripts/ng_js_att_tpls/loading/loading.html',
10595 link: function(scope, element) {
10596 var progressvalue = scope.progressStatus;
10597 scope.progressStatus = Math.min(100, Math.max(0, progressvalue));
10598 if($window.navigator.userAgent.indexOf("MSIE 8.")!==-1){
10599 var shiftX = 0, shiftY = scope.progressStatus * 36;
10601 'background-position-x' : shiftX,
10602 'background-position-y' : -shiftY
10608 angular.module('att.abs.modal', [])
10610 * A helper, internal data structure that acts as a map but also allows getting / removing
10611 * elements in the LIFO order
10613 .factory('$$stackedMap', function () {
10615 createNew: function () {
10619 add: function (key, value) {
10625 get: function (key) {
10626 for (var i = 0; i < stack.length; i++) {
10627 if (key === stack[i].key) {
10634 for (var i = 0; i < stack.length; i++) {
10635 keys.push(stack[i].key);
10640 return stack[stack.length - 1];
10642 remove: function (key) {
10644 for (var i = 0; i < stack.length; i++) {
10645 if (key === stack[i].key) {
10650 return stack.splice(idx, 1)[0];
10652 removeTop: function () {
10653 return stack.splice(stack.length - 1, 1)[0];
10655 length: function () {
10656 return stack.length;
10664 * A helper directive for the $modal service. It creates a backdrop element.
10666 .directive('modalBackdrop', ['$timeout', function ($timeout) {
10670 templateUrl: 'app/scripts/ng_js_att_tpls/modal/backdrop.html',
10671 link: function (scope) {
10672 scope.animate = false;
10673 //trigger CSS transitions
10674 $timeout(function () {
10675 scope.animate = true;
10681 .directive('modalWindow', ['$modalStack','$timeout','$document', function ($modalStack,$timeout,$document) {
10689 templateUrl: 'app/scripts/ng_js_att_tpls/modal/window.html',
10690 link: function (scope, element, attrs) {
10691 scope.windowClass = attrs.windowClass || '';
10692 $timeout(function () {
10693 // trigger CSS transitions
10694 scope.focusModalFlag = true;
10695 scope.animate = true;
10697 $document.on('focus keydown', function(e){
10698 if (e.which ===9) {
10699 String.prototype.contains = function(it) {
10700 return this.indexOf(it) !== -1;
10702 if (element[0] !== e.target && !element[0].contains( e.target )) {
10703 element[0].focus();
10707 scope.close = function (evt) {
10708 var modal = $modalStack.getTop();
10709 if (modal && modal.value.backdrop && modal.value.backdrop !== 'static' && (evt.target === evt.currentTarget)) {
10710 // Check if preventDefault exists due to lack of support for IE8
10711 if (evt.preventDefault) {
10712 evt.preventDefault();
10713 evt.stopPropagation();
10715 evt.returnValue = false;
10717 $modalStack.dismiss(modal.key, 'backdrop click');
10724 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap',
10725 function ($document, $compile, $rootScope, $$stackedMap) {
10726 var OPENED_MODAL_CLASS = 'modal-open';
10727 var backdropjqLiteEl, backdropDomEl;
10728 var backdropScope = $rootScope.$new(true);
10729 var openedWindows = $$stackedMap.createNew();
10730 var $modalStack = {};
10731 function backdropIndex() {
10732 var topBackdropIndex = -1;
10733 var opened = openedWindows.keys();
10734 for (var i = 0; i < opened.length; i++) {
10735 if (openedWindows.get(opened[i]).value.backdrop) {
10736 topBackdropIndex = i;
10739 return topBackdropIndex;
10742 $rootScope.$watch(backdropIndex, function(newBackdropIndex){
10743 backdropScope.index = newBackdropIndex;
10746 function removeModalWindow(modalInstance) {
10748 var body = $document.find('body').eq(0);
10749 var modalWindow = openedWindows.get(modalInstance).value;
10750 //clean up the stack
10751 openedWindows.remove(modalInstance);
10752 ////remove window DOM element
10753 modalWindow.modalDomEl.remove();
10754 body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
10756 //remove backdrop if no longer needed
10757 if (backdropDomEl && backdropIndex() === -1) {
10758 backdropDomEl.remove();
10759 backdropDomEl = undefined;
10762 modalWindow.modalScope.$destroy();
10764 $document.bind('keydown', function (evt) {
10766 if (evt.which === 27) {
10767 modal = openedWindows.top();
10768 if (modal && modal.value.keyboard) {
10769 $rootScope.$apply(function () {
10770 $modalStack.dismiss(modal.key);
10776 $modalStack.open = function (modalInstance, modal) {
10777 openedWindows.add(modalInstance, {
10778 deferred: modal.deferred,
10779 modalScope: modal.scope,
10780 backdrop: modal.backdrop,
10781 keyboard: modal.keyboard
10783 var body = $document.find('body').eq(0);
10785 if (backdropIndex() >= 0 && !backdropDomEl) {
10786 backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
10787 backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
10788 body.append(backdropDomEl);
10790 var angularDomEl = angular.element('<div modal-window></div>');
10791 angularDomEl.attr('window-class', modal.windowClass);
10792 angularDomEl.attr('index', openedWindows.length() - 1);
10793 angularDomEl.html(modal.content);
10795 var modalDomEl = $compile(angularDomEl)(modal.scope);
10796 openedWindows.top().value.modalDomEl = modalDomEl;
10797 body.append(modalDomEl);
10798 body.addClass(OPENED_MODAL_CLASS);
10801 $modalStack.close = function (modalInstance, result) {
10802 var modal = openedWindows.get(modalInstance);
10804 modal.value.deferred.resolve(result);
10805 removeModalWindow(modalInstance);
10809 $modalStack.dismiss = function (modalInstance, reason) {
10810 var modalWindow = openedWindows.get(modalInstance).value;
10812 modalWindow.deferred.reject(reason);
10813 removeModalWindow(modalInstance);
10817 $modalStack.getTop = function () {
10818 return openedWindows.top();
10821 return $modalStack;
10824 .provider('$modal', function () {
10826 var $modalProvider = {
10828 //can be also false or 'static'
10832 $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
10833 function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
10835 function getTemplatePromise(options) {
10836 return options.template ? $q.when(options.template) :
10837 $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
10838 return result.data;
10842 function getResolvePromises(resolves) {
10843 var promisesArr = [];
10844 angular.forEach(resolves, function (value) {
10845 if (angular.isFunction(value) || angular.isArray(value)) {
10846 promisesArr.push($q.when($injector.invoke(value)));
10849 return promisesArr;
10851 $modal.open = function (modalOptions) {
10852 var modalResultDeferred = $q.defer();
10853 var modalOpenedDeferred = $q.defer();
10855 //prepare an instance of a modal to be injected into controllers and returned to a caller
10856 var modalInstance = {
10857 result: modalResultDeferred.promise,
10858 opened: modalOpenedDeferred.promise,
10859 close: function (result) {
10860 $modalStack.close(modalInstance, result);
10862 dismiss: function (reason) {
10863 $modalStack.dismiss(modalInstance, reason);
10866 //merge and clean up options
10867 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
10868 modalOptions.resolve = modalOptions.resolve || {};
10871 if (!modalOptions.template && !modalOptions.templateUrl) {
10872 throw new Error('One of template or templateUrl options is required.');
10875 var templateAndResolvePromise =
10876 $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
10877 templateAndResolvePromise.then(function(tplAndVars) {
10878 var modalScope = (modalOptions.scope || $rootScope).$new();
10879 modalScope.$close = modalInstance.close;
10880 modalScope.$dismiss = modalInstance.dismiss;
10882 var ctrlInstance, ctrlLocals = {};
10883 var resolveIter = 1;
10886 if (modalOptions.controller) {
10887 ctrlLocals.$scope = modalScope;
10888 ctrlLocals.$modalInstance = modalInstance;
10889 angular.forEach(modalOptions.resolve, function (value, key) {
10890 ctrlLocals[key] = tplAndVars[resolveIter++];
10893 ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
10896 $modalStack.open(modalInstance, {
10898 deferred: modalResultDeferred,
10899 content: tplAndVars[0],
10900 backdrop: modalOptions.backdrop,
10901 keyboard: modalOptions.keyboard,
10902 windowClass: modalOptions.windowClass
10905 }, function(reason) {
10906 modalResultDeferred.reject(reason);
10909 templateAndResolvePromise.then(function () {
10910 modalOpenedDeferred.resolve(true);
10912 modalOpenedDeferred.reject(false);
10915 return modalInstance;
10922 return $modalProvider;
10925 .directive("simpleModal", ["$modal", function($modal) {
10937 link: function(scope, elm) {
10938 elm.bind('click', function(ev) {
10939 ev.preventDefault();
10940 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
10941 scope.simpleModal = elm.attr("href");
10943 if(!scope.backdrop){
10944 scope.backdropclick='static';
10948 scope.backdropclick=true;
10950 if(!scope.keyboard ){
10951 scope.keyboardev=false;
10954 scope.keyboardev=true;
10957 templateUrl: scope.simpleModal,
10958 backdrop:scope.backdropclick,
10959 keyboard:scope.keyboardev,
10960 windowClass:scope.windowClass,
10961 controller: scope.controller
10962 }).result.then(scope.modalOk, scope.modalCancel);
10968 angular.module('att.abs.pagination', ['att.abs.utilities'])
10969 .directive('attPagination', [ function() {
10979 templateUrl: 'app/scripts/ng_js_att_tpls/pagination/pagination.html',
10980 link: function(scope) {
10982 scope.$watch('totalPages', function(value) {
10983 if(angular.isDefined(value) && value !== null){
10986 scope.totalPages = 1;
10990 for (var i = 1; i <= value; i++) {
10991 scope.pages.push(i);
10993 } else if (value > 7) {
10994 var midVal = Math.ceil(value / 2);
10995 scope.pages = [midVal - 1, midVal, midVal + 1];
10997 currentPageChanged(1);
11000 scope.$watch('currentPage', function(value) {
11001 currentPageChanged(value);
11003 var callbackHandler = function(num) {
11004 if (angular.isFunction(scope.clickHandler)){
11005 scope.clickHandler(num);
11008 function currentPageChanged(value) {
11009 if (angular.isDefined(value) && value !== null) {
11010 if (!value || value < 1) {
11013 if (value > scope.totalPages) {
11014 value = scope.totalPages;
11016 if(scope.currentPage !== value) {
11017 scope.currentPage = value;
11018 callbackHandler(scope.currentPage);
11020 if (scope.totalPages > 7) {
11021 if (value < scope.pages[0] && value > 3) {
11022 scope.pages = [value, value + 1, value + 2];
11023 } else if (value > scope.pages[2] && value < scope.totalPages - 2) {
11024 scope.pages = [value - 2, value - 1, value];
11025 } else if (value <= 3) {
11026 scope.pages = [1, 2, 3];
11027 } else if (value >= scope.totalPages - 2) {
11028 scope.pages = [scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
11033 scope.next = function(event) {
11034 event.preventDefault();
11035 if (scope.currentPage < scope.totalPages) {
11036 scope.currentPage += 1;
11037 callbackHandler(scope.currentPage);
11040 scope.prev = function(event) {
11041 event.preventDefault();
11042 if (scope.currentPage > 1) {
11043 scope.currentPage -= 1;
11044 callbackHandler(scope.currentPage);
11047 scope.selectPage = function(value, event) {
11048 event.preventDefault();
11049 scope.currentPage = value;
11050 scope.focusedPage = value;
11051 callbackHandler(scope.currentPage);
11053 scope.checkSelectedPage = function(value) {
11054 if(scope.currentPage === value) {
11059 scope.isFocused = function(page) {
11060 return scope.focusedPage === page;
11066 angular.module('att.abs.paneSelector',[])
11067 .constant('paneGroupConstants',{
11068 SIDE_WIDTH_DEFAULT: '33%',
11069 INNER_PANE_DEFAULT: '67%',
11070 SIDE_PANE_ID: 'sidePane',
11071 NO_DRILL_DOWN: 'none'
11073 .factory('animation', function(){
11076 .directive('sideRow', [function(){
11080 require: ['^sidePane','^paneGroup'],
11081 link: function(scope,element,attr,ctrls){
11082 var sidePaneCtrl = ctrls[0];
11083 var paneGroupCtrl = ctrls[1];
11086 Reset the sidePaneId array if a new
11087 set of ngRepeat data appeared
11089 sidePaneCtrl.sidePaneIds = [];
11092 var paneId =attr['paneId'];
11093 var drillDownTo = attr['drillDownTo'];
11095 sidePaneCtrl.sidePaneRows.push({'paneId':paneId, 'drillDownTo':drillDownTo});
11096 element.on('click', function(){
11097 sidePaneCtrl.currentSelectedRowPaneId = paneId;
11098 paneGroupCtrl.slideOutPane(paneId,true);
11103 .controller('SidePaneCtrl',['$scope', '$element','animation', 'paneGroupConstants',
11104 function($scope,$element,animation, paneGroupConstants){
11106 this.sidePaneTracker = {};
11107 this.currentWidth = paneGroupConstants.SIDE_WIDTH_DEFAULT;
11108 this.paneId = paneGroupConstants.SIDE_PANE_ID;
11109 this.currentSelectedRowPaneId;
11111 this.drillDownToMapper = {};
11113 this.sidePaneRows = [];
11115 this.init = function(){
11117 var sidePaneRows = this.sidePaneRows;
11120 for(var index in sidePaneRows){
11121 if (sidePaneRows.hasOwnProperty(index)) {
11122 var paneId = sidePaneRows[index].paneId;
11123 var drillDownTo = sidePaneRows[index].drillDownTo;
11125 this.drillDownToMapper[paneId] = drillDownTo;
11128 this.currentSelectedRowPaneId = paneId;
11129 this.sidePaneTracker[paneId] = [];
11136 this.getSidePanesList = function(){
11137 return this.sidePaneTracker[this.currentSelectedRowPaneId];
11140 this.addToSidePanesList = function(newPaneId){
11141 if(this.sidePaneTracker[this.currentSelectedRowPaneId] === undefined){
11142 this.sidePaneTracker[this.currentSelectedRowPaneId] = [];
11144 else if(newPaneId){
11145 this.sidePaneTracker[this.currentSelectedRowPaneId].push(newPaneId);
11149 this.setWidth = function(val){
11151 this.currentWidth = val;
11153 animation.set($element,{width:this.currentWidth});
11156 this.resizeWidth = function(val){
11158 this.currentWidth = val;
11160 animation.to($element,.5,{width:val});
11164 .directive('sidePane', ['paneGroupConstants', function(paneGroupConstants){
11169 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/sidePane.html',
11170 require: ['^paneGroup', 'sidePane'],
11171 controller: 'SidePaneCtrl',
11173 link: function(scope,element,attr, ctrls){
11174 var paneGroupCtrl = ctrls[0];
11175 var sidePaneCtrl = ctrls[1];
11176 paneGroupCtrl.addPaneCtrl(paneGroupConstants.SIDE_PANE_ID, sidePaneCtrl);
11180 .directive('drillDownRow', ['$parse', 'paneGroupConstants',function($parse,paneGroupConstants){
11184 require: ['^innerPane','^paneGroup'],
11185 link: function(scope,element,attr,ctrls){
11186 var innerPaneCtrl = ctrls[0];
11187 var paneGroupCtrl = ctrls[1];
11189 element.on('click', function(){
11190 var drillDownTo = innerPaneCtrl.drillDownTo;
11192 if(innerPaneCtrl.drillDownTo !== paneGroupConstants.NO_DRILL_DOWN){
11193 paneGroupCtrl.slideOutPane(drillDownTo);
11199 .controller('InnerPaneCtrl', ['$scope', '$element','animation', 'paneGroupConstants',
11200 function($scope,$element,animation,paneGroupConstants){
11202 this.paneId = $scope.paneId;
11204 this.currentWidth = paneGroupConstants.INNER_PANE_DEFAULT;
11206 this.setWidth = function(val){
11208 this.currentWidth = val;
11210 animation.set($element,{width:this.currentWidth});
11213 this.resizeWidth = function(val,callback){
11214 animation.to($element,.25,{width:val,onComplete: callback});
11217 this.displayNone = function(){
11218 animation.set($element, {display:'none'});
11221 this.displayBlock = function(){
11222 animation.set($element,{display:'block'});
11224 this.hideRightBorder();
11228 this.floatLeft = function(){
11229 animation.set($element,{float:'left'});
11232 this.hideLeftBorder = function(){
11233 animation.set($element, {borderLeftWidth: '0px'});
11236 this.showLeftBorder = function(){
11237 animation.set($element,{borderLeftWidth: '1px'});
11240 this.hideRightBorder = function(){
11241 animation.set($element,{borderRightWidth: '0px'});
11244 this.showRightBorder = function(){
11245 animation.set($element, {borderRightWidth: '1px'});
11248 this.slideFromRight = function(){
11249 animation.set($element, {float:'right'});
11250 animation.set($element, {width: this.currentWidth});
11253 this.startOpen = function(){
11254 return $scope.startOpen;
11258 .directive('innerPane', function(){
11263 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/innerPane.html',
11264 require: ['^paneGroup', 'innerPane'],
11265 controller: 'InnerPaneCtrl',
11269 link: function(scope,element,attr,ctrls){
11271 if(attr.startOpen === ""){
11272 scope.startOpen = true;
11275 var paneGroupCtrl = ctrls[0];
11276 var innerPaneCtrl = ctrls[1];
11277 paneGroupCtrl.addPaneCtrl(scope.paneId,innerPaneCtrl);
11281 .controller('PaneGroupCtrl', ['$scope', '$element', 'paneGroupConstants',function($scope,$element,paneGroupConstants){
11283 this.accountLevelPaneModel = [];
11285 this.title = $scope.title;
11287 this.init = function(){
11288 var sidePane = this.panes[paneGroupConstants.SIDE_PANE_ID];
11294 //Show the other panes that may be set to startOpen
11295 //numOpen starts at 1 because of the side pane
11298 for(key in this.panes){
11299 if(this.panes[key].startOpen && this.panes[key].startOpen()){
11305 width = ((100/numOpen)) + '%';
11309 if(this.panes[sidePane.currentSelectedRowPaneId])
11312 sidePane.setWidth(width);
11313 this.panes[sidePane.currentSelectedRowPaneId].setWidth(width);
11316 sidePane.setWidth();
11317 this.panes[sidePane.currentSelectedRowPaneId].setWidth();
11320 this.panes[sidePane.currentSelectedRowPaneId].displayBlock();
11322 for(key in this.panes){
11323 if(key !== paneGroupConstants.SIDE_PANE_ID && key !== sidePane.currentSelectedRowPaneId){
11324 this.panes[key].displayNone();
11326 this.panes[key].drillDownTo = sidePane.drillDownToMapper[key];
11329 openOtherPanesOnStart(sidePane, this.panes);
11332 function openOtherPanesOnStart(sidePane, panes){
11333 //Build an array of the panes that need to be out
11334 var otherPanesStartOpened = [];
11336 for(index in sidePane.sidePaneRows){
11337 if (sidePane.sidePaneRows.hasOwnProperty(index)) {
11338 var pane = sidePane.sidePaneRows[index];
11340 //Skip the first pane row since we handled it in the begining
11341 if(index > 0 && panes[pane.paneId].startOpen && panes[pane.paneId].startOpen()){
11342 otherPanesStartOpened.push(pane);
11343 //Remember the panes that are opened for the first pane row Index
11344 sidePane.addToSidePanesList(pane.paneId);
11350 for(index in otherPanesStartOpened){
11351 if (otherPanesStartOpened.hasOwnProperty(index)) {
11352 var paneId = otherPanesStartOpened[index].paneId;
11353 var paneCtrl = panes[paneId];
11355 if(paneCtrl && paneCtrl.setWidth && paneCtrl.displayBlock){
11356 paneCtrl.setWidth(width);
11357 paneCtrl.displayBlock();
11367 Resets all the panels to their original positions at the end of a sidebar click
11368 By setting the sideBar to its default width
11369 Setting all panes to float left and displaynone
11370 Setting the pane that was clicked to default width and slide right
11373 this.resetPanes = function(){
11374 for(var key in this.panes){
11375 if(this.panes.hasOwnProperty(key)){
11376 var pane = this.panes[key];
11377 if(pane && (pane.paneId !== paneGroupConstants.SIDE_PANE_ID)){
11379 pane.displayNone();
11384 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11385 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
11389 this.addPaneCtrl = function(paneId,paneCtrl){
11390 this.panes[paneId] = paneCtrl;
11393 this._slideOutPane = function(paneId,isFromSidePane){
11396 //Check current side pane stack to see how many panes are already open for that side pane choice
11397 //then add the new pane that needs to be there
11399 if(isFromSidePane){
11401 //Check if the side pane id has already been clicked
11402 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11403 panesList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11408 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID] && this.panes[paneId]){
11409 this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId = paneId;
11410 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList();
11412 this.panes[paneId].slideFromRight();
11413 this.panes[paneId].displayBlock();
11415 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
11419 else if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID]){
11420 //Restore the panes based on the panelist
11421 if(panesList.length === 0 && this.panes[paneId]){
11422 //Only one pane is out
11423 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
11424 this.panes[paneId].displayBlock();
11425 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
11428 //Multiple panes out
11429 var numPanes = panesList.length + 2;
11430 var width = ((100/numPanes)) + '%';
11431 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(width);
11433 //Set the sidePanes pane
11434 //set the panes children list
11435 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11436 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
11437 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].setWidth(width);
11440 for(var i in panesList){
11441 if(this.panes[panesList[i]]){
11442 this.panes[panesList[i]].displayBlock();
11443 this.panes[panesList[i]].setWidth(width);
11451 //Have to check the paneId that was given and where it is drilling down to
11452 var isPaneInStack = false;
11456 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11457 stackPaneList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11460 for(var j in stackPaneList){
11461 if(stackPaneList.hasOwnProperty(j)){
11462 var pId = stackPaneList[j];
11463 if(pId === paneId){
11464 isPaneInStack = true;
11470 if(!isPaneInStack && this.panes[paneGroupConstants.SIDE_PANE_ID]){
11471 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList(paneId);
11474 var sidePanesListLength;
11476 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11477 sidePanesListLength = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList().length;
11480 var numberPanes = sidePanesListLength + 2;
11481 var widthToSet = ((100/numberPanes)) + '%';
11483 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11484 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(widthToSet);
11489 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
11490 slideInPaneId = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList()[sidePanesListLength - 1];
11495 if(that.panes[paneGroupConstants.SIDE_PANE_ID]){
11496 panesList = that.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11499 for(var p in panesList){
11500 if(panesList.hasOwnProperty(p)){
11501 var paneListPaneId = panesList[p];
11502 var pane = this.panes[paneListPaneId];
11503 if(paneListPaneId !== slideInPaneId && pane){
11504 pane.setWidth(widthToSet);
11505 pane.displayBlock();
11511 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11512 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
11513 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].showRightBorder();
11515 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].resizeWidth(width,function(){
11517 if(that.panes[slideInPaneId] && that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11518 that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].hideRightBorder();
11519 that.panes[slideInPaneId].setWidth(width);
11520 that.panes[slideInPaneId].slideFromRight();
11521 that.panes[slideInPaneId].displayBlock();
11522 that.panes[slideInPaneId].floatLeft();
11530 this.slideOutPane = function(paneId,isFromSidePane){
11531 this._slideOutPane(paneId,isFromSidePane);
11535 .directive('paneGroup', ['$timeout',function($timeout){
11540 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html',
11543 controller: 'PaneGroupCtrl',
11544 link: function(scope,element,attr,ctrl){
11546 $timeout(initialize,100);
11548 function initialize(){
11555 angular.module('att.abs.profileCard', [])
11556 .constant('profileStatus',{
11558 ACTIVE:{status:"Active",color:"green"},
11559 DEACTIVATED:{status:"Deactivated",color:"red"},
11560 LOCKED:{status:"Locked",color:"red"},
11561 IDLE:{status:"Idle",color:"yellow"},
11562 PENDING:{status:"Pending",color:"blue"}
11564 role:"COMPANY ADMINISTRATOR"
11566 .directive('profileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
11570 templateUrl:function(element, attrs){
11571 if(!attrs.addUser){
11572 return 'app/scripts/ng_js_att_tpls/profileCard/profileCard.html';
11575 return 'app/scripts/ng_js_att_tpls/profileCard/addUser.html';
11581 link: function(scope, elem, attr){
11583 function isImage(src) {
11584 var deferred = $q.defer();
11585 var image = new Image();
11586 image.onerror = function() {
11587 deferred.reject(false);
11589 image.onload = function() {
11590 deferred.resolve(true);
11592 if(src!==undefined && src.length>0 ){
11595 deferred.reject(false);
11597 return deferred.promise;
11601 isImage(scope.profile.img).then(function(img) {
11604 var splitName=(scope.profile.name).split(' ');
11606 for(var i=0;i<splitName.length;i++){
11607 scope.initials += splitName[i][0];
11609 if(scope.profile.role.toUpperCase()===profileStatus.role){
11612 var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
11614 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
11615 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
11616 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
11617 scope.profile.lastLogin=scope.profile.state;
11620 var today=new Date().getTime();
11621 var lastlogin=new Date(scope.profile.lastLogin).getTime();
11622 var diff=(today-lastlogin)/(1000*60*60*24);
11624 scope.profile.lastLogin="Today";
11627 scope.profile.lastLogin="Yesterday";
11633 angular.module('att.abs.progressBars', [])
11635 .directive('attProgressBar', [function(){
11639 templateUrl : 'app/scripts/ng_js_att_tpls/progressBars/progressBars.html'
11642 angular.module('att.abs.radio', [])
11643 .constant('attRadioConfig', {
11644 activeClass : "att-radio--on",
11645 disabledClass : "att-radio--disabled"
11647 .directive('attRadio', ['$compile','attRadioConfig', function ($compile, attRadioConfig) {
11651 require: 'ngModel',
11652 link: function (scope, element, attr, ctrl) {
11654 var parentDiv = $compile('<div tabindex="0" role="radio" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-radio"></div>')(scope);
11656 element.wrap(parentDiv);
11657 element.parent().append('<div class="att-radio__indicator"></div>');
11658 element.parent().attr("title", attr.title);
11659 element.attr("tabindex","-1");
11661 ngCtrl.$render = function () {
11662 var selected = angular.equals(ngCtrl.$modelValue, attr.attRadio);
11663 element.parent().toggleClass(attRadioConfig.activeClass, selected);
11664 element.parent().attr("aria-checked", selected);
11667 scope.updateModel = function (evt) {
11668 var isActive = element.parent().hasClass(attRadioConfig.activeClass);
11670 if (!isActive && !scope.disabled) {
11671 ngCtrl.$setViewValue(isActive ? null : attr.attRadio);
11674 evt.preventDefault();
11677 attr.$observe('disabled', function (val) {
11678 scope.disabled = (val || val === "disabled" || val === "true");
11679 element.parent().toggleClass(attRadioConfig.disabledClass, scope.disabled);
11680 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
11686 angular.module('att.abs.scrollbar', [])
11687 .constant('attScrollbarConstant', {
11689 // Vertical or horizontal scrollbar? ( x || y ).
11691 // Enable or disable the mousewheel.
11693 // How many pixels must the mouswheel scroll at a time.
11695 // Lock default scrolling window when there is no more content.
11697 //// Enable invert style scrolling
11698 scrollInvert: false,
11699 // Set the size of the scrollbar to auto or a fixed number.
11701 // Set the size of the thumb to auto or a fixed number.
11703 // Set to false to hide the scrollbar if not being used
11704 alwaysVisible: true
11707 .directive('attScrollbar', ['$window', '$timeout', '$parse', '$animate', 'attScrollbarConstant',
11708 function ($window, $timeout, $parse, $animate, attScrollbarConstant) {
11712 templateUrl: 'app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html',
11713 controller: ['$scope','$element','$attrs', function($scope, $element, $attrs) {
11714 var defaults =attScrollbarConstant.defaults;
11715 var options = $attrs.scrollbar;
11717 options = $parse(options)($scope);
11721 this.options = angular.extend({}, defaults, options);
11722 this._defaults = defaults;
11725 $body = angular.element(document.querySelectorAll('body')[0]),
11726 $document = angular.element(document),
11727 $viewport = angular.element($element[0].querySelectorAll('.scroll-viewport')[0]),
11728 $overview = angular.element($element[0].querySelectorAll('.scroll-overview')[0]),
11729 $scrollbar = angular.element($element[0].querySelectorAll('.scroll-bar')[0]),
11730 $thumb = angular.element($element[0].querySelectorAll('.scroll-thumb')[0]),
11732 isHorizontal = this.options.axis === 'x',
11733 hasTouchEvents=false,
11734 // Modern browsers support "wheel"
11735 wheelEvent = ("onwheel" in document ? "wheel" :
11736 // Webkit and IE support at least "mousewheel"
11737 document.onmousewheel !== undefined ? "mousewheel" :
11738 // let's assume that remaining browsers are older Firefox
11740 sizeLabel = isHorizontal ? 'width' : 'height',
11741 sizeLabelCap = sizeLabel.charAt(0).toUpperCase() + sizeLabel.slice(1).toLowerCase(),
11742 posiLabel = isHorizontal ? 'left' : 'top',
11743 // moveEvent = document.createEvent('HTMLEvents'),
11744 restoreVisibilityAfterWheel,
11745 thumbscrolltouch=false,documnetscrolltouch=false;
11746 if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
11747 hasTouchEvents = true;
11749 this.contentPosition = 0;
11750 this.viewportSize = 0;
11751 this.contentSize = 0;
11752 this.contentRatio = 0;
11753 this.trackSize = 0;
11754 this.trackRatio = 0;
11755 this.thumbSize = 0;
11756 this.thumbPosition = 0;
11758 this.initialize = function() {
11759 if (!this.options.alwaysVisible) {
11760 $scrollbar.css('opacity', 0);
11766 this.setSizeData = function() {
11767 this.viewportSize = $viewport.prop('offset' + sizeLabelCap) || 1;
11768 this.contentSize = $overview.prop('scroll' + sizeLabelCap) || 1;
11769 this.contentRatio = this.viewportSize / this.contentSize;
11770 this.trackSize = this.options.trackSize || this.viewportSize;
11771 this.thumbSize = Math.min(this.trackSize, Math.max(0, (this.options.thumbSize || (this.trackSize * this.contentRatio))));
11772 this.trackRatio = this.options.thumbSize ? (this.contentSize - this.viewportSize) / (this.trackSize - this.thumbSize) : (this.contentSize / this.trackSize);
11774 this.update = function(scrollTo) {
11775 self.setSizeData();
11776 mousePosition = $scrollbar.prop('offsetTop');
11778 $scrollbar.toggleClass('disable', this.contentRatio >= 1 || isNaN(this.contentRatio));
11780 if (!this.options.alwaysVisible && this.contentRatio < 1 && this.viewportSize > 0) {
11781 //flash the scrollbar when update happens
11782 $animate.addClass($scrollbar, 'visible').then(function() {
11783 $animate.removeClass($scrollbar, 'visible');
11787 if (scrollTo !== null) {
11788 if (scrollTo==='bottom') {
11789 this.contentPosition = this.contentSize - this.viewportSize;
11791 this.contentPosition = parseInt(scrollTo, 10) || 0;
11794 ensureContentPosition();
11795 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
11796 $scrollbar.css(sizeLabel, self.trackSize + 'px');
11797 $thumb.css(sizeLabel, self.thumbSize + 'px');
11798 $overview.css(posiLabel, -self.contentPosition + 'px');
11802 fireEvent = function(obj, evt) {
11803 var fireOnThis = obj;
11805 if (document.createEvent) {
11806 evtObj = document.createEvent('HTMLEvents');
11807 evtObj.initEvent(evt, true, false);
11808 fireOnThis.dispatchEvent(evtObj);
11810 else if (document.createEventObject) {
11811 evtObj = document.createEventObject();
11812 fireOnThis.fireEvent('on' + evt, evtObj);
11815 function ensureContentPosition() {
11816 // if scrollbar is on, ensure the bottom of the content does not go above the bottom of the viewport
11817 if (self.contentRatio <= 1 && self.contentPosition > self.contentSize - self.viewportSize) {
11818 self.contentPosition = self.contentSize - self.viewportSize;
11820 // if scrollbar is off, ensure the top of the content does not go below the top of the viewport
11821 else if (self.contentRatio > 1 && self.contentPosition > 0) {
11822 self.contentPosition = 0;
11826 function setEvents() {
11828 if (hasTouchEvents) {
11829 $viewport.on('touchstart', touchstart);
11830 $thumb.on('touchstart', touchstart);
11833 $thumb.on('mousedown', start);
11834 $scrollbar.on('mousedown', drag);
11837 angular.element($window).on('resize', resize);
11839 if (self.options.wheel) {
11840 $element.on(wheelEvent, wheel);
11844 function resize() {
11848 function touchstart(event) {
11849 if (1 === event.touches.length) {
11850 event.stopPropagation();
11851 start(event.touches[0]);
11855 function start(event) {
11856 $body.addClass('scroll-no-select');
11857 $element.addClass('scroll-no-select');
11859 if (!self.options.alwaysVisible) {
11860 $scrollbar.addClass('visible');
11862 mousePosition = isHorizontal ? event.clientX : event.clientY;
11863 self.thumbPosition = parseInt($thumb.css(posiLabel), 10) || 0;
11864 if (hasTouchEvents) {
11865 documnetscrolltouch=false;
11866 thumbscrolltouch=false;
11867 $viewport.on('touchmove', touchdrag);
11868 $thumb.on('touchmove',touchdragthumb);
11869 $thumb.on('touchend', end);
11871 $document.on('mousemove', drag);
11872 $document.on('mouseup', end);
11873 $thumb.on('mouseup', end);
11877 function wheel(event) {
11879 if (self.contentRatio >= 1) {
11883 if (!self.options.alwaysVisible) {
11884 //cancel removing visibility if wheel event is triggered before the timeout
11885 if (restoreVisibilityAfterWheel) {
11886 $timeout.cancel(restoreVisibilityAfterWheel);
11888 $scrollbar.addClass('visible');
11890 restoreVisibilityAfterWheel = $timeout(function() {
11891 $scrollbar.removeClass('visible');
11896 var evntObj = (event && event.originalEvent) || event || $window.event,
11897 deltaDir = self.options.axis.toUpperCase(),
11902 wheelSpeed = evntObj.deltaMode === 0 ? self.options.wheelSpeed : 1;
11904 if (self.options.scrollInvert) {
11908 if (wheelEvent === 'mousewheel') {
11909 delta.Y = -1 * evntObj.wheelDelta / 40;
11910 if(evntObj.wheelDeltaX){
11911 delta.X = -1 * evntObj.wheelDeltaX / 40;
11914 delta.X *= -1 / wheelSpeed;
11915 delta.Y *= -1 / wheelSpeed;
11917 var wheelSpeedDelta = delta[deltaDir];
11919 self.contentPosition -= wheelSpeedDelta * self.options.wheelSpeed;
11920 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
11921 fireEvent($element[0], 'move');
11923 ensureContentPosition();
11924 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
11925 $overview.css(posiLabel, -self.contentPosition + 'px');
11927 if (self.options.wheelLock || (self.contentPosition !== (self.contentSize - self.viewportSize) && self.contentPosition !== 0)) {
11928 evntObj.preventDefault();
11932 function touchdrag(event) {
11933 event.preventDefault();
11934 documnetscrolltouch=true;
11935 drag(event.touches[0]);
11937 function touchdragthumb(event){
11938 event.preventDefault();
11939 thumbscrolltouch=true;
11940 drag(event.touches[0]);
11943 function drag(event) {
11945 if (self.contentRatio >= 1) {
11948 var mousePositionNew = isHorizontal ? event.clientX : event.clientY,
11949 thumbPositionDelta = mousePositionNew - mousePosition;
11951 if ((self.options.scrollInvert && !hasTouchEvents) ||
11952 (hasTouchEvents && !self.options.scrollInvert))
11954 thumbPositionDelta = mousePosition - mousePositionNew;
11956 if(documnetscrolltouch && hasTouchEvents){
11957 thumbPositionDelta = mousePosition - mousePositionNew;
11959 if(thumbscrolltouch && hasTouchEvents){
11960 thumbPositionDelta = mousePositionNew - mousePosition;
11962 var thumbPositionNew = Math.min((self.trackSize - self.thumbSize), Math.max(0, self.thumbPosition + thumbPositionDelta));
11963 self.contentPosition = thumbPositionNew * self.trackRatio;
11964 fireEvent($element[0], 'move');
11966 ensureContentPosition();
11967 $thumb.css(posiLabel, thumbPositionNew + 'px');
11968 $overview.css(posiLabel, -self.contentPosition + 'px');
11973 $body.removeClass('scroll-no-select');
11974 $element.removeClass('scroll-no-select');
11975 if (!self.options.alwaysVisible) {
11976 $scrollbar.removeClass('visible');
11978 $document.off('mousemove', drag);
11979 $document.off('mouseup', end);
11980 $thumb.off('mouseup', end);
11981 $document.off('touchmove', touchdrag);
11982 $document.off('ontouchend', end);
11983 $thumb.off('touchmove',touchdragthumb);
11984 $thumb.off('touchend', end);
11986 this.cleanup = function() {
11987 $viewport.off('touchstart', touchstart);
11988 $thumb.off('mousedown', start);
11989 $scrollbar.off('mousedown', drag);
11990 $thumb.off('touchmove',touchdragthumb);
11991 $thumb.off('touchend', end);
11992 angular.element($window).off('resize', resize);
11993 $element.off(wheelEvent, wheel);
11994 //ensure scrollbar isn't activated
11995 self.options.alwaysVisible = true;
12000 link: function(scope, iElement, iAttrs, controller) {
12001 var position = iElement.css('position');
12002 if (position !== 'relative' && position !== 'absolute') {
12003 iElement.css('position', 'relative');
12005 scope.$watch(function() {
12006 $timeout(function() {
12007 var $overview = angular.element(iElement[0].querySelectorAll('.scroll-overview')[0]);
12008 var newValue = $overview.prop('scrollHeight');
12009 var oldValue = scope.oldValue;
12010 if (newValue !== oldValue) {
12011 scope.oldValue = newValue;
12012 controller.update();
12016 controller.initialize();
12017 iElement.on('$destroy', function() {
12018 controller.cleanup();
12023 angular.module('att.abs.search', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
12024 .directive('attSearch', ["$document", "$filter", "$isElement", '$documentBind', "$timeout", "keymap", function($document,$filter,$isElement,$documentBind,$timeout,keymap){
12027 scope:{cName: '=attSearch'},
12031 templateUrl: 'app/scripts/ng_js_att_tpls/search/search.html',
12032 link: function(scope, element, attr, ctrl) {
12033 scope.selectedIndex = -1;
12034 scope.selectedOption = attr.placeholder;
12035 scope.isDisabled = false;
12036 scope.className = "select2-match";
12037 scope.showSearch = false;
12038 scope.showlist = false;
12039 if(attr.placeholderAsOption === "false")
12041 scope.selectMsg = "";
12045 scope.selectMsg = attr.placeholder;
12047 if (attr.startsWithFilter === "true" || attr.startsWithFilter) {
12048 scope.startsWithFilter = true;
12050 if(attr.showInputFilter === "true"){
12051 scope.showSearch = true;
12053 scope.showDropdown = function(){
12054 if(!(attr.disabled)){
12055 scope.showlist = !scope.showlist;
12056 scope.setSelectTop();
12059 element.bind("keydown", function(e){
12060 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e))
12062 e.preventDefault();
12063 e.stopPropagation();
12065 switch (e.keyCode) {
12066 case keymap.KEY.DOWN:
12067 scope.selectNext();
12069 case keymap.KEY.UP:
12070 scope.selectPrev();
12072 case keymap.KEY.ENTER:
12073 scope.selectCurrent();
12075 case keymap.KEY.BACKSPACE:
12079 case keymap.KEY.SPACE:
12080 scope.title += " ";
12083 case keymap.KEY.ESC:
12084 if(scope.title === "")
12086 scope.showlist = false;
12100 if(typeof scope.showSearch === 'boolean' && !scope.showSearch && e.keyCode !== 9)
12102 scope.showlist = true;
12103 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode):String.fromCharCode(e.keyCode);
12106 else if(e.keyCode === 9)
12108 scope.showlist = false;
12114 scope.selectOption = function(sTitle,sIndex,keepOpen)
12116 if(sIndex === -1 || sIndex === '-1'){
12117 scope.selCategory = "";
12118 scope.selectedIndex = -1;
12119 ctrl.$setViewValue("");
12120 scope.selectedOption = scope.selectMsg;
12124 scope.selCategory = scope.cName[sIndex];
12125 scope.selectedIndex = sIndex;
12126 ctrl.$setViewValue(scope.selCategory);
12127 scope.selectedOption = scope.selCategory.title;
12132 scope.showlist = false;
12137 scope.isDisabled = true;
12139 scope.selectCurrent = function()
12143 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12148 scope.showlist = true;
12149 scope.setSelectTop();
12153 scope.hoverIn = function(cItem)
12155 scope.selectedIndex = cItem;
12157 scope.setSelectTop = function()
12159 $timeout(function ()
12163 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12164 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
12165 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12169 scope.setCurrentTop = function()
12171 $timeout(function ()
12175 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12176 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
12177 if(selectedElemTopPos < (angular.element(containerUL)[0].scrollTop) )
12179 angular.element(containerUL)[0].scrollTop -= 30;
12181 else if((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight))
12183 angular.element(containerUL)[0].scrollTop += 30;
12189 scope.selectNext = function()
12191 if((scope.selectedIndex + 1) <= (scope.cName.length-1))
12193 scope.selectedIndex += 1;
12194 if(!scope.showlist)
12196 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12200 scope.setCurrentTop();
12202 scope.selectPrev = function()
12204 if((scope.selectedIndex - 1) >= 0)
12206 scope.selectedIndex -= 1;
12207 if(!scope.showlist)
12209 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12213 else if(scope.selectedIndex -1 < 0)
12215 scope.selectedIndex = -1;
12216 if(!scope.showlist)
12218 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12222 scope.setCurrentTop();
12225 scope.updateSelection = function(sItem)
12227 scope.selectedOption = sItem.title;
12230 scope.$watch('selCategory',function(value)
12233 scope.updateSelection(value);
12236 ctrl.$viewChangeListeners.push(function(){
12237 scope.$eval(attr.ngChange);
12239 ctrl.$render = function(){
12240 scope.selCategory = ctrl.$viewValue;
12242 var outsideClick = function(e){
12243 var isElement = $isElement(angular.element(e.target), element, $document);
12245 scope.showlist = false;
12249 $documentBind.click('showlist', outsideClick, scope);
12254 angular.module('att.abs.select', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
12255 .directive('attSelect', ["$document", "$filter", "$isElement", '$documentBind', "$timeout", "keymap", function($document,$filter,$isElement,$documentBind,$timeout,keymap){
12258 scope:{cName: '=attSelect'},
12262 templateUrl: 'app/scripts/ng_js_att_tpls/select/select.html',
12263 link: function(scope, element, attr, ctrl) {
12264 scope.selectedIndex = -1;
12265 scope.selectedOption = attr.placeholder;
12266 scope.isDisabled = false;
12267 scope.className = "select2-match";
12268 scope.showSearch = false;
12269 scope.showlist = false;
12270 if(attr.placeholderAsOption === "false")
12272 scope.selectMsg = "";
12276 scope.selectMsg = attr.placeholder;
12278 if (attr.startsWithFilter === "true" || attr.startsWithFilter) {
12279 scope.startsWithFilter = true;
12281 if(attr.showInputFilter === "true"){
12282 scope.showSearch = true;
12284 scope.showDropdown = function(){
12285 if(!(attr.disabled)){
12286 scope.showlist = !scope.showlist;
12287 scope.setSelectTop();
12290 element.bind("keydown", function(e){
12291 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e))
12293 e.preventDefault();
12294 e.stopPropagation();
12296 switch (e.keyCode) {
12297 case keymap.KEY.DOWN:
12298 scope.selectNext();
12300 case keymap.KEY.UP:
12301 scope.selectPrev();
12303 case keymap.KEY.ENTER:
12304 scope.selectCurrent();
12306 case keymap.KEY.BACKSPACE:
12310 case keymap.KEY.SPACE:
12311 scope.title += " ";
12314 case keymap.KEY.ESC:
12315 if(scope.title === "")
12317 scope.showlist = false;
12331 if(typeof scope.showSearch === 'boolean' && !scope.showSearch && e.keyCode !== 9)
12333 scope.showlist = true;
12334 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode):String.fromCharCode(e.keyCode);
12337 else if(e.keyCode === 9)
12339 scope.showlist = false;
12345 scope.selectOption = function(sTitle,sIndex,keepOpen)
12347 if(sIndex === -1 || sIndex === '-1'){
12348 scope.selCategory = "";
12349 scope.selectedIndex = -1;
12350 ctrl.$setViewValue("");
12351 scope.selectedOption = scope.selectMsg;
12355 scope.selCategory = scope.cName[sIndex];
12356 scope.selectedIndex = sIndex;
12357 ctrl.$setViewValue(scope.selCategory);
12358 scope.selectedOption = scope.selCategory.title;
12363 scope.showlist = false;
12368 scope.isDisabled = true;
12370 scope.selectCurrent = function()
12374 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12379 scope.showlist = true;
12380 scope.setSelectTop();
12384 scope.hoverIn = function(cItem)
12386 scope.selectedIndex = cItem;
12388 scope.setSelectTop = function()
12390 $timeout(function ()
12394 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12395 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
12396 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12400 scope.setCurrentTop = function()
12402 $timeout(function ()
12406 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12407 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
12408 if(selectedElemTopPos < (angular.element(containerUL)[0].scrollTop) )
12410 angular.element(containerUL)[0].scrollTop -= 30;
12412 else if((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight))
12414 angular.element(containerUL)[0].scrollTop += 30;
12420 scope.selectNext = function()
12422 if((scope.selectedIndex + 1) <= (scope.cName.length-1))
12424 scope.selectedIndex += 1;
12425 if(!scope.showlist)
12427 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12431 scope.setCurrentTop();
12433 scope.selectPrev = function()
12435 if((scope.selectedIndex - 1) >= 0)
12437 scope.selectedIndex -= 1;
12438 if(!scope.showlist)
12440 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12444 else if(scope.selectedIndex -1 < 0)
12446 scope.selectedIndex = -1;
12447 if(!scope.showlist)
12449 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12453 scope.setCurrentTop();
12456 scope.updateSelection = function(sItem)
12458 scope.selectedOption = sItem.title;
12462 scope.$watch('selCategory',function(value)
12465 scope.updateSelection(value);
12468 ctrl.$viewChangeListeners.push(function(){
12469 scope.$eval(attr.ngChange);
12471 ctrl.$render = function(){
12472 scope.selCategory = ctrl.$viewValue;
12474 var outsideClick = function(e){
12475 var isElement = $isElement(angular.element(e.target), element, $document);
12477 scope.showlist = false;
12481 $documentBind.click('showlist', outsideClick, scope);
12486 .directive('textDropdown', ['$document', '$isElement', '$documentBind', "keymap", function($document,$isElement,$documentBind,keymap) {
12491 actions: '=actions',
12492 defaultAction: '=defaultAction',
12493 onActionClicked: '=?'
12495 templateUrl : 'app/scripts/ng_js_att_tpls/select/textDropdown.html',
12497 link: function(scope, element, attr) {
12498 scope.selectedIndex = 0;
12499 scope.selectedOption = attr.placeholder;
12500 scope.isDisabled = false;
12501 scope.isActionsShown = false;
12503 if(typeof scope.defaultAction === 'undefined')
12505 scope.currentAction = scope.actions[0];
12506 scope.selectedIndex = 0;
12507 } else if (typeof scope.defaultAction !== 'undefined' || scope.defaultAction !== '') {
12508 for (var act in scope.actions)
12510 if (scope.actions[act] === scope.defaultAction)
12512 scope.currentAction = scope.actions[act];
12513 scope.selectedIndex = scope.actions.indexOf(act);
12514 scope.isActionsShown = false;
12521 scope.currentAction = scope.actions[0];
12524 scope.toggle = function() {
12525 scope.isActionsShown = !scope.isActionsShown;
12528 scope.chooseAction = function($event, action){
12530 if ($event != null) {
12531 scope.currentAction = action;
12532 scope.selectedIndex = scope.actions.indexOf(action);
12535 scope.currentAction = scope.actions[scope.selectedIndex];
12538 if (angular.isFunction(scope.onActionClicked))
12540 scope.onActionClicked(scope.currentAction);
12546 scope.isCurrentAction = function(action) {
12547 return (action === scope.currentAction);
12551 element.bind("keydown", function(e){
12552 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e))
12554 e.preventDefault();
12555 e.stopPropagation();
12556 switch (e.keyCode) {
12557 case keymap.KEY.DOWN:
12558 scope.selectNext();
12560 case keymap.KEY.UP:
12561 scope.selectPrev();
12563 case keymap.KEY.ENTER:
12564 scope.selectCurrent();
12566 case keymap.KEY.ESC:
12567 scope.isActionsShown = false;
12579 scope.isDisabled = true;
12583 scope.selectCurrent = function()
12585 if (scope.selectedIndex < 0)
12587 scope.selectedIndex = 0;
12591 if(!scope.isActionsShown) {
12595 scope.chooseAction(null, scope.currentAction);
12599 scope.selectNext = function()
12601 if(scope.isActionsShown)
12603 if((scope.selectedIndex + 1) < scope.actions.length)
12605 scope.selectedIndex += 1;
12610 scope.selectedIndex = (scope.actions.length - 1);
12617 scope.selectPrev = function()
12619 if(scope.isActionsShown)
12621 if((scope.selectedIndex - 1) >= 0)
12623 scope.selectedIndex -= 1;
12626 else if(scope.selectedIndex - 1 < 0)
12628 scope.selectedIndex = 0;
12634 scope.hoverIn = function(cItem)
12636 scope.selectedIndex = cItem;
12642 var outsideClick = function(e) {
12643 var isElement = $isElement(angular.element(e.target), element, $document);
12652 $documentBind.click('isActionsShown', outsideClick, scope);
12658 angular.module('att.abs.slider', ['att.abs.position'])
12659 .constant('sliderDefaultOptions', {
12665 .directive('attSlider', ['sliderDefaultOptions','$position', function(sliderDefaultOptions,$position)
12679 ngModelSingle: '=?',
12682 ngModelDisabled: '=?'
12684 templateUrl: 'app/scripts/ng_js_att_tpls/slider/slider.html',
12685 link: function(scope, elem, attr)
12687 var minOffset, maxOffset, newOffset, offsetRange, valueRange, start_x = 0, disabledRange, disabled, evFlag = false, minValue, maxValue, range, refLow, refHigh, maxPtr, minPtr, singlePtr, getHandles;
12688 scope.minPtrOffset = 0;
12689 scope.maxPtrOffset = 0;
12690 var disableWidth = sliderDefaultOptions.disabledWidth;
12692 var obj = elem.children();
12693 disabledRange = obj[0].children;
12694 disabledRange = angular.element(disabledRange[0]);
12695 getHandles = obj[1].children;
12696 singlePtr = angular.element(getHandles[0]);
12697 minPtr = angular.element(getHandles[1]);
12698 maxPtr = angular.element(getHandles[2]);
12699 disabled = ((attr.ngModelSingle == null) && (attr.ngModelLow == null) && (attr.ngModelHigh == null)) && (attr.ngModelDisabled != null);
12700 range = (attr.ngModelSingle == null) && ((attr.ngModelLow != null) && (attr.ngModelHigh != null));
12701 refLow = 'ngModelLow';
12702 refHigh = 'ngModelHigh';
12708 singlePtr.remove();
12711 disabledRange.remove();
12714 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
12715 scope.handleStyle = {left: disableWidth + 'px'};
12717 minValue = parseFloat(scope.floor);
12718 maxValue = parseFloat(scope.ceiling);
12719 valueRange = maxValue - minValue;
12721 if (attr.width !== undefined) {
12722 maxOffset = attr.width;
12725 if (elem[0].clientWidth !== 0) {
12726 maxOffset = elem[0].clientWidth;
12729 maxOffset = sliderDefaultOptions.width;
12732 offsetRange = maxOffset - minOffset;
12734 scope.keyDown = function(ev){
12735 if(ev.keyCode === 39){
12736 var elemLeft = $position.position(elem).left;
12738 newOffset = sliderDefaultOptions.step + newOffset;
12740 else{newOffset = sliderDefaultOptions.step + elemLeft;}
12742 else if(ev.keyCode === 37){
12743 var ptrLeft = $position.position(singlePtr).left;
12745 if (newOffset!==0){
12746 newOffset = newOffset - sliderDefaultOptions.step ;
12750 newOffset = ptrLeft - sliderDefaultOptions.step ;}
12753 scope.ptrOffset(newOffset);
12757 scope.mouseDown = function(e, ref) {
12763 start_x = e.clientX - newOffset;
12766 start_x = e.clientX;
12769 if (scope.ref === refLow) {
12770 start_x = e.clientX - scope.minPtrOffset;
12773 start_x = e.clientX - scope.maxPtrOffset;
12777 scope.ref= 'ngModelDisabled';
12778 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
12781 // Mouse Move Event
12782 scope.moveElem = function(ev) {
12785 eventX = ev.clientX;
12786 newOffset = eventX - start_x;
12787 scope.ptrOffset(newOffset);
12791 scope.mouseUp = function(ev) {
12793 minPtr.removeClass('dragging');
12794 maxPtr.removeClass('dragging');
12795 singlePtr.removeClass('dragging');
12796 $(document).off('mousemove');
12798 //Function to calculate the current PositionValue
12799 scope.calStep = function(value, precision, step, floor) {
12800 var decimals, remainder, roundedValue, steppedValue;
12801 if (floor === null) {
12804 if (step === null) {
12805 step = 1 / Math.pow(10, precision);
12807 remainder = (value - floor) % step;
12808 steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
12809 decimals = Math.pow(10, precision);
12810 roundedValue = steppedValue * decimals / decimals;
12811 return roundedValue.toFixed(precision);
12813 //Function to calculate Offset Percent
12814 scope.percentOffset = function(offset) {
12815 return ((offset - minOffset) / offsetRange) * 100;
12817 //Function to calculate Offset position
12818 scope.ptrOffset = function(newOffset){
12819 var newPercent, newValue;
12820 newOffset = Math.max(Math.min(newOffset, maxOffset), minOffset);
12821 newPercent = scope.percentOffset(newOffset);
12822 newValue = minValue + (valueRange * newPercent / 100.0);
12824 var rangeSliderWidth;
12825 if (scope.ref === refLow) {
12826 scope.minHandleStyle = {left: newOffset + "px"};
12827 scope.minNewVal = newValue;
12828 scope.minPtrOffset = newOffset;
12829 minPtr.addClass('dragging');
12830 if (newValue > scope.maxNewVal) {
12831 scope.ref = refHigh;
12832 scope.maxNewVal = newValue;
12833 scope.maxPtrOffset = newOffset;
12834 maxPtr.addClass('dragging');
12835 minPtr.removeClass('dragging');
12836 scope.maxHandleStyle = {left: newOffset + "px"};
12840 scope.maxHandleStyle = {left: newOffset + "px"};
12841 scope.maxNewVal = newValue;
12842 scope.maxPtrOffset = newOffset;
12843 maxPtr.addClass('dragging');
12844 if (newValue < scope.minNewVal) {
12845 scope.ref = refLow;
12846 scope.minVal = newValue;
12847 scope.minPtrOffset = newOffset;
12848 minPtr.addClass('dragging');
12849 maxPtr.removeClass('dragging');
12850 scope.minHandleStyle = {left: newOffset + "px"};
12853 rangeSliderWidth = parseInt(scope.maxPtrOffset) - parseInt(scope.minPtrOffset);
12854 scope.rangeStyle = {width: rangeSliderWidth + "px", left: scope.minPtrOffset + "px"};
12857 if (disabled && newOffset > disableWidth) {
12858 scope.rangeStyle = {width: newOffset + "px", zIndex: 0};
12861 singlePtr.addClass('dragging');
12862 scope.rangeStyle = {width: newOffset + "px"};
12864 scope.handleStyle = {left: newOffset + "px"};
12866 if ((scope.precision === undefined) || (scope.step === undefined)) {
12867 scope.precision = sliderDefaultOptions.precision;
12868 scope.step = sliderDefaultOptions.step;
12870 newValue = scope.calStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
12871 scope[scope.ref] = newValue;
12876 ]).directive('attSliderMin',[function()
12879 require: '^attSlider',
12883 templateUrl: 'app/scripts/ng_js_att_tpls/slider/minContent.html'
12886 ]).directive('attSliderMax',[function()
12889 require: '^attSlider',
12893 templateUrl: 'app/scripts/ng_js_att_tpls/slider/maxContent.html'
12897 angular.module('att.abs.splitButtonDropdown', ['att.abs.utilities'])
12898 .directive('attButtonDropdown', ['$document', '$parse', '$documentBind', function($document, $parse, $documentBind) {
12903 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html',
12910 link: function(scope, element, attr) {
12911 scope.isSmall = false;
12912 scope.isDropDownOpen = false;
12913 scope.isActionDropdown = false;
12915 if (attr.small === "") {
12916 scope.isSmall = true;
12919 if (!(scope.btnText)) {
12920 scope.isActionDropdown = true;
12923 scope.clickFxn = function() {
12924 if(typeof scope.btnClick === "function" && !scope.btnLink){
12925 scope.btnClick = $parse(scope.btnClick);
12930 scope.toggleDropdown = function() {
12931 if (!(scope.btnType === 'disabled')) {
12932 scope.isDropDownOpen = !scope.isDropDownOpen;
12936 scope.hideDropdown = function() {
12937 if (!(scope.btnType === 'disabled')) {
12938 scope.isDropDownOpen = false;
12942 var outsideClick = function() {
12943 scope.$apply(function() {
12944 scope.isDropDownOpen = false;
12948 $documentBind.click('isDropDownOpen', outsideClick, scope);
12950 attr.$observe('btnType', function(val) {
12951 scope.btnType = val;
12957 angular.module('att.abs.splitIconButton', ['att.abs.utilities'])
12958 .constant('iconStateConstants', {
12962 NEXT_TO_DROPDOWN:'next-to-dropdown',
12963 LEFT_NEXT_TO_DROPDOWN:'left-next-to-dropdown',
12975 SPLIT_ICON_BTN_EVENT_EMITTER_KEY: 'splitIconButtonTap'
12977 .directive('expandableLine', ['$document',function($document){
12982 require: ['^attSplitIconButton', 'expandableLine'],
12983 controller: ['$scope', function($scope){
12984 $scope.isActive = false;
12985 this.setActiveState = function(isActive){
12986 $scope.isActive = isActive;
12989 this.isActive = $scope.isActive;
12990 this.dirType = $scope.dirType;
12992 template: '<div ng-class="{\'expand-line-container\': !isActive, \'expand-line-container-active\': isActive}"> <div ng-class="{\'hovered-line\':isActive, \'vertical-line\':!isActive}"> </div></div>',
12996 link: function(scope,element,attr,ctrls){
12997 var attSplitIconButtonCtrl = ctrls[0];
12998 var expandableLineCtrl = ctrls[1];
12999 attSplitIconButtonCtrl.addSubCtrl(expandableLineCtrl);
13003 .controller('AttSplitIconCtrl', ['$scope', function($scope){
13004 this.setType = function(type){
13005 $scope.type = type;
13008 this.isDropdown = function(isDropdown){
13009 $scope.isDropdown = isDropdown;
13012 this.dropDownClicked = function(){
13013 if($scope.dropDownClicked)
13014 $scope.dropDownClicked();
13017 this.dirType = $scope.dirType;
13020 .directive('attSplitIcon', ['$document', '$timeout','iconStateConstants','$documentBind','events',
13021 function($document,$timeout,iconStateConstants,$documentBind, events){
13027 require: ['^attSplitIconButton','attSplitIcon'],
13028 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html',
13032 dropDownWatch: '=',
13035 controller:'AttSplitIconCtrl',
13036 link: function(scope,element,attr,ctrls){
13038 var attSplitIconButtonCtrl = ctrls[0];
13039 var attSplitIconCtrl = ctrls[1];
13040 attSplitIconButtonCtrl.addSubCtrl(attSplitIconCtrl);
13042 scope.iconStateConstants = iconStateConstants;
13044 var currentIndex = 0;
13045 var isMyElement = false;
13048 scope.isDropdown = false;
13049 scope.isDropdownOpen = false;
13052 scope.$on(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, function(evnt, data){
13053 if(typeof data == 'boolean' && data){
13054 scope.dropDownClicked();
13057 Check if the dropdown is open and if we are selecting one
13058 of the items, so that when pressing enter it will trigger it.
13060 if(scope.isDropDownOpen){
13061 listElements[currentIndex].eq(0).find('a')[0].click();
13066 //Only trigger the keyboard event if the icon button is a dropdown type
13067 if(scope.isDropdown)
13068 triggerKeyboardEvents(e);
13071 function triggerKeyboardEvents(e){
13072 if(e.which == iconStateConstants.KEYBOARD.ESC){
13075 if( e.which == iconStateConstants.KEYBOARD.UP ||
13076 e.which == iconStateConstants.KEYBOARD.DOWN){
13078 e.preventDefault();
13079 events.stopPropagation(e);
13080 //e.stopPropagation();
13082 if(e.which == iconStateConstants.KEYBOARD.DOWN){
13083 //Dropdown is open and the user taps down again
13085 if(scope.isDropDownOpen){
13086 //Now we need to go through the rows in the dropdown
13087 scope.nextItemInDropdown();
13089 //Dropdown is not open
13091 isMyElement = true;
13093 listElementsInit();
13096 else if(e.which == iconStateConstants.KEYBOARD.UP){
13097 if(scope.isDropDownOpen){
13098 scope.previousItemInDropdown();
13104 isMyElement = false;
13107 }else if(e.which == iconStateConstants.KEYBOARD.ENTER){
13108 if(scope.isDropDownOpen){
13109 listElementsInit();
13115 function listElementsInit(){
13116 if(listElements == undefined){
13118 var liTemps = element.find('li');
13119 for(var i = 0; i < liTemps.length; i++){
13120 listElements.push(liTemps.eq(i));
13122 listElements[currentIndex].children().eq(0).addClass('selected-item');
13128 scope.nextItemInDropdown = function(){
13129 if(listElements && currentIndex < listElements.length - 1){
13131 listElements[currentIndex - 1].children().eq(0).removeClass('selected-item');
13132 listElements[currentIndex].children().eq(0).addClass('selected-item');
13136 scope.previousItemInDropdown = function(){
13137 if(currentIndex > 0){
13139 listElements[currentIndex].children().eq(0).addClass('selected-item');
13141 if(currentIndex + 1 < listElements.length)
13142 listElements[currentIndex + 1].children().eq(0).removeClass('selected-item');
13146 scope.$watch('isIconHovered', function(val){
13147 scope.hoverWatch = val;
13150 scope.$watch('type', function(val){
13152 function toggleValues(isMiddle,isNextToDropDown,isRight,isLeft,isLeftNextDropdown){
13153 scope['isMiddle'] = isMiddle;
13154 scope['isNextToDropDown'] = isNextToDropDown;
13155 scope['isRight'] = isRight;
13156 scope['isLeft'] = isLeft;
13157 scope['isLeftNextDropdown'] = isLeftNextDropdown;
13160 if(val == scope.iconStateConstants.MIDDLE){
13161 toggleValues(true,false,false,true,false);
13163 else if(val == scope.iconStateConstants.LEFT){
13164 toggleValues(false,false,false,true,false);
13166 else if(val == scope.iconStateConstants.RIGHT){
13167 toggleValues(false,false,true,false,false);
13168 }else if(val == scope.iconStateConstants.NEXT_TO_DROPDOWN){
13169 toggleValues(false,true,true,true,false);
13170 }else if(val == scope.iconStateConstants.LEFT_NEXT_TO_DROPDOWN){
13171 toggleValues(false,false,false,true,true);
13175 if(attr.dropDownId && attr.dropDownId != ''){
13176 scope.dropDownId = attr.dropDownId;
13177 scope.isDropdown = true;
13180 scope.dropDownClicked = function(){
13181 isMyElement = true;
13184 scope.toggleDropdown = function(val) {
13185 if(val != undefined)
13186 scope.isDropDownOpen=val;
13188 scope.isDropDownOpen = !scope.isDropDownOpen;
13190 scope.dropDownWatch = scope.isDropDownOpen;
13193 var outsideClick = function(e) {
13194 if(scope.isDropdown){
13196 isMyElement = false;
13197 scope.toggleDropdown();
13199 scope.toggleDropdown(false);
13205 $documentBind.click('isDropdown', outsideClick, scope);
13209 .controller('AttSplitIconButtonCtrl',['$scope', 'iconStateConstants',function($scope,iconStateConstants){
13211 this.subCtrls = [];
13213 $scope.isLeftLineShown=true;
13214 $scope.isRightLineShown=true;
13215 $scope.childrenScopes = [];
13217 var origLeftLineShown = $scope.isLeftLineShown;
13218 var origRightLineShown = $scope.isRightLineShown;
13222 function getDirIndex(dirType){
13224 for(var c in that.subCtrls){
13225 var ctrl = that.subCtrls[c];
13226 if(ctrl.dirType==dirType){
13234 this.addSubCtrl = function(sub){
13235 this.subCtrls.push(sub);
13238 this.isLeftLineShown = function(isShown){
13239 if(isShown == undefined)
13240 return $scope.isLeftLineShown;
13242 $scope.isLeftLineShown = isShown;
13245 this.isRightLineShown = function(isShown){
13246 if(isShown == undefined)
13247 return $scope.isRightLineShown;
13249 $scope.isRightLineShown = isShown;
13252 this.setLeftLineHover = function(isHovered){
13253 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
13255 if($scope.isLeftLineShown){
13256 if(this.subCtrls[leftLineIndex] && this.subCtrls[leftLineIndex].setActiveState){
13257 this.subCtrls[leftLineIndex].setActiveState(isHovered);
13262 this.setRightLineHover = function(isHovered){
13263 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
13264 if($scope.isRightLineShown){
13265 if(this.subCtrls[rightLineIndex] && this.subCtrls[rightLineIndex].setActiveState){
13266 this.subCtrls[rightLineIndex].setActiveState(isHovered);
13271 this.toggleLines = function(isHovered,buttonGroupCtrl,buttonCtrl,isDropDownOpen){
13273 var subIconButtons = buttonGroupCtrl.subIconButtons;
13274 var subIconButtonsLength = subIconButtons.length;
13276 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
13277 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
13279 function noVerticalLineToggle(){
13280 for(var i =0; i < subIconButtonsLength; i++){
13281 if(subIconButtons[i] == buttonCtrl){
13282 if(i + 1 <= subIconButtonsLength - 1){
13283 if(subIconButtons[i+1].isLeftLineShown() && subIconButtons[i+1].subCtrls[leftLineIndex]
13284 && subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState)
13285 subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState(isHovered);
13288 if(subIconButtons[i-1].isRightLineShown() && subIconButtons[i-1].subCtrls[rightLineIndex]
13289 && subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState)
13290 subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState(isHovered);
13297 if(isDropDownOpen){
13299 If the button is next to the dropdown button then just keep the
13300 buttons left line or its left neighbors right line toggled on
13301 If the button is the dropdown button don't do anything
13302 else do things normally witht the button
13304 if(subIconButtons[subIconButtonsLength-1] == buttonCtrl){
13307 else if(subIconButtons[subIconButtonsLength-2]==buttonCtrl){
13308 if(subIconButtons[subIconButtonsLength-2].isLeftLineShown())
13309 subIconButtons[subIconButtonsLength-2].subCtrls[leftLineIndex].setActiveState(isHovered);
13310 else if(subIconButtonsLength - 3 >= 0){
13311 if(subIconButtons[subIconButtonsLength-3].isRightLineShown())
13312 subIconButtons[subIconButtonsLength-3].subCtrls[rightLineIndex].setActiveState(isHovered);
13316 noVerticalLineToggle();
13318 if($scope.isLeftLineShown){
13319 this.subCtrls[leftLineIndex].setActiveState(isHovered);
13322 if($scope.isRightLineShown){
13323 this.subCtrls[rightLineIndex].setActiveState(isHovered);
13328 //Handle Special cases where they aren't showing any vertical lines
13329 //and the dropdown isn't down
13330 if(!$scope.isLeftLineShown && !$scope.isRightLineShown){
13331 noVerticalLineToggle();
13334 if($scope.isLeftLineShown){
13335 if(this.subCtrls[leftLineIndex].setActiveState)
13336 this.subCtrls[leftLineIndex].setActiveState(isHovered);
13339 if($scope.isRightLineShown){
13340 if(this.subCtrls[rightLineIndex].setActiveState)
13341 this.subCtrls[rightLineIndex].setActiveState(isHovered);
13346 this.setButtonType = function(type){
13347 var buttonIndex = getDirIndex(iconStateConstants.DIR_TYPE.BUTTON);
13348 if(this.subCtrls[buttonIndex] && this.subCtrls[buttonIndex].setType)
13349 this.subCtrls[buttonIndex].setType(type);
13353 .directive('attSplitIconButton', ['$document', 'iconStateConstants',
13354 function($document,iconStateConstants){
13360 require: ['^attSplitIconButtonGroup', 'attSplitIconButton'],
13361 controller: 'AttSplitIconButtonCtrl',
13362 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html',
13367 link: function(scope,element,attr,ctrls){
13370 var attSplitButtonGroupCtrl = ctrls[0];
13371 var attSplitIconButtonCtrl = ctrls[1];
13373 attSplitButtonGroupCtrl.addIconButton(attSplitIconButtonCtrl);
13375 element.bind('keydown', function(e){
13376 //Check if the key is the up or down key
13378 if(e.which == iconStateConstants.KEYBOARD.UP ||
13379 e.which == iconStateConstants.KEYBOARD.DOWN ||
13380 e.which == iconStateConstants.KEYBOARD.ENTER ||
13381 e.which == iconStateConstants.KEYBOARD.ESC ) {
13383 scope.clickHandler();
13384 scope.$broadcast(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, e);
13388 scope.dropDownWatch = false;
13390 scope.iconStateConstants = iconStateConstants;
13392 scope.clickHandler = function(){
13393 attSplitButtonGroupCtrl.hideLeftLineRightButton(attSplitIconButtonCtrl);
13396 scope.$watch('isHovered', function(val){
13398 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
13400 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
13404 scope.$watch('dropDownWatch', function(val){
13405 attSplitButtonGroupCtrl.isDropDownOpen = val;
13406 attSplitButtonGroupCtrl.toggleDropdownState(val);
13411 .controller('AttSplitIconButtonGroupCtrl', ['$scope','iconStateConstants',function($scope,iconStateConstants){
13413 this.subIconButtons = [];
13414 this.addIconButton = function(iconButton){
13415 this.subIconButtons.push(iconButton);
13418 this.isDropDownOpen = false;
13420 this.hideLeftLineRightButton = function(btn){
13421 var numButtons = this.subIconButtons.length;
13422 var buttonLeftOfRightMost = this.subIconButtons[numButtons - 2];
13423 var rightMostButton = this.subIconButtons[numButtons -1];
13425 if (btn != buttonLeftOfRightMost && btn != rightMostButton ){
13426 rightMostButton.setLeftLineHover(false);
13430 this.toggleDropdownState = function(isDropDownOpen){
13432 var numButtons = this.subIconButtons.length;
13434 if(numButtons > 2){
13436 if(isDropDownOpen){
13438 if(this.subIconButtons[numButtons - 2].isRightLineShown())
13439 this.subIconButtons[numButtons - 2].setRightLineHover(true);
13441 this.subIconButtons[numButtons - 1].setLeftLineHover(true);
13443 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.NEXT_TO_DROPDOWN);
13446 this.subIconButtons[numButtons - 1].setLeftLineHover(false);
13447 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.MIDDLE);
13452 if(isDropDownOpen){
13453 this.subIconButtons[0].setRightLineHover(true);
13454 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT_NEXT_TO_DROPDOWN);
13456 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT);
13463 .directive('attSplitIconButtonGroup', ['$document', '$timeout', 'iconStateConstants' ,function($document,$timeout,iconStateConstants){
13469 require: 'attSplitIconButtonGroup',
13470 controller: 'AttSplitIconButtonGroupCtrl',
13471 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html',
13473 link: function(scope,element,attr,ctrls){
13475 $timeout(initialize,100);
13477 function initialize(){
13479 var subIconButtonCtrls = ctrls.subIconButtons;
13480 var leftMostButtonIndex = 0;
13481 var rightMostButtonIndex =subIconButtonCtrls.length-1;
13483 //left most button config
13484 subIconButtonCtrls[leftMostButtonIndex].setButtonType(iconStateConstants.LEFT);
13485 subIconButtonCtrls[leftMostButtonIndex].isLeftLineShown(false);
13486 subIconButtonCtrls[leftMostButtonIndex].isRightLineShown(true);
13488 //right most button config
13489 subIconButtonCtrls[rightMostButtonIndex].setButtonType(iconStateConstants.RIGHT);
13490 subIconButtonCtrls[rightMostButtonIndex].isRightLineShown(false);
13491 subIconButtonCtrls[rightMostButtonIndex].isLeftLineShown(false);
13493 //middle buttons config
13494 if(rightMostButtonIndex >= 2){
13496 while(index < rightMostButtonIndex){
13497 subIconButtonCtrls[index].setButtonType(iconStateConstants.MIDDLE);
13498 subIconButtonCtrls[index].isRightLineShown(false);
13499 subIconButtonCtrls[index].isLeftLineShown(false);
13504 while(skipIndex <= rightMostButtonIndex){
13505 if(skipIndex == rightMostButtonIndex){
13506 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
13508 subIconButtonCtrls[skipIndex].isRightLineShown(true);
13509 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
13511 skipIndex = skipIndex + 2;
13515 //reposition the dropdown
13516 var ulElem = element.find('ul');
13517 if(ulElem.length > 0){
13518 var numButtons = rightMostButtonIndex+1;
13519 if(numButtons > 2){
13520 var offset = (numButtons)*34-70+(numButtons/1.5) + 0.5;
13521 var offSetStr = offset+'px';
13522 angular.element(ulElem).css('left',offSetStr);
13523 angular.element(ulElem).css('border-top-left-radius','0px');
13525 angular.element(ulElem).css('left','0px');
13533 angular.module('att.abs.stepSlider', ['att.abs.position'])
13534 .constant('sliderConstants', {
13536 The MIT License (MIT)
13537 Copyright (c) 2013 Julien Valéry
13550 className: "jslider",
13551 selector: ".jslider-"
13557 BLUE_HIGHLIGHT: 'blue',
13558 MAGENTA: 'magenta',
13561 DARK_BLUE: 'dark-blue',
13562 REGULAR: 'regular',
13566 .factory('utils', function () {
13568 The MIT License (MIT)
13569 Copyright (c) 2013 Julien Valéry
13572 offset: function (elm) {
13573 var rawDom = elm[0];
13576 var body = document.documentElement || document.body;
13577 var scrollX = window.pageXOffset || body.scrollLeft;
13578 var scrollY = window.pageYOffset || body.scrollTop;
13579 _x = rawDom.getBoundingClientRect().left + scrollX;
13580 _y = rawDom.getBoundingClientRect().top + scrollY;
13581 return {left: _x, top: _y};
13583 roundUpToScale: function (mousePrc, scale, cutOffWidth, cutOffIndex) {
13589 for (var index = 1; index < scale.length; index++) {
13590 lowerVal = scale[index - 1];
13591 higherVal = scale[index];
13592 middle = ((higherVal - lowerVal) * .5) + lowerVal;
13594 Handles a situation where the user clicks close to the start point of
13595 the slider but the pointer doesn't move
13597 if ((lowerVal === 0 && mousePrc <= middle) || checkEquality(lowerVal, mousePrc)) {
13598 newMousePrc = lowerVal;
13601 else if (lowerVal < mousePrc && (mousePrc < higherVal ||
13602 checkEquality(mousePrc, higherVal)))
13604 newMousePrc = higherVal;
13608 //Check if the newMousePrc is <= the cuttOffPoint
13609 if (cutOffWidth && newMousePrc < cutOffWidth) {
13610 return scale[cutOffIndex];
13613 return newMousePrc;
13616 Checks to see if 2 points are so close that they are
13619 function checkEquality(point1, point2) {
13620 var precision = 0.1;
13621 if (Math.abs(point2 - point1) <= precision) {
13627 valueForDifferentScale: function (from, to, prc, prcToValueMapper) {
13628 var decimalPrc = prc / 100;
13629 if (decimalPrc === 0) {
13632 return prcToValueMapper[prc];
13634 getConversionFactorValue: function (value, conversion, firstDimension) {
13636 Loop through the conversion array and keep checking the
13639 if (value <= conversion[0].startVal) {
13642 scaledDimension: firstDimension
13646 for (var index in conversion) {
13647 var c = conversion[index];
13648 if (value > c.startVal) {
13652 var scaleFactor = conversion[endIndex].scaleFactor;
13653 var scaledVal = value / scaleFactor;
13654 var scaledDimension = conversion[endIndex].dimension;
13656 scaledVal: scaledVal,
13657 scaledDimension: scaledDimension
13662 .factory('sliderDraggable', ['utils', function (utils) {
13664 The MIT License (MIT)
13665 Copyright (c) 2013 Julien Valéry
13667 function Draggable() {
13668 this._init.apply(this, arguments);
13670 Draggable.prototype.oninit = function () {
13672 Draggable.prototype.events = function () {
13674 Draggable.prototype.onmousedown = function () {
13675 this.ptr.css({position: "absolute"});
13677 Draggable.prototype.onmousemove = function (evt, x, y) {
13678 this.ptr.css({left: x, top: y});
13680 Draggable.prototype.onmouseup = function () {
13682 Draggable.prototype.isDefault = {
13688 Draggable.prototype._init = function () {
13689 if (arguments.length > 0) {
13690 this.ptr = arguments[0];
13691 this.parent = arguments[2];
13696 angular.extend(this.is, this.isDefault);
13697 var offset = utils.offset(this.ptr);
13701 width: this.ptr[0].clientWidth,
13702 height: this.ptr[0].clientHeight
13704 this.oninit.apply(this, arguments);
13708 Draggable.prototype._getPageCoords = function (event) {
13710 if (event.targetTouches && event.targetTouches[0]) {
13711 value = {x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY};
13713 value = {x: event.pageX, y: event.pageY};
13717 Draggable.prototype._bindEvent = function (ptr, eventType, handler) {
13718 if (this.supportTouches_) {
13719 ptr[0].attachEvent(this.events_[ eventType ], handler);
13723 ptr.bind(this.events_[ eventType ], handler);
13727 Draggable.prototype._events = function () {
13729 this.supportTouches_ = 'ontouchend' in document;
13731 "click": this.supportTouches_ ? "touchstart" : "click",
13732 "down": this.supportTouches_ ? "touchstart" : "mousedown",
13733 "move": this.supportTouches_ ? "touchmove" : "mousemove",
13734 "up": this.supportTouches_ ? "touchend" : "mouseup",
13735 "mousedown": this.supportTouches_ ? "mousedown" : "mousedown"
13737 var documentElt = angular.element(window.document);
13738 this._bindEvent(documentElt, "move", function (event) {
13739 if (self.is.drag) {
13740 event.stopPropagation();
13741 event.preventDefault();
13742 if (!self.parent.disabled) {
13743 self._mousemove(event);
13747 this._bindEvent(documentElt, "down", function (event) {
13748 if (self.is.drag) {
13749 event.stopPropagation();
13750 event.preventDefault();
13753 this._bindEvent(documentElt, "up", function (event) {
13754 self._mouseup(event);
13756 this._bindEvent(this.ptr, "down", function (event) {
13757 self._mousedown(event);
13760 this._bindEvent(this.ptr, "up", function (event) {
13761 self._mouseup(event);
13765 Draggable.prototype._mousedown = function (evt) {
13766 this.is.drag = true;
13767 this.is.clicked = false;
13768 this.is.mouseup = false;
13769 var coords = this._getPageCoords(evt);
13770 this.cx = coords.x - this.ptr[0].offsetLeft;
13771 this.cy = coords.y - this.ptr[0].offsetTop;
13772 angular.extend(this.d, {
13773 left: this.ptr[0].offsetLeft,
13774 top: this.ptr[0].offsetTop,
13775 width: this.ptr[0].clientWidth,
13776 height: this.ptr[0].clientHeight
13778 if (this.outer && this.outer.get(0)) {
13779 this.outer.css({height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden"});
13781 this.onmousedown(evt);
13783 Draggable.prototype._mousemove = function (evt) {
13784 if (this.uid === 0) {
13787 this.is.toclick = false;
13788 var coords = this._getPageCoords(evt);
13789 this.onmousemove(evt, coords.x - this.cx, coords.y - this.cy);
13791 Draggable.prototype._mouseup = function (evt) {
13792 if (this.is.drag) {
13793 this.is.drag = false;
13794 if (this.outer && this.outer.get(0)) {
13795 if ($.browser.mozilla) {
13796 this.outer.css({overflow: "hidden"});
13798 this.outer.css({overflow: "visible"});
13800 if ($.browser.msie && $.browser.version === '6.0') {
13801 this.outer.css({height: "100%"});
13803 this.outer.css({height: "auto"});
13806 this.onmouseup(evt);
13811 .factory('sliderPointer', ['sliderDraggable', 'utils', function (Draggable, utils) {
13813 The MIT License (MIT)
13814 Copyright (c) 2013 Julien Valéry
13816 function SliderPointer() {
13817 Draggable.apply(this, arguments);
13819 SliderPointer.prototype = new Draggable();
13820 SliderPointer.prototype.oninit = function (ptr, id, _constructor) {
13822 this.parent = _constructor;
13824 this.settings = angular.copy(_constructor.settings);
13826 SliderPointer.prototype.onmousedown = function (evt) {
13827 var off = utils.offset(this.parent.domNode);
13831 width: this.parent.domNode[0].clientWidth,
13832 height: this.parent.domNode[0].clientHeight
13836 width: offset.width,
13837 height: offset.height
13839 this.ptr.addClass("jslider-pointer-hover");
13840 this.setIndexOver();
13842 SliderPointer.prototype.onmousemove = function (evt, x, y) {
13843 var coords = this._getPageCoords(evt);
13844 //val is the percent where the slider pointer is located
13845 var val = this.calc(coords.x);
13846 if (!this.parent.settings.smooth) {
13847 val = utils.roundUpToScale(val,
13848 this.parent.settings.scale,
13849 this.parent.settings.cutOffWidth,
13850 this.parent.settings.cutOffIndex);
13852 var cutOffWidth = this.parent.settings.cutOffWidth;
13853 if (cutOffWidth && val < cutOffWidth) {
13858 SliderPointer.prototype.onmouseup = function (evt) {
13859 if (this.settings.callback && angular.isFunction(this.settings.callback)) {
13860 var val = this.parent.getValue();
13861 this.settings.callback.call(this.parent, val);
13863 this.ptr.removeClass("jslider-pointer-hover");
13865 SliderPointer.prototype.setIndexOver = function () {
13866 this.parent.setPointersIndex(1);
13869 SliderPointer.prototype.index = function (i) {
13871 SliderPointer.prototype.limits = function (x) {
13872 return this.parent.limits(x, this);
13874 SliderPointer.prototype.calc = function (coords) {
13875 var diff = coords - this._parent.offset.left;
13876 var val = this.limits((diff * 100) / this._parent.width);
13879 SliderPointer.prototype.set = function (value, opt_origin) {
13880 this.value.origin = this.parent.round(value);
13881 this._set(this.parent.valueToPrc(value, this), opt_origin);
13883 SliderPointer.prototype._set = function (prc, opt_origin) {
13885 this.value.origin = this.parent.prcToValue(prc);
13887 this.value.prc = prc;
13888 //Sets the location of the SliderPointer
13889 this.ptr.css({left: prc + '%'});
13890 this.parent.redraw(this);
13892 return SliderPointer;
13894 .factory('slider', ['sliderPointer', 'sliderConstants', 'utils', function (SliderPointer, sliderConstants, utils) {
13896 The MIT License (MIT)
13897 Copyright (c) 2013 Julien Valéry
13900 function Slider() {
13901 return this.init.apply(this, arguments);
13903 function changeCutOffWidth(width) {
13904 cutOffDom.css('width', width);
13907 Slider.prototype.changeCutOffWidth = changeCutOffWidth;
13908 Slider.prototype.init = function (inputNode, templateNode, settings) {
13909 this.settings = sliderConstants.SLIDER.settings;
13910 angular.extend(this.settings, angular.copy(settings));
13911 this.inputNode = inputNode;
13912 this.inputNode.addClass("ng-hide");
13913 this.settings.interval = this.settings.to - this.settings.from;
13914 if (this.settings.calculate && $.isFunction(this.settings.calculate)) {
13915 this.nice = this.settings.calculate;
13917 if (this.settings.onstatechange && $.isFunction(this.settings.onstatechange)) {
13918 this.onstatechange = this.settings.onstatechange;
13920 this.is = {init: false};
13922 this.create(templateNode);
13924 Slider.prototype.create = function (templateNode) {
13926 this.domNode = templateNode;
13927 var off = utils.offset(this.domNode);
13931 width: this.domNode[0].clientWidth,
13932 height: this.domNode[0].clientHeight
13934 this.sizes = {domWidth: this.domNode[0].clientWidth, domOffset: offset};
13935 angular.extend(this.o, {
13939 o: angular.element(this.domNode.find('div')[5])
13942 o: angular.element(this.domNode.find('div')[6])
13946 0: angular.element(this.domNode.find('div')[3]),
13947 1: angular.element(this.domNode.find('div')[5])
13950 angular.extend(this.o.labels[0], {
13951 value: this.o.labels[0].o.find("span")
13953 angular.extend(this.o.labels[1], {
13954 value: this.o.labels[1].o.find("span")
13956 if (!$this.settings.value.split(";")[1]) {
13957 this.settings.single = true;
13959 var domNodeDivs = this.domNode.find('div');
13960 cutOffDom = angular.element(domNodeDivs[8]);
13961 if (cutOffDom && cutOffDom.css) {
13962 cutOffDom.css('width', '0%');
13964 var pointers = [angular.element(domNodeDivs[1]), angular.element(domNodeDivs[2])];
13965 angular.forEach(pointers, function (pointer, key) {
13966 $this.settings = angular.copy($this.settings);
13967 var value = $this.settings.value.split(';')[key];
13969 $this.o.pointers[key] = new SliderPointer(pointer, key, $this);
13970 var prev = $this.settings.value.split(';')[key - 1];
13971 if (prev && parseInt(value, 10) < parseInt(prev, 10)) {
13974 var value1 = value < $this.settings.from ? $this.settings.from : value;
13975 value1 = value > $this.settings.to ? $this.settings.to : value;
13976 $this.o.pointers[key].set(value1, true);
13978 $this.domNode.bind('mousedown', $this.clickHandler.apply($this));
13982 this.o.value = angular.element(this.domNode.find("i")[2]);
13983 this.is.init = true;
13984 angular.forEach(this.o.pointers, function (pointer) {
13985 $this.redraw(pointer);
13988 Slider.prototype.clickHandler = function () {
13990 return function (evt) {
13991 if (self.disabled) {
13994 var className = evt.target.className;
13996 if (className.indexOf('jslider-pointer-to') > 0) {
13999 var _off = utils.offset(self.domNode);
14003 width: self.domNode[0].clientWidth,
14004 height: self.domNode[0].clientHeight
14007 var targetPtr = self.o.pointers[targetIdx];
14008 targetPtr._parent = {offset: offset, width: offset.width, height: offset.height};
14009 targetPtr._mousemove(evt);
14010 targetPtr.onmouseup();
14014 Slider.prototype.disable = function (bool) {
14015 this.disabled = bool;
14017 Slider.prototype.nice = function (value) {
14020 Slider.prototype.onstatechange = function () {
14022 Slider.prototype.limits = function (x, pointer) {
14023 if (!this.settings.smooth) {
14024 var step = this.settings.step * 100 / (this.settings.interval);
14025 x = Math.round(x / step) * step;
14027 var another = this.o.pointers[1 - pointer.uid];
14028 if (another && pointer.uid && x < another.value.prc) {
14029 x = another.value.prc;
14031 if (another && !pointer.uid && x > another.value.prc) {
14032 x = another.value.prc;
14040 var val = Math.round(x * 10) / 10;
14043 Slider.prototype.setPointersIndex = function (i) {
14044 angular.forEach(this.getPointers(), function (pointer, i) {
14048 Slider.prototype.getPointers = function () {
14049 return this.o.pointers;
14051 Slider.prototype.onresize = function () {
14054 domWidth: this.domNode[0].clientWidth,
14055 domHeight: this.domNode[0].clientHeight,
14057 left: this.domNode[0].offsetLeft,
14058 top: this.domNode[0].offsetTop,
14059 width: this.domNode[0].clientWidth,
14060 height: this.domNode[0].clientHeight
14063 angular.forEach(this.o.pointers, function (ptr, key) {
14067 Slider.prototype.update = function () {
14071 Slider.prototype.drawScale = function () {
14073 Slider.prototype.redraw = function (pointer) {
14074 if (!this.settings.smooth) {
14075 var newMousePrc = utils.roundUpToScale(pointer.value.prc,
14076 this.settings.scale,
14077 this.settings.cutOffWidth,
14078 this.settings.cutOffIndex);
14079 pointer.value.origin = newMousePrc;
14080 pointer.value.prc = newMousePrc;
14083 if (!this.is.init) {
14087 var width = this.o.pointers[1].value.prc;
14088 var newPos = {left: '0%', width: width + '%'};
14089 this.o.value.css(newPos);
14090 var htmlValue = this.nice(pointer.value.origin);
14091 var scaledDimension = this.settings.firstDimension;
14092 if (this.settings.stepWithDifferentScale && !this.settings.smooth) {
14093 htmlValue = utils.valueForDifferentScale(this.settings.from,
14094 this.settings.to, htmlValue, this.settings.prcToValueMapper);
14096 //This is the base value before the conversion
14097 if (this.settings.realtimeCallback && angular.isFunction(this.settings.realtimeCallback)
14098 && this.settings.cutOffVal !== undefined && pointer.uid === 1) {
14099 this.settings.realtimeCallback(htmlValue);
14101 //Need to change this to the correct value for the scale
14102 if (this.settings.conversion) {
14103 var conversionObj = utils.getConversionFactorValue(parseInt(htmlValue),
14104 this.settings.conversion,
14105 this.settings.firstDimension);
14106 htmlValue = conversionObj.scaledVal;
14107 scaledDimension = conversionObj.scaledDimension;
14109 //Check if we need to round the decimal places
14110 if (this.settings.decimalPlaces || this.settings.decimalPlaces === 0) {
14111 if (typeof htmlValue === 'number') {
14112 htmlValue = htmlValue.toFixed(this.settings.decimalPlaces);
14115 this.o.labels[pointer.uid].value.html(htmlValue + ' ' + scaledDimension);
14116 //Top tooltip label
14117 this.redrawLabels(pointer);
14119 Slider.prototype.redrawLabels = function (pointer) {
14120 function setPosition(label, sizes, prc) {
14121 sizes.margin = -sizes.label / 2;
14122 var domSize = self.sizes.domWidth;
14123 var label_left = sizes.border + sizes.margin;
14124 if (label_left < 0) {
14125 sizes.margin -= label_left;
14127 if (sizes.border + sizes.label / 2 > domSize) {
14129 sizes.right = true;
14131 sizes.right = false;
14132 //Adjust the tooltip location
14133 sizes.margin = -((label.o[0].clientWidth / 2) - label.o[0].clientWidth / 20);
14134 label.o.css({left: prc + "%", marginLeft: sizes.margin, right: "auto"});
14136 label.o.css({left: "auto", right: 0});
14140 var label = this.o.labels[pointer.uid];
14141 var prc = pointer.value.prc;
14143 label: label.o[0].offsetWidth,
14145 border: (prc * domSize) / 100
14147 var another_label = null;
14148 var another = null;
14149 if (!this.settings.single) {
14150 another = this.o.pointers[1 - pointer.uid];
14151 another_label = this.o.labels[another.uid];
14152 switch (pointer.uid) {
14154 if (sizes.border + sizes.label / 2 > another_label.o[0].offsetLeft - this.sizes.domOffset.left) {
14155 another_label.o.css({visibility: "hidden"});
14156 another_label.value.html(this.nice(another.value.origin));
14157 label.o.css({visibility: "hidden"});
14158 prc = (another.value.prc - prc) / 2 + prc;
14159 if (another.value.prc !== pointer.value.prc) {
14160 label.value.html(this.nice(pointer.value.origin) + " – " + this.nice(another.value.origin));
14161 sizes.label = label.o[0].clientWidth;
14162 sizes.border = (prc * domSize) / 100;
14165 another_label.o.css({visibility: "visible"});
14169 if (sizes.border - sizes.label / 2 < another_label.o[0].offsetLeft - this.sizes.domOffset.left + another_label.o[0].clientWidth) {
14170 another_label.o.css({visibility: "hidden"});
14171 another_label.value.html(this.nice(another.value.origin));
14172 label.o.css({visibility: "visible"});
14173 prc = (prc - another.value.prc) / 2 + another.value.prc;
14174 if (another.value.prc !== pointer.value.prc) {
14175 label.value.html(this.nice(another.value.origin) + " – " + this.nice(pointer.value.origin));
14176 sizes.label = label.o[0].clientWidth;
14177 sizes.border = (prc * domSize) / 100;
14180 another_label.o.css({visibility: "visible"});
14185 sizes = setPosition(label, sizes, prc);
14186 var domSize = self.sizes.domWidth;
14187 //This is the 0th pointer
14188 if (another_label) {
14190 label: another_label.o[0].clientWidth,
14192 border: (another.value.prc * this.sizes.domWidth) / 100
14194 sizes = setPosition(another_label, sizes, another.value.prc);
14197 Slider.prototype.redrawLimits = function () {
14198 if (this.settings.limits) {
14199 var limits = [true, true];
14200 for (var key in this.o.pointers) {
14201 if (!this.settings.single || key === 0) {
14202 var pointer = this.o.pointers[key];
14203 var label = this.o.labels[pointer.uid];
14204 var label_left = label.o[0].offsetLeft - this.sizes.domOffset.left;
14205 var limit = this.o.limits[0];
14206 if (label_left < limit[0].clientWidth)
14208 limit = this.o.limits[1];
14209 if (label_left + label.o[0].clientWidth > this.sizes.domWidth - limit[0].clientWidth)
14213 for (var i = 0; i < limits.length; i++) {
14215 angular.element(this.o.limits[i]).addClass("animate-show");}
14217 angular.element(this.o.limits[i]).addClass("animate-hidde");}
14221 Slider.prototype.setValue = function () {
14222 var value = this.getValue();
14223 this.inputNode.attr("value", value);
14224 this.onstatechange.call(this, value, this.inputNode);
14226 Slider.prototype.getValue = function () {
14227 if (!this.is.init){
14231 angular.forEach(this.o.pointers, function (pointer, key) {
14232 if (pointer.value.prc !== undefined && !isNaN(pointer.value.prc)) {
14233 var pointerPrc = pointer.value.prc;
14234 var myValue = $this.prcToValue(pointerPrc);
14235 if (!$this.settings.smooth) {
14236 var myValue = utils.valueForDifferentScale($this.settings.from,
14239 $this.settings.prcToValueMapper);
14241 value += (key > 0 ? ";" : "") + myValue;
14246 Slider.prototype.getPrcValue = function () {
14250 $.each(this.o.pointers, function (i) {
14251 if (this.value.prc !== undefined && !isNaN(this.value.prc))
14252 value += (i > 0 ? ";" : "") + this.value.prc;
14256 Slider.prototype.prcToValue = function (prc) {
14258 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
14259 var h = this.settings.heterogeneity;
14261 var _from = this.settings.from;
14262 for (var i = 0; i <= h.length; i++) {
14265 v = h[i].split("/");}
14267 v = [100, this.settings.to];}
14268 if (prc >= _start && prc <= v[0]) {
14269 value = _from + ((prc - _start) * (v[1] - _from)) / (v[0] - _start);
14276 value = this.settings.from + (prc * this.settings.interval) / 100;
14278 var roundedValue = this.round(value);
14279 return roundedValue;
14281 Slider.prototype.valueToPrc = function (value, pointer) {
14283 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
14284 var h = this.settings.heterogeneity;
14286 var _from = this.settings.from;
14287 for (var i = 0; i <= h.length; i++) {
14290 v = h[i].split("/");
14292 v = [100, this.settings.to];
14293 if (value >= _from && value <= v[1]) {
14294 prc = pointer.limits(_start + (value - _from) * (v[0] - _start) / (v[1] - _from));
14300 prc = pointer.limits((value - this.settings.from) * 100 / this.settings.interval);
14304 Slider.prototype.round = function (value) {
14305 value = Math.round(value / this.settings.step) * this.settings.step;
14306 if (this.settings.round){
14307 value = Math.round(value * Math.pow(10, this.settings.round)) / Math.pow(10, this.settings.round);}
14309 value = Math.round(value);}
14314 .directive('attStepSlider', [
14315 '$compile', '$templateCache', '$timeout', '$window', 'slider', 'sliderConstants', 'utils',
14316 function (compile, templateCache, timeout, win, Slider, sliderConstants, utils) {
14318 The MIT License (MIT)
14319 Copyright (c) 2013 Julien Valéry
14321 var templateUrl = 'app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html';
14324 require: '?ngModel',
14330 templateUrl: templateUrl,
14331 link: function (scope, element, attrs, ngModel) {
14334 scope.mainSliderClass = 'step-slider';
14335 element.after(compile(templateCache.get(templateUrl))(scope, function (clonedElement, scope) {
14336 scope.tmplElt = clonedElement;
14338 ngModel.$render = function () {
14339 if (ngModel.$viewValue.split && ngModel.$viewValue.split(";").length === 1) {
14340 ngModel.$viewValue = '0;' + ngModel.$viewValue;
14341 } else if (typeof (ngModel.$viewValue) === 'number') {
14342 ngModel.$viewValue = '0;' + ngModel.$viewValue;
14344 if (!ngModel.$viewValue && ngModel.$viewValue !== 0) {
14347 if (typeof (ngModel.$viewValue) === 'number') {
14348 ngModel.$viewValue = '' + ngModel.$viewValue;
14350 if (scope.slider) {
14351 var firstPointer = '0';
14352 scope.slider.getPointers()[0].set(firstPointer, true);
14353 if (ngModel.$viewValue.split(";")[1]) {
14354 var value = ngModel.$viewValue.split(";")[1];
14355 if (value.length >= 4) {
14356 value = value.substring(0, 2);
14358 if (!scope.options.realtime)
14359 scope.options.callback(parseFloat(ngModel.$viewValue.split(";")[1]));
14360 scope.slider.getPointers()[1].set(ngModel.$viewValue.split(";")[1], true);
14364 var init = function () {
14365 scope.from = '' + scope.options.from;
14366 scope.to = '' + scope.options.to;
14367 if (scope.options.calculate && typeof scope.options.calculate === 'function') {
14368 scope.from = scope.options.calculate(scope.from);
14369 scope.to = scope.options.calculate(scope.to);
14371 scope.showDividers = scope.options.showDividers;
14372 scope.COLORS = sliderConstants.COLORS;
14373 scope.sliderColor = scope.options.sliderColor;
14374 if (!scope.sliderColor)
14375 scope.sliderColor = sliderConstants.COLORS.REGULAR;
14376 var scaleArray = scope.options.scale;
14377 //Make a copy of the scaleArray before converting it to percentage for the bars
14378 var nonPercentScaleArray = [];
14379 //Create Mapper for the percentage to value
14380 var prcToValueMapper = {};
14381 for (var i in scaleArray) {
14382 var s = scaleArray[i];
14383 nonPercentScaleArray.push(s);
14385 function addScaleArrayStartAndEnd() {
14386 if (scaleArray[0] !== 0) {
14387 scaleArray.splice(0, 0, 0);
14389 if (scaleArray[scaleArray.length - 1] !== 100) {
14390 scaleArray.splice(scaleArray.length, 0, 100);
14393 function convertScaleArrayToPercentage() {
14394 if (scaleArray[scaleArray.length - 1] !== scope.options.to) {
14395 scaleArray.splice(scaleArray.length, 0, scope.options.to);
14397 for (var i in scaleArray) {
14398 var fromValueCheck = (scaleArray[i] / scope.options.from);
14399 var toValueCheck = (scaleArray[i] / scope.options.to);
14400 var prcValue = ((scaleArray[i] - scope.options.from) / (scope.options.to - scope.options.from)) * 100;
14401 var realValue = scaleArray[i];
14402 if (toValueCheck === 1) {
14405 else if (fromValueCheck === 1) {
14408 scaleArray[i] = prcValue;
14409 prcToValueMapper['' + prcValue] = realValue;
14412 if ((scope.options.from !== 0 || scope.options.to !== 100)
14413 && scope.options.smooth) {
14415 scale array is in real values.
14417 addScaleArrayStartAndEnd();
14418 scope.options.stepWithDifferentScale = true;
14420 else if ((scope.options.from !== 0 || scope.options.to !== 100)
14421 && !scope.options.smooth) {
14423 Case for different from and to values other than 0 and 100
14424 so we have to do some different calculations
14426 scope.options.stepWithDifferentScale = true;
14427 convertScaleArrayToPercentage();
14428 addScaleArrayStartAndEnd();
14432 This is the normal case where the from and to values are 0 and
14435 //Check that the scale starts at 0 and 100
14436 convertScaleArrayToPercentage();
14437 addScaleArrayStartAndEnd();
14439 var decimalPlaces = 0;
14440 if (scope.options.decimalPlaces) {
14441 decimalPlaces = scope.options.decimalPlaces;
14443 //Modify the endDimension based on whether converison was passed in
14444 //Also change the toStr value to scale to the last factor
14445 scope.endDimension = scope.options.dimension;
14446 if (scope.options.conversion) {
14447 //Get the dimension of the last conversion
14448 var lastIndex = scope.options.conversion.length - 1;
14449 var lastDimension = scope.options.conversion[lastIndex].dimension;
14450 var lastScaleFactor = scope.options.conversion[lastIndex].scaleFactor;
14451 scope.endDimension = " " + lastDimension;
14453 var toVal = (scope.to / lastScaleFactor).toFixed(decimalPlaces);
14454 scope.toStr = toVal;
14456 scope.toStr = scope.options.to;
14459 from: scope.options.from,
14460 to: scope.options.to,
14461 step: scope.options.step,
14462 smooth: scope.options.smooth,
14464 stepWithDifferentScale: scope.options.stepWithDifferentScale,
14465 round: scope.options.round || false,
14466 value: ngModel.$viewValue,
14467 scale: scope.options.scale,
14468 nonPercentScaleArray: nonPercentScaleArray,
14469 prcToValueMapper: prcToValueMapper,
14470 firstDimension: scope.options.dimension,
14471 decimalPlaces: decimalPlaces,
14472 conversion: scope.options.conversion
14474 if (angular.isFunction(scope.options.realtime)) {
14475 OPTIONS.realtimeCallback = function (value) {
14476 ngModel.$setViewValue(value);
14477 scope.options.callback(value);
14481 OPTIONS.callback = forceApply;
14483 OPTIONS.calculate = scope.options.calculate || undefined;
14484 OPTIONS.onstatechange = scope.options.onstatechange || undefined;
14485 timeout(function () {
14486 var scaleDiv = scope.tmplElt.find('div')[7];
14487 if (!OPTIONS.conversion) {
14488 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-left', '10px');
14489 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-right', '15px');
14491 scope.slider = angular.element.slider(element, scope.tmplElt, OPTIONS);
14492 angular.element(scaleDiv).html(scope.generateScale());
14493 scope.drawScale(scaleDiv);
14495 scope.$watch('options.disable', function (val) {
14496 if (scope.slider) {
14497 scope.tmplElt.toggleClass('disabled', val);
14498 scope.slider.disable(val);
14501 scope.$watch('cutOff', function (cutOffVal) {
14502 if (cutOffVal && cutOffVal > 0) {
14503 var cutOffPrc = (cutOffVal - scope.slider.settings.from) / (scope.slider.settings.to -
14504 scope.slider.settings.from);
14505 cutOffPrc = cutOffPrc * 100;
14506 scope.isCutOffSlider = true;
14507 scope.slider.settings.cutOffWidth = cutOffPrc;
14508 //cutOffVal is the actual value of the cutoff point
14509 scope.cutOffVal = cutOffVal;
14510 if (scope.options.conversion) {
14511 var convertedVal = utils.getConversionFactorValue(cutOffVal, scope.options.conversion, scope.options.dimension);
14512 convertedVal.scaledVal = parseFloat(convertedVal.scaledVal).toFixed(scope.options.decimalPlaces);
14513 scope.cutOffVal = convertedVal.scaledVal + ' ' + convertedVal.scaledDimension;
14515 scope.slider.settings.cutOffVal = cutOffVal;
14516 //Calculate the cutOff percentage
14517 scope.slider.changeCutOffWidth(cutOffPrc + '%');
14518 var scale = scope.slider.settings.nonPercentScaleArray;
14519 //Calculate where the cutOff point in relation to the scale array
14520 for (var i in scale) {
14522 var lowerVal = scale[i - 1];
14523 var higherVal = scale[i];
14524 if (cutOffVal > lowerVal && cutOffVal <= higherVal) {
14525 scope.slider.settings.cutOffIndex = i;
14530 scope.slider.settings.cutOffVal = 0;
14535 function initListener() {
14536 angular.element(win).bind('resize', function (event) {
14537 scope.slider.onresize();
14540 scope.generateScale = function () {
14541 if (scope.options.scale && scope.options.scale.length > 0) {
14543 var s = scope.options.scale;
14544 var position = 'left';
14545 for (var i = 0; i < s.length; i++) {
14546 if (i !== 0 && i !== s.length - 1) {
14547 var scaledPosition = ((s[i] - scope.from) / (scope.to - scope.from)) * 100;
14548 if (scope.options.stepWithDifferentScale && !scope.options.smooth) {
14549 scaledPosition = s[i];
14551 str += '<span style="' + position + ': ' + scaledPosition + '%"></span>';
14559 scope.drawScale = function (scaleDiv) {
14560 angular.forEach(angular.element(scaleDiv).find('ins'), function (scaleLabel, key) {
14561 scaleLabel.style.marginLeft = -scaleLabel.clientWidth / 2;
14564 var forceApply = function (value) {
14565 var val = value.split(";")[1];
14566 scope.$apply(function () {
14567 ngModel.$setViewValue(parseInt(val));
14569 if (scope.options.callback) {
14570 scope.options.callback(parseInt(val));
14573 scope.$watch('options', function (value) {
14576 angular.element.slider = function (inputElement, element, settings) {
14577 if (!element.data('jslider'))
14578 element.data('jslider', new Slider(inputElement, element, settings));
14579 var sliderObj = element.data('jslider');
14585 angular.module('att.abs.steptracker', ['att.abs.transition'])
14586 .directive('steptracker', ['$timeout', function ($timeout) {
14588 // This allows dev's clickHandler to cancel an operation
14592 cstep: "=currentStep",
14593 clickHandler: '=?',
14598 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/step-tracker.html',
14599 link: function (scope, elem) {
14600 if (scope.disableClick === undefined) {
14601 scope.disableClick = false;
14603 $timeout(function () {
14604 if (scope.cstep < 1) {
14607 else if (scope.cstep > scope.sdata.length) {
14608 scope.cstep = scope.sdata.length;
14610 var divs = elem.find('div');
14611 var slidertracks = [];
14612 for (var i in divs) {
14613 if (divs.eq(i)[0]) {
14614 var el = divs.eq(i)[0].className;
14615 if (el.indexOf('track ng-scope') > -1) {
14616 slidertracks.push(divs.eq(i));
14620 var currentPage,totalPage,currentTrack = updateCurrentTrack(scope.cstep);
14621 function updateCurrentTrack(step) {
14622 // Always return the step-1 because array starts at 0
14623 return angular.element(slidertracks[step - 1]);
14625 function updateTrackWidth() {
14626 if (scope.cstep > 0 && scope.cstep <= scope.sdata.length - 1 && currentPage > 0) {
14627 var newWidth = ((currentPage / totalPage) * 100) + "%";
14628 currentTrack = updateCurrentTrack(scope.cstep);
14629 currentTrack.css('width', newWidth);
14632 function updatePages() {
14633 if (scope.cstep <= scope.sdata.length) {
14634 currentPage = scope.sdata[scope.cstep - 1]['currentPage'];
14635 totalPage = scope.sdata[scope.cstep - 1]['totalPages'];
14638 // dynamically add width for steps, depending on the number of steps.
14639 scope.set_width = function (indexval) {
14640 var setwidth = (100 / (scope.sdata.length - 1)) + "%";
14641 // skip last element and add width for all other element
14642 if ((scope.sdata.length - 1) > indexval) {
14643 return {'width': setwidth};
14646 scope.$watch('sdata', function () {
14648 var prevStep = scope.cstep;
14649 // Before anything, ensure currentPage is never below 1
14650 if (currentPage < 1) {
14652 if (scope.cstep !== 1) {
14653 // Decrease step, current track width is 0%, new step width updates
14658 // Move to next step, reset currentPage, totalPage, and ensure previous steps are completed
14659 if (currentPage > totalPage) {
14660 if (scope.cstep > scope.sdata.length - 1) {
14664 currentPage = totalPage;
14665 updateTrackWidth();
14668 updateTrackWidth();
14671 if (currentPage < 1 && prevStep === scope.cstep) {
14673 if (scope.cstep > 1) {
14675 scope.sdata[scope.cstep - 1]['currentPage'] = scope.sdata[scope.cstep - 1]['totalPages'];
14676 scope.sdata[scope.cstep]['currentPage'] = 1;
14679 updateTrackWidth();
14681 //add the active class for current step
14682 scope.activestep = function (index) {
14683 return (index === scope.cstep - 1);
14685 //add the done class for finished step
14686 scope.donesteps = function (index) {
14687 return (index < scope.cstep - 1);
14689 //add the last class for final step
14690 scope.laststep = function (index) {
14691 return (index === scope.sdata.length - 1);
14693 scope.isIncomplete = function (index) {
14694 if (index === scope.cstep - 1) {
14697 if (index >= 0 && index < scope.sdata.length - 1) {
14698 var step = scope.sdata[index];
14699 return (step['currentPage'] <= step['totalPages']);
14703 scope.stepclick = function ($event, steps) {
14704 // If we are decreasing steps, reset all currentPage counts to 1
14705 if (steps < scope.cstep) {
14706 for (var i = scope.cstep - 1; i > steps; i--) {
14707 scope.sdata[i]['currentPage'] = 1;
14709 scope.sdata[steps]['currentPage']--;
14711 if (angular.isFunction(scope.clickHandler)) {
14712 scope.clickHandler($event, steps);
14714 scope.cstep = steps + 1;
14715 // In the case we decremented previously from this step, we need to reset currentpage to default
14716 if (scope.cstep <= scope.sdata.length && scope.sdata[scope.cstep]['currentPage'] < 1) {
14717 scope.sdata[scope.cstep]['currentPage'] = 1;
14720 updateTrackWidth();
14727 .constant('timelineConstants', {
14730 COMPLETED: 'completed',
14731 CANCELLED: 'cancelled'
14734 .controller('AttTimelineCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
14735 var timelineBarCtrls = [];
14736 var timelineDotCtrls = [];
14738 this.isAlternate = function () {
14739 return $scope.alternate;
14741 this.addTimelineBarCtrls = function (t) {
14742 timelineBarCtrls.push(t);
14744 this.addTimelineDotCtrls = function (b) {
14745 timelineDotCtrls.push(b);
14747 $timeout(init, 200);
14749 function compare(a, b) {
14750 if (a.order < b.order) {
14753 if (a.order > b.order) {
14758 timelineDotCtrls.sort(compare);
14759 timelineBarCtrls.sort(compare);
14760 if ($scope.$parent.animate) {
14763 $scope.$watch('trigger', function (val) {
14765 $scope.resetTimeline();
14767 $scope.$parent.animate = false;
14771 function animateSequence() {
14772 var dotsDuration = .25;
14773 var timelineBarProgressDuration = .25;
14774 if (typeof $scope.barAnimateDuration === 'number') {
14775 timelineBarProgressDuration = $scope.barAnimateDuration;
14777 var start = createAnimation(0, timelineBarProgressDuration);
14778 function setToInactiveStates() {
14779 for (var i in timelineDotCtrls) {
14780 var dotCtrl = timelineDotCtrls[i];
14782 dotCtrl.unhoveredStateForBelow(.25);
14784 dotCtrl.unhoveredStateForAbove(.25);
14786 if (dotCtrl.isStop()) {
14791 function createAnimation(i, duration) {
14793 return function () {
14794 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
14795 timelineBarCtrls[i].isCancelled(true);
14797 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
14799 } else if (i === timelineBarCtrls.length - 1) {
14800 return function () {
14801 //Removes the bolded text from the start
14802 if (timelineDotCtrls[0].isCurrentStep()) {
14803 timelineDotCtrls[0].isCurrentStep(false);
14805 if (timelineDotCtrls[i].isStop()) {
14806 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
14807 timelineDotCtrls[i].isCurrentStep(true);
14809 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
14810 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
14812 timelineDotCtrls[i].expandedAnimate(dotsDuration);
14813 $timeout(function () {
14814 setToInactiveStates();
14819 else if (i === timelineBarCtrls.length) {
14820 return function () {
14821 //Removes the bolded text from the start
14822 if (timelineDotCtrls[0].isCurrentStep()) {
14823 timelineDotCtrls[0].isCurrentStep(false);
14825 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
14826 timelineDotCtrls[i].expandedAnimate(dotsDuration);
14827 timelineDotCtrls[i].isCurrentStep(true);
14828 $timeout(function () {
14829 setToInactiveStates();
14834 return function () {
14835 //Removes the bolded text from the start
14836 if (timelineDotCtrls[0].isCurrentStep()) {
14837 timelineDotCtrls[0].isCurrentStep(false);
14839 if (timelineDotCtrls[i].isStop()) {
14840 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
14841 timelineDotCtrls[i].expandedAnimate(dotsDuration);
14842 timelineDotCtrls[i].isCurrentStep(true);
14843 $timeout(function () {
14844 setToInactiveStates();
14847 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
14848 timelineBarCtrls[i].isCancelled(true);
14850 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
14851 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
14852 timelineDotCtrls[i].expandedAnimate(dotsDuration);
14860 .directive('attTimeline', ['$timeout', '$compile', function ($timeout, $compile) {
14868 barAnimateDuration: '='
14870 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timeline.html',
14871 controller: 'AttTimelineCtrl',
14872 link: function (scope, element, attrs, ctrl) {
14873 var init = function () {
14874 var steps = scope.steps;
14875 var middleSteps = [];
14876 for (var i = 1; i < steps.length; i++) {
14877 var aStep = steps[i];
14878 middleSteps.push(aStep);
14880 scope.middleSteps = middleSteps;
14881 //Used in calculating the width of the loading bars
14882 ctrl.numSteps = steps.length - 1;
14885 //Recompile in case of scope changes
14886 scope.resetTimeline = function () {
14887 scope.animate = true;
14888 $compile(element)(scope);
14893 .controller('TimelineBarCtrl', ['$scope', function ($scope) {
14894 this.type = 'timelinebar';
14895 this.order = parseInt($scope.order);
14896 this.animate = function (callback, duration) {
14897 $scope.loadingAnimation(callback, duration);
14899 this.isCancelled = function (isCancelled) {
14900 $scope.isCancelled = isCancelled;
14903 .directive('timelineBar', ['animation', '$progressBar', function (animation, $progressBar) {
14907 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineBar.html',
14911 require: ['^attTimeline', 'timelineBar'],
14912 controller: 'TimelineBarCtrl',
14913 link: function (scope, element, attrs, ctrls) {
14914 var attTimelineCtrl = ctrls[0];
14915 var timelineBarCtrl = ctrls[1];
14916 attTimelineCtrl.addTimelineBarCtrls(timelineBarCtrl);
14917 scope.isCompleted = true;
14918 var widthPerc = (100 / attTimelineCtrl.numSteps) - 3;
14919 element.css('width', widthPerc + '%');
14920 var elem = element.find('div').eq(0);
14921 animation.set(elem, {opacity: 0.0});
14922 var updateCallback = function (selfElement) {
14923 animation.set(elem, {opacity: 1.0});
14924 animation.set(elem, {
14925 scaleX: selfElement.progress(),
14926 transformOrigin: "left"
14929 scope.loadingAnimation = $progressBar(updateCallback);
14933 .controller('TimelineDotCtrl', ['$scope', '$timeout', 'timelineConstants', function ($scope, $timeout, timelineConstants) {
14935 this.order = parseInt($scope.order);
14937 $timeout(function () {
14938 if (self.order !== 0) {
14939 if (self.order % 2 !== 0) {
14940 $scope.initializeAboveForAnimation();
14943 $scope.initializeBelowForAnimation();
14947 this.expandedAnimate = function (duration) {
14949 $scope.expandedAnimate(duration);
14950 if (self.order !== 0 && !$scope.isStepsLessThanFive()) {
14951 if (self.order % 2 !== 0) {
14952 $scope.expandContentForAbove(duration);
14954 $scope.expandContentForBelow(duration);
14958 this.unhoveredStateForAbove = function (duration) {
14959 $scope.unhoveredStateForAbove(duration);
14961 this.unhoveredStateForBelow = function (duration) {
14962 $scope.unhoveredStateForBelow(duration);
14964 this.shrinkAnimate = function (duration) {
14965 $scope.shrinkAnimate(duration);
14967 this.setExpanded = function () {
14970 this.isStop = function () {
14971 return $scope.isStop;
14973 this.isCancelled = function () {
14974 return ($scope.type === timelineConstants.STEP_TYPE.CANCELLED);
14976 this.isAlert = function () {
14977 return ($scope.type === timelineConstants.STEP_TYPE.ALERT);
14979 //Sets the bolded text
14980 this.isCurrentStep = function (isCurrentStep) {
14981 if (isCurrentStep !== undefined) {
14982 $scope.isCurrentStep = isCurrentStep;
14984 return $scope.isCurrentStep;
14987 .directive('timelineDot', ['animation', 'timelineConstants',
14988 function (animation, timelineConstants) {
15000 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineDot.html',
15001 require: ['^attTimeline', 'timelineDot'],
15002 controller: 'TimelineDotCtrl',
15003 link: function (scope, element, attrs, ctrls) {
15004 var attTimelineCtrl = ctrls[0];
15005 var timelineDotCtrl = ctrls[1];
15006 attTimelineCtrl.addTimelineDotCtrls(timelineDotCtrl);
15007 scope.numSteps = attTimelineCtrl.numSteps + 1;
15008 scope.isCurrentStep = false;
15009 scope.isCompleted = false;
15010 scope.isStop = false;
15011 if (scope.type === timelineConstants.STEP_TYPE.ALERT || scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
15012 scope.isStop = true;
15014 scope.isInactive = true;
15015 var divs = element.find('div');
15016 var biggerCircleElem = divs.eq(0);
15017 var expandableCircleElem = divs.eq(2);
15018 var infoboxElem = divs.eq(3);
15019 var titleElem = divs.eq(5);
15020 var contentElem = divs.eq(6);
15021 var dateElem = divs.eq(9);
15022 function isEmptyStep() {
15023 if (!scope.description && !scope.by && !scope.date) {
15028 scope.isStepsLessThanFive = function () {
15029 if (scope.numSteps < 5) {
15034 scope.titleMouseover = function (num) {
15035 if (!scope.isStepsLessThanFive() && !isEmptyStep()) {
15036 if (num === 1 && scope.order % 2 === 0) {
15037 scope.expandContentForBelow(.25);
15039 if (num === 2 && scope.order % 2 !== 0) {
15040 scope.expandContentForAbove(.25);
15044 scope.titleMouseleave = function () {
15045 if (scope.order % 2 === 0) {
15046 scope.unhoveredStateForBelow(.25);
15049 scope.unhoveredStateForAbove(.25);
15052 scope.initializeAboveForAnimation = function () {
15053 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15054 animation.set(contentElem, {opacity: 0});
15055 animation.set(dateElem, {opacity: 0});
15056 if (!isEmptyStep()) {
15057 var yOffset = contentElem[0].offsetHeight + dateElem[0].offsetHeight;
15058 animation.set(titleElem, {'top': yOffset});
15062 scope.expandContentForAbove = function (duration) {
15063 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15064 animation.to(titleElem, duration, {'top': 0});
15065 animation.to(contentElem, duration, {opacity: 1});
15066 animation.to(dateElem, duration, {opacity: 1});
15069 scope.unhoveredStateForAbove = function (duration) {
15070 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15071 animation.set(contentElem, {opacity: 0});
15072 animation.set(dateElem, {opacity: 1});
15073 var yOffset = contentElem[0].offsetHeight;
15074 animation.to(titleElem, duration, {'top': yOffset});
15077 scope.initializeBelowForAnimation = function () {
15078 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15079 animation.set(contentElem, {height: '0%', opacity: 0, top: '-20px'});
15080 animation.set(dateElem, {opacity: 0});
15083 scope.expandContentForBelow = function (duration) {
15084 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15085 animation.set(dateElem, {opacity: 1});
15086 animation.to(contentElem, duration, {height: 'auto', opacity: 1, top: '0px'});
15089 scope.unhoveredStateForBelow = function (duration) {
15090 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
15091 animation.to(contentElem, duration, {height: '0%', opacity: 0, top: '-20px', position: 'relative'});
15092 animation.set(dateElem, {opacity: 1});
15095 /*Default Initializaztion*/
15096 //If the info box is above and the description and date and by are empty then we have do reset its position
15097 if (isEmptyStep() && (scope.order % 2 !== 0 && attTimelineCtrl.isAlternate())) {
15098 infoboxElem.css('top', '-47px');
15100 //Check if the order is odd and set the appropiate above or below and other effects
15101 if (scope.order % 2 === 0 || !attTimelineCtrl.isAlternate()) {
15102 scope.isBelowInfoBoxShown = true;
15105 scope.isBelowInfoBoxShown = false;
15107 //modify some css for steps less than 5 and not alternating
15108 if (scope.isStepsLessThanFive() && !attTimelineCtrl.isAlternate()) {
15109 animation.set(dateElem, {marginTop: 10});
15112 animation.set(biggerCircleElem, {opacity: '.5'});
15113 //shrink the expandableCircle to we can expand it later
15114 animation.set(expandableCircleElem, {opacity: '0.0'});
15115 animation.set(expandableCircleElem, {scale: .10});
15116 if (scope.order === 0) {
15117 animation.set(expandableCircleElem, {opacity: '1.0'});
15118 animation.set(expandableCircleElem, {scale: 1});
15119 animation.set(biggerCircleElem, {scale: 3});
15120 scope.isCurrentStep = true;
15121 scope.isInactive = false;
15122 scope.isCompleted = true;
15124 scope.setColor = function () {
15125 scope.isInactive = false;
15126 if (scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
15127 scope.isCancelled = true;
15129 else if (scope.type === timelineConstants.STEP_TYPE.ALERT) {
15130 scope.isAlert = true;
15133 scope.isCompleted = true;
15135 if (!scope.$phase) {
15139 scope.setSize = function (size) {
15140 animation.set(biggerCircle, {scale: size});
15142 scope.setExpandedCircle = function () {
15143 animation.set(expandableCircleElem, {opacity: '1.0'});
15144 animation.set(expandableCircleElem, {scale: 1});
15146 scope.expandedAnimate = function (duration) {
15147 animation.to(biggerCircleElem, duration, {scale: 3});
15148 animation.set(expandableCircleElem, {opacity: '1.0'});
15149 animation.to(expandableCircleElem, duration, {scale: 1});
15151 scope.shrinkAnimate = function (duration) {
15152 animation.to(biggerCircleElem, duration, {scale: 1});
15157 angular.module('att.abs.table', ['att.abs.utilities'])
15158 .constant('tableConfig', {
15159 //true for descending & false for ascending
15160 defaultSortPattern: false,
15161 highlightSearchStringClass: 'tablesorter-search-highlight'
15164 .directive('attTable', ['$filter', function($filter) {
15174 searchCategory: "=",
15177 require: 'attTable',
15178 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTable.html',
15179 controller: ['$scope', function($scope) {
15181 this.currentSortIndex = null;
15182 this.setIndex = function(headerScope) {
15183 this.headers.push(headerScope);
15185 this.getIndex = function(headerName) {
15186 for (var i = 0; i < this.headers.length; i++) {
15187 if (this.headers[i].headerName === headerName) {
15188 return this.headers[i].index;
15193 this.sortData = function(columnIndex, reverse) {
15194 $scope.$parent.columnIndex = columnIndex;
15195 $scope.$parent.reverse = reverse;
15196 this.currentSortIndex = columnIndex;
15197 $scope.currentPage = 1;
15198 this.resetSortPattern();
15200 this.getSearchString = function() {
15201 return $scope.searchString;
15203 this.resetSortPattern = function() {
15204 for(var i = 0; i < this.headers.length; i++) {
15205 var currentScope = this.headers[i];
15206 if(currentScope.index !== this.currentSortIndex) {
15207 currentScope.resetSortPattern();
15212 link: function(scope, elem, attr, ctrl) {
15213 scope.searchCriteria = {};
15214 scope.$watchCollection('tableData', function(value) {
15215 if(value && !isNaN(value.length)) {
15216 scope.totalRows = value.length;
15219 scope.$watch('currentPage', function(val) {
15220 scope.$parent.currentPage = val;
15222 scope.$watch('viewPerPage', function(val) {
15223 scope.$parent.viewPerPage = val;
15225 scope.$watch(function() {
15226 return scope.totalRows / scope.viewPerPage;
15227 }, function(value) {
15228 if(!isNaN(value)) {
15229 scope.totalPage = Math.ceil(value);
15230 scope.currentPage = 1;
15233 var searchValCheck = function(val){
15234 if(angular.isDefined(val) && val !== null && val !== ""){
15238 var setSearchCriteria = function(v1,v2){
15239 if(searchValCheck(v1) && searchValCheck(v2)){
15240 var index = ctrl.getIndex(v2);
15241 scope.searchCriteria = {};
15242 if (index !== null) {
15243 scope.searchCriteria[index] = v1;
15245 }else if(searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")){
15246 scope.searchCriteria = {
15250 scope.searchCriteria = {};
15253 scope.$watch('searchCategory', function(newVal,oldVal) {
15254 if(newVal !== oldVal){
15255 setSearchCriteria(scope.searchString,newVal);
15258 scope.$watch('searchString', function (newVal,oldVal) {
15259 if(newVal !== oldVal){
15260 setSearchCriteria(newVal,scope.searchCategory);
15263 scope.$watchCollection('searchCriteria', function(val) {
15264 scope.$parent.searchCriteria = val;
15265 scope.totalRows = ($filter('filter')(scope.tableData, val, false)).length;
15266 scope.currentPage = 1;
15272 .directive('attTableRow', [function() {
15275 compile: function (elem, attr) {
15276 if (attr.type === 'header') {
15277 elem.find('tr').eq(0).addClass('tablesorter-headerRow');
15278 } else if (attr.type === 'body') {
15279 var html = elem.children();
15280 if(attr.rowRepeat){
15281 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1)"));
15283 html.attr('ng-class', "{'alt-row': $even,'normal-row': $odd}");
15290 .directive('attTableHeader', ['tableConfig', function(tableConfig) {
15299 arrowDirection: '=',
15302 require: '^attTable',
15303 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableHeader.html',
15304 link: function(scope, elem, attr, ctrl) {
15305 var reverse = tableConfig.defaultSortPattern;
15306 scope.headerName = elem.text();
15307 scope.sortPattern = null;
15308 ctrl.setIndex(scope);
15310 scope.$watch('arrowDirection', function(val){
15312 scope.sortPattern = 'asc';}
15314 scope.sortPattern = 'desc';}
15317 scope.$watch(function() {
15318 return elem.text();
15319 }, function(value) {
15320 scope.headerName = value;
15322 scope.sort = function(sortType) {
15323 if(typeof sortType === 'boolean') {
15324 reverse = sortType;
15326 ctrl.sortData(scope.index, reverse);
15327 scope.sortPattern = reverse ? 'desc' : 'asc';
15328 reverse = !reverse;
15330 scope.$watch(function() {
15331 return ctrl.currentSortIndex;
15332 }, function(value) {
15333 if (value !== scope.index) {
15334 scope.sortPattern = null;
15337 if(scope.sortable !== 'false') {
15338 if(scope.defaultSort === 'A' || scope.defaultSort === 'a') {
15340 } else if(scope.defaultSort === 'D' || scope.defaultSort === 'd') {
15344 scope.resetSortPattern = function() {
15345 reverse = tableConfig.defaultSortPattern;
15351 .directive('attTableBody', ['$filter', '$timeout', 'tableConfig', function($filter, $timeout, tableConfig) {
15354 require: '^attTable',
15357 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableBody.html',
15358 link: function (scope, elem, attr, ctrl) {
15359 var highlightSearchStringClass = tableConfig.highlightSearchStringClass;
15360 var searchString = "";
15361 var wrapElement = function (elem) {
15362 var text = elem.text();
15364 elem.append($filter('highlight')(text, searchString, highlightSearchStringClass));
15366 var traverse = function (elem) {
15367 var innerHtml = elem.children();
15368 if (innerHtml.length > 0) {
15369 for (var i = 0; i < innerHtml.length; i++) {
15370 traverse(innerHtml.eq(i));
15377 var clearWrap = function (elem) {
15378 var elems = elem.find('*');
15379 for (var i = 0; i < elems.length; i++) {
15380 if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
15381 var text = elems.eq(i).text();
15382 elems.eq(i).replaceWith(text);
15386 $timeout(function () {
15387 var actualHtml = elem.children();
15388 scope.$watch(function () {
15389 return ctrl.getSearchString();
15390 }, function (val) {
15391 searchString = val;
15393 if (actualHtml.length > 0) {
15404 angular.module('att.abs.tabs', [])
15405 .directive('attTabs', function () {
15413 controller: ['$scope', function ($scope) {
15414 this.getData = function () {
15415 return $scope.tabs;
15417 this.onClickTab = function (tab) {
15418 $scope.currentTab = tab.url;
15419 return $scope.currentTab;
15421 this.isActiveTab = function (tab) {
15422 return (tab === $scope.currentTab);
15425 link: function (scope) {
15426 for (var i = 0; i < scope.tabs.length; i++) {
15427 if ((scope.tabs[i].selected) && (scope.tabs[i].url)) {
15428 scope.currentTab = scope.tabs[i].url;
15434 .directive('floatingTabs', function () {
15436 require: '^attTabs',
15443 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/floatingTabs.html',
15444 link: function (scope, elem, attr, attTabsCtrl) {
15445 scope.tabs = attTabsCtrl.getData();
15446 scope.onClickTab = attTabsCtrl.onClickTab;
15447 scope.isActiveTab = attTabsCtrl.isActiveTab;
15451 .directive('simplifiedTabs', function () {
15453 require: '^attTabs',
15460 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html',
15461 link: function (scope, elem, attr, attTabsCtrl) {
15462 scope.tabs = attTabsCtrl.getData();
15463 scope.clickTab = function (tab) {
15464 scope.ctab = tab.id;
15467 scope.isActive = function (tab) {
15468 return (tab === scope.ctab);
15473 .directive('genericTabs', function () {
15475 require: '^attTabs',
15482 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/genericTabs.html',
15483 link: function (scope, elem, attr, attTabsCtrl) {
15484 scope.tabs = attTabsCtrl.getData();
15485 scope.clickTab = function (tab) {
15486 scope.ctab = tab.id;
15489 scope.isActive = function (tab) {
15490 return (tab === scope.ctab);
15495 .directive('parentTab', [function () {
15500 activeSubMenu: '=',
15503 controller: ['$scope', function ($scope) {
15504 $scope.megaMenu = $scope.menuItems;
15505 $scope.megaMenuTab;
15506 $scope.megaMenuHoverTab;
15507 this.setMenu = function () {
15508 $scope.menuItems = $scope.megaMenu;
15509 for (var i = 0; i < $scope.menuItems.length; i++) {
15510 if ($scope.menuItems[i].active) {
15511 $scope.activeMenu = $scope.menuItems[i];
15514 this.setSubMenuStatus(false);
15517 this.setActiveMenu = function () {
15518 if (!($scope.megaMenuTab === "undefined" || $scope.megaMenuTab === null)) {
15519 $scope.menuItems = [$scope.megaMenuTab];
15520 $scope.activeMenu = {};
15521 $scope.activeSubMenu = $scope.megaMenuTab;
15522 this.setSubMenuStatus(true);
15529 this.setMenuItems = function(){
15530 for (var i = 0; i < $scope.menuItems.length; i++) {
15531 $scope.menuItems[i].active = false;
15532 if ($scope.menuItems[i].subItems){
15533 for (var j = 0; j < $scope.menuItems[i].subItems.length; j++) {
15534 $scope.menuItems[i].subItems[j].active = false;
15538 $scope.menuItems = $scope.megaMenu;
15540 var checkSubMenuStatus = false;
15541 this.setSubMenuStatus = function (value) {
15542 checkSubMenuStatus = value;
15544 this.getSubMenuStatus = function () {
15545 return checkSubMenuStatus;
15547 this.setActiveMenuTab = function (tab) {
15548 $scope.megaMenuTab = tab;
15550 this.setActiveMenuHoverTab = function (tab) {
15551 $scope.megaMenuHoverTab = tab;
15553 this.setActiveSubMenuTab = function () {
15554 $scope.megaMenuTab = $scope.megaMenuHoverTab;
15556 this.resetMenuTab = function () {
15557 $scope.megaMenuTab = 'undefined';
15562 .directive('parentmenuTabs', [function () {
15571 controller: ['$scope', function ($scope) {
15572 this.getMenu = function () {
15573 return $scope.menuItems;
15575 this.setMenu = function (menuItem) {
15576 $scope.menuItems = menuItem;
15579 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html'
15582 .directive('menuTabs', ["$window", "$document", function (win, $document) {
15587 require: ['^parentTab', '^?parentmenuTabs'],
15594 templateUrl: function (element, attrs) {
15595 if (attrs.megaMenu) {
15596 return 'app/scripts/ng_js_att_tpls/tabs/menuTab.html';
15599 return 'app/scripts/ng_js_att_tpls/tabs/submenuTab.html';
15602 link: function (scope, elem, attr, ctrl) {
15603 var parentCtrl = ctrl[0];
15604 var parentmenuCtrl = ctrl[1];
15605 scope.clickInactive = true;
15606 scope.showHoverChild = function (e) {
15607 scope.clickInactive = false;
15608 scope.hoverChild = ctrl[0].getSubMenuStatus();
15609 if (e.type === "mouseover" && ctrl[0].getSubMenuStatus())
15611 scope.showChildren(e);
15614 scope.showChildren = function (e) {
15615 scope.parentMenuItems = parentmenuCtrl.getMenu();
15616 for (var i = 0; i < scope.parentMenuItems.length; i++) {
15617 scope.parentMenuItems[i].active = false;
15618 if (scope.parentMenuItems[i].subItems) {
15619 for (var j = 0; j < scope.parentMenuItems[i].subItems.length; j++) {
15620 scope.parentMenuItems[i].subItems[j].active = false;
15623 scope.clickInactive = true;
15625 scope.menuItem.active = true;
15626 scope.activeMenu = scope.menuItem;
15627 e.stopPropagation();
15629 scope.$watch("subItemActive", function (value) {
15630 if (value === "true" && scope.subMenu === 'true') {
15631 parentCtrl.setActiveMenuHoverTab(scope.menuItem);
15634 scope.showMenuClick = function () {
15635 parentCtrl.setActiveMenuTab(scope.menuItem);
15637 scope.showSubMenuClick = function () {
15638 parentCtrl.setActiveSubMenuTab();
15640 scope.resetMenu = function () {
15641 parentCtrl.resetMenuTab();
15643 function debounce(method, delay) {
15644 clearTimeout(method._tId);
15645 method._tId = setTimeout(function () {
15646 parentCtrl.setMenu();
15649 function debounce1(method, delay) {
15650 clearTimeout(method._tId);
15651 method._tId = setTimeout(function () {
15652 parentCtrl.setActiveMenu();
15655 $document.bind('scroll', function () {
15656 if (win.pageYOffset === 0) {
15657 debounce(parentCtrl.setMenu, 100);
15659 else if (win.pageYOffset > 1 && win.pageYOffset < 1500) {
15660 debounce1(parentCtrl.setActiveMenu, 100);
15666 angular.module('att.abs.tagBadges', [])
15667 .directive('tagBadges', ['$parse', '$timeout', function($parse, $timeout) {
15672 templateUrl: 'app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html',
15677 link: function(scope, elem, attr) {
15678 scope.isSmall = false;
15679 scope.isIcon = false;
15680 scope.isColor = false;
15681 scope.display = true;
15682 scope.isClosable = false;
15683 scope.isHighlight = false;
15684 scope.customColor = false;
15686 if (attr.small === "") {
15687 scope.isSmall = true;
15689 if (scope.styleType === "icon") {
15690 scope.isIcon = true;
15692 else if (scope.styleType === "color") {
15693 scope.isColor = true;
15694 if(attr.color !== undefined && attr.color !== "") {
15695 scope.customColor = true;
15696 attr.$observe("color", function(val) {
15697 scope.border_type_borderColor = val;
15698 scope.background_type_backgroundColor = val;
15699 scope.background_type_borderColor = val;
15703 scope.activeHighlight = function(state){
15704 if(scope.customColor){
15706 scope.isHighlight = true;
15709 scope.isHighlight = false;
15713 if (attr.closable === "") {
15714 scope.isClosable = true;
15715 scope.closeMe = function() {
15716 scope.display = false;
15717 $timeout(function(){
15718 elem.attr("tabindex", "0");
15720 elem.bind('blur', function(){
15724 if(attr['onClose']){
15725 scope.onClose = $parse(scope.onClose);
15733 angular.module('att.abs.textOverflow', [])
15734 .constant('textDefaultOptions', {
15737 .directive('attTextOverflow', ['textDefaultOptions','$compile',function(textDefaultOptions,$compile)
15741 link: function(scope, elem, attrs)
15743 var tooltipText = elem.text();
15744 elem.addClass('text-ellipsis');
15745 attrs.$observe('attTextOverflow', function(val){
15747 elem.css({"width":val});
15750 elem.css({"width":textDefaultOptions.width});
15753 if(!(elem.attr('tooltip'))){
15754 elem.attr("tooltip", tooltipText);
15755 elem.attr("tooltip-placement", 'above');
15756 var newElem = angular.element(elem);
15757 $compile(newElem)(scope);
15763 angular.module('att.abs.toggle', ['angular-gestures', 'att.abs.position'])
15764 .directive('attToggleTemplate', ['$compile', '$log', '$position', function($compile, $log, $position)
15768 require: 'ngModel',
15771 modelVal: "=ngModel"
15773 templateUrl: 'app/scripts/ng_js_att_tpls/toggle/demoToggle.html',
15774 link: function(scope, element, attr) {
15775 scope.initialDragPosition = 0;
15776 var dragStatus = 0;
15777 var switchMovementPath = ($position.offset(element.children().eq(1).children().eq(0)).width -1);
15778 var updateModelVal = function() {
15779 if (scope.attrValue === attr.ngTrueValue || scope.attrValue)
15781 scope.modelVal = false;
15785 scope.modelVal = true;
15788 scope.updateModel = function(env){
15790 if (dragStatus !== 1) {
15795 env.preventDefault();
15797 scope.drag = function(e) {
15799 if (e.type === 'dragstart') {
15800 scope.initialDragPosition = $position.position(element.children().eq(1)).left;
15802 element.children().eq(1).addClass('dragging');
15803 } else if (e.type === 'drag') {
15804 var left = Math.min(0, Math.max(scope.initialDragPosition + e.gesture.deltaX, -switchMovementPath));
15805 element.children().eq(1).css({
15808 } else if (e.type === 'dragend') {
15809 var isOn = $position.position(element.children().eq(1)).left > (switchMovementPath*-1)/2;
15810 element.children().eq(1).removeClass('dragging');
15811 TweenMax.to(element.children().eq(1), .1, {left: isOn ? 0 : (switchMovementPath*-1), ease: Power4.easeOut,
15812 onComplete: function(){element.children().eq(1).css({left: ''});
15814 if(isOn || (!isOn && e.gesture.direction === "left")){
15823 scope.directiveValue = attr.attToggleTemplate;
15824 scope.on = attr.trueValue;
15825 scope.off = attr.falseValue;
15826 var switchMovementPathPixels = ((switchMovementPath)*-1) + 'px';
15827 scope.$watch('modelVal', function(newVal) {
15828 scope.attrValue = newVal;
15829 if (newVal === attr.ngTrueValue || newVal) {
15830 element.children().eq(1).css({
15833 element.addClass('att-checkbox--on');
15834 element.attr("aria-checked", true);
15837 element.children().eq(1).css({
15838 left : switchMovementPathPixels
15840 element.removeClass('att-checkbox--on');
15841 element.attr("aria-checked", false);
15844 element.children().eq(1).css({
15853 .directive('attToggleMain', ['$compile', function($compile)
15857 require: 'ngModel',
15861 modelValue: "=ngModel",
15862 trueValue: "=ngTrueValue",
15863 falseValue: "=ngFalseValue"
15865 link: function(scope, element, attr) {
15868 element.removeAttr('att-toggle-main');
15869 scope.on = attr.ngTrueValue;
15870 scope.off = attr.ngFalseValue;
15871 scope.largeValue = attr.attToggleMain;
15872 if (angular.isDefined(attr.ngTrueValue)) {
15873 html += ' true-value="{{on}}" false-value="{{off}}"';
15875 if (scope.largeValue !== undefined)
15877 attrVal += ' ="{{largeValue}}"';
15880 element.css({display:'none'});
15881 var elm = angular.element('<div role="checkbox" class="att-switch att-switch-alt" ng-class="{\'large\' : largeValue == \'large\'}" ng-model="modelValue"' + html + ' att-toggle-template' + attrVal + '>' + element.prop('outerHTML') + '</div>');
15882 elm = $compile(elm)(scope);
15883 element.replaceWith(elm);
15888 angular.module('att.abs.tooltip', ['att.abs.position', 'att.abs.utilities', 'ngSanitize'])
15889 // The default options tooltip and popover.
15890 .constant('tooltipDefaultOptions', {
15891 placement: 'above',
15899 * The $tooltip service creates tooltip- and popover-like directives as well as
15900 * houses global options for them.
15902 .provider('$tooltip', ['tooltipDefaultOptions', function(tooltipDefaultOptions) {
15904 // Default hide triggers for each show trigger
15906 'mouseenter': 'mouseleave',
15909 'mouseover':'mouseout'
15912 // The options specified to the provider globally.
15913 var globalOptions = {};
15915 this.options = function(value) {
15916 angular.extend(globalOptions, value);
15920 * This allows you to extend the set of trigger mappings available. E.g.:
15922 * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
15924 this.setTriggers = function(triggers) {
15925 angular.extend(triggerMap, triggers);
15929 * This is a helper function for translating camel-case to snake-case.
15931 function snakeCase(name) {
15932 var regexp = /[A-Z]/g;
15933 var separator = '-';
15934 return name.replace(regexp, function(letter, pos) {
15935 return (pos ? separator : '') + letter.toLowerCase();
15940 * Returns the actual instance of the $tooltip service.
15942 this.$get = ['$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function($window, $compile, $timeout, $parse, $document, $position, $interpolate) {
15943 return function (type, prefix, defaultTriggerShow) {
15944 var options = angular.extend({}, tooltipDefaultOptions, globalOptions);
15946 * Returns an object of show and hide triggers.
15948 * If a trigger is supplied,
15949 * it is used to show the tooltip; otherwise, it will use the `trigger`
15950 * option passed to the `$tooltipProvider.options` method; else it will
15951 * default to the trigger supplied to this directive factory.
15953 * The hide trigger is based on the show trigger. If the `trigger` option
15954 * was passed to the `$tooltipProvider.options` method, it will use the
15955 * mapped trigger from `triggerMap` or the passed trigger if the map is
15956 * undefined; otherwise, it uses the `triggerMap` value of the show
15957 * trigger; else it will just use the show trigger.
15959 function getTriggers(trigger) {
15960 var show = trigger || options.trigger || defaultTriggerShow;
15961 var hide = triggerMap[show] || show;
15968 var directiveName = snakeCase(type);
15970 var startSym = $interpolate.startSymbol();
15971 var endSym = $interpolate.endSymbol();
15973 '<div ' + directiveName + '-popup ' +
15974 'title="' + startSym + 'tt_title' + endSym + '" ' +
15975 'content="' + startSym + 'tt_content' + endSym + '" ' +
15976 'placement="' + startSym + 'tt_placement' + endSym + '" ' +
15977 'animation="tt_animation()" ' +
15978 'is-open="tt_isOpen" ' +
15979 'stylett="' + startSym + 'tt_style' + endSym + '" ' +
15985 link: function (scope, element, attrs) {
15986 element.attr("tabindex", "0");
15987 element.bind('mouseenter', function(){
15988 element.removeAttr("title");
15990 element.bind('mouseleave', function(){
15991 element.attr("title", scope.tt_content);
15993 var tooltip = $compile(template)(scope);
15994 var transitionTimeout;
15997 var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
15998 var triggers = getTriggers(undefined);
15999 var hasRegisteredTriggers = false;
16000 var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
16002 // By default, the tooltip is not open.
16003 // add ability to start tooltip opened
16004 scope.tt_isOpen = false;
16006 //Adding a scope watch, to remove the created popup from DOM, incase it is updated outside the provider code.
16007 scope.$watch('tt_isOpen', function(newVal, oldVal){
16008 if(newVal !== oldVal && !newVal){
16013 function toggleTooltipBind() {
16014 if (!scope.tt_isOpen) {
16021 // Show the tooltip with delay if specified, otherwise show it immediately
16022 function showTooltipBind() {
16023 tooltip = $compile(template)(scope);
16025 if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
16028 if (scope.tt_popupDelay) {
16029 popupTimeout = $timeout(show, scope.tt_popupDelay);
16031 scope.$apply(show);
16035 function hideTooltipBind() {
16036 scope.$apply(function() {
16041 // Show the tooltip popup element.
16048 // Don't show empty tooltips.
16049 if (!scope.tt_content) {
16053 // If there is a pending remove transition, we must cancel it, lest the
16054 // tooltip be mysteriously removed.
16055 if (transitionTimeout) {
16056 $timeout.cancel(transitionTimeout);
16059 // Set the initial positioning.
16060 tooltip.css({top: 0, left: 0, display: 'block', 'z-index': 9999});
16062 // Now we add it to the DOM because need some info about it. But it's not
16063 // visible yet anyway.
16064 if (appendToBody) {
16065 $body = $body || $document.find('body');
16066 $body.append(tooltip);
16068 element.after(tooltip);
16071 // Get the position of the directive element.
16072 position = appendToBody ? $position.offset(element) : $position.position(element);
16074 // Get the height and width of the tooltip so we can center it.
16075 ttWidth = tooltip.prop('offsetWidth');
16076 ttHeight = tooltip.prop('offsetHeight');
16078 // Calculate the tooltip's top and left coordinates to center it with
16080 var ttArrowOffset = 10;
16081 switch (scope.tt_placement) {
16085 top: position.top + position.height / 2 - ttHeight / 2,
16086 left: position.left + position.width
16090 top: position.top + position.height / 2 - ttHeight / 2,
16091 left: position.left + position.width + ttArrowOffset
16098 top: position.top + position.height,
16099 left: position.left + position.width / 2 - ttWidth / 2
16103 top: position.top + position.height + ttArrowOffset,
16104 left: position.left + position.width / 2 - ttWidth / 2
16111 top: position.top + position.height / 2 - ttHeight / 2,
16112 left: position.left - ttWidth
16116 top: position.top + position.height / 2 - ttHeight / 2,
16117 left: position.left - ttWidth - ttArrowOffset
16124 top: position.top - ttHeight,
16125 left: position.left + position.width / 2 - ttWidth / 2
16129 top: position.top - ttHeight - ttArrowOffset,
16130 left: position.left + position.width / 2 - ttWidth / 2
16136 ttPosition.top += 'px';
16137 ttPosition.left += 'px';
16139 // Now set the calculated positioning.
16140 tooltip.css(ttPosition);
16142 // And show the tooltip.
16143 scope.tt_isOpen = true;
16146 // Hide the tooltip popup element.
16148 // First things first: we don't show it anymore.
16149 scope.tt_isOpen = false;
16151 //if tooltip is going to be shown after delay, we must cancel this
16152 $timeout.cancel(popupTimeout);
16154 // And now we remove it from the DOM. However, if we have animation, we
16155 // need to wait for it to expire beforehand.
16156 // This is a placeholder for a port of the transitions library.
16157 if (angular.isDefined(scope.tt_animation) && scope.tt_animation()) {
16158 transitionTimeout = $timeout(function() {
16167 * Observe the relevant attributes.
16169 attrs.$observe(type, function(val) {
16171 scope.tt_content = val;
16172 element.attr('title',val);
16174 if (scope.tt_isOpen) {
16180 attrs.$observe(prefix + 'Title', function(val) {
16181 scope.tt_title = val;
16184 attrs.$observe(prefix + 'Placement', function(val) {
16185 scope.tt_placement = angular.isDefined(val) ? val : options.placement;
16188 attrs.$observe(prefix + 'Style', function(val) {
16189 scope.tt_style = angular.isDefined(val) ? val : options.stylett;
16192 attrs.$observe(prefix + 'Animation', function(val) {
16193 scope.tt_animation = angular.isDefined(val) ? $parse(val) : function() {
16194 return options.animation;
16198 attrs.$observe(prefix + 'PopupDelay', function(val) {
16199 var delay = parseInt(val, 10);
16200 scope.tt_popupDelay = !isNaN(delay) ? delay : options.popupDelay;
16203 attrs.$observe(prefix + 'Trigger', function(val) {
16205 if (hasRegisteredTriggers) {
16206 element.unbind(triggers.show, showTooltipBind);
16207 element.unbind(triggers.hide, hideTooltipBind);
16210 triggers = getTriggers(val);
16212 if (triggers.show === triggers.hide) {
16213 element.bind(triggers.show, toggleTooltipBind);
16215 element.bind(triggers.show, showTooltipBind);
16216 element.bind(triggers.hide, hideTooltipBind);
16219 hasRegisteredTriggers = true;
16222 attrs.$observe(prefix + 'AppendToBody', function(val) {
16223 appendToBody = angular.isDefined(val) ? $parse(val)(scope) : appendToBody;
16226 // if a tooltip is attached to <body> we need to remove it on
16227 // location change as its parent scope will probably not be destroyed
16229 if (appendToBody) {
16230 scope.$on('$locationChangeSuccess', function() {
16231 if (scope.tt_isOpen) {
16237 // Make sure tooltip is destroyed and removed.
16238 scope.$on('$destroy', function() {
16239 if (scope.tt_isOpen) {
16251 .directive('tooltipPopup', ['$document', '$documentBind', function($document, $documentBind) {
16256 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
16257 templateUrl: 'app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html',
16258 link: function(scope, elem) {
16260 scope.$watch("isOpen", function() {
16261 flag = scope.isOpen;
16263 elem.bind('click', function (e) {
16264 e.stopPropagation();
16266 var outsideClick = function() {
16268 scope.$apply(function() {
16269 scope.isOpen = false;
16275 $documentBind.click('isOpen', outsideClick, scope);
16280 .directive('tooltip', ['$tooltip', function($tooltip) {
16281 return $tooltip('tooltip', 'tooltip', 'mouseenter');
16284 .directive('tooltipCondition', [ '$timeout',function($timeout) {
16289 tooltipCondition:"@?"
16291 template:'<p><span tooltip=\"{{tooltipCondition}}\" ng-if=\"showpop\">{{tooltipCondition}}</span><span id=\"innerElement\" ng-hide=\"showpop\">{{tooltipCondition}}</span></p>',
16292 link: function(scope, elem, attr){
16293 scope.showpop=false;
16294 if(attr.height==='true'){
16295 $timeout(function () {
16296 var maxHeight=(elem[0].offsetHeight);
16297 var elemHeight=elem.children(0)[0].offsetHeight;
16298 if(elemHeight > maxHeight){
16299 scope.showpop=true;
16303 else if(scope.tooltipCondition.length>=25){
16304 scope.showpop=true;
16309 angular.module('att.abs.treeview', [])
16310 .directive('treeView', function() {
16313 link: function(scope, elem) {
16314 var el = elem.children('ul li');
16315 var list = TweenMax.from(el, .2, {display: 'none', paused: true, reversed: true});
16316 elem.attr("tabindex","0");
16317 function toggleBranch() {
16318 if (list.reversed())
16326 function toggleTree(e) {
16327 e.stopPropagation();
16328 if ($(e.target).attr("tree-view") !== undefined)
16330 if (elem.hasClass('minus'))
16332 elem.removeClass('minus');
16336 elem.addClass('minus');
16341 elem.on('click', function(e) {
16344 elem.on('keypress', function (e) {
16345 var activeCode = e.keyCode ? e.keyCode : e.charCode;
16346 var keyCode = [13,32];
16347 if (keyCode.length > 0 && ((activeCode && keyCode.indexOf(activeCode) > -1))) {
16349 e.preventDefault();
16356 angular.module('att.abs.typeAhead', ['att.abs.tagBadges'])
16358 .directive('focusMe',['$timeout', '$parse', function($timeout, $parse) {
16360 link: function(scope, element, attrs) {
16361 var model = $parse(attrs.focusMe);
16362 scope.$watch(model, function(value) {
16364 $timeout(function() {
16365 element[0].focus();
16366 scope.inputActive=true;
16370 element.bind('blur', function() {
16371 scope.$apply(model.assign(scope, false));
16372 scope.inputActive=false;
16378 .directive('typeAhead', ['$timeout', function($timeout) {
16381 templateUrl: 'app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html',
16391 link: function(scope, elem) {
16392 scope.lineItems = [];
16393 scope.filteredListLength = -1;
16394 scope.filteredList = [];
16395 scope.inputfocus = false;
16397 scope.setFocus = function() {
16398 scope.clickFocus = true;
16400 scope.handleSelection = function(selectedItem,emailItem) {
16401 scope.lineItems.push(selectedItem);
16402 scope.emailIdList.push(emailItem);
16405 scope.selected = true;
16406 scope.clickFocus = true;
16408 scope.theMethodToBeCalled = function(index) {
16409 var tempArr = scope.lineItems.slice();
16410 scope.emailIdList.splice(index, 1);
16411 tempArr.splice(index, 1);
16412 $timeout(function() {
16413 scope.lineItems = [];
16415 scope.lineItems = scope.lineItems.concat(tempArr);
16420 scope.selected = true;
16422 scope.isCurrent = function(index, itemName,itemEmail,dropdownLength) {
16423 if (scope.current === index) {
16424 scope.itemName = itemName;
16425 scope.itemEmail = itemEmail;
16427 scope.dropdownLength=dropdownLength;
16428 return scope.current === index;
16431 scope.setCurrent = function(index) {
16432 scope.current = index;
16435 scope.selectionIndex = function(evt) {
16436 if (evt.keyCode === 38 && scope.current > 0) {
16437 evt.preventDefault();
16438 scope.current = scope.current - 1;
16439 scope.isCurrent(scope.current);
16440 } else if (evt.keyCode === 9) {
16441 scope.selected = true;
16442 } else if (evt.keyCode === 13 && scope.dropdownLength!==scope.items.length) {
16443 scope.handleSelection(scope.itemName,scope.itemEmail);
16444 } else if ((evt.keyCode === 8 && scope.model.length === 0) || evt.keyCode === 46) {
16445 scope.theMethodToBeCalled(scope.lineItems.length - 1);
16446 } else if (evt.keyCode === 40 && scope.current < scope.dropdownLength-1) {
16447 evt.preventDefault();
16448 scope.current = scope.current + 1;
16449 scope.isCurrent(scope.current);
16451 elem[0].querySelector('.list-scrollable').scrollTop = (scope.current - 1) * 35;
16456 angular.module('att.abs.userMessages', [])
16457 .constant('messageConstants', {
16458 TABLE_MESSAGE_TYPES: {
16463 USER_MESSAGE_TYPES: {
16468 .directive('attTableMessage', ['messageConstants', function(messageConstants) {
16475 onRefreshClick: '&'
16477 templateUrl: 'app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html',
16478 link: function(scope) {
16479 scope.messageConstants = messageConstants;
16480 scope.refreshAction = function(evt) {
16481 scope.onRefreshClick(evt);
16485 }]).directive('attUserMessage', ['messageConstants', function(messageConstants) {
16496 templateUrl: 'app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html',
16497 link: function(scope) {
16498 scope.messageConstants = messageConstants;
16502 angular.module('att.abs.verticalSteptracker', ['ngSanitize'])
16503 .directive('verticalSteptracker', [ function(){
16509 template: '<div class="vertical-nav"><ul ng-transclude class="tickets-list-height"></ul></div>',
16510 link: function () {}
16513 .directive('verticalSteptrackerStep',[ function(){
16522 templateUrl: 'app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html',
16526 .directive('attAbsLink',[ function(){
16531 template: '<span ng-transclude class="view-log"></span>'
16534 angular.module('att.abs.videoControls', [])
16535 .config(['$compileProvider' , function ($compileProvider) {
16536 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|javascript):/);
16538 .directive('videoControls', [function() {
16543 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/videoControls.html'
16546 .directive('photoControls', [function() {
16551 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/photoControls.html',
16556 link: function(scope, elem, attr) {
16557 if(!attr['prevLink']){
16558 scope.prevLink = 'javascript:void(0)';
16560 if(!attr['nextLink']){
16561 scope.nextLink = 'javascript:void(0)';
16564 prevLink : scope.prevLink,
16565 nextLink : scope.nextLink
16570 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
16571 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion.html",
16572 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
16573 " <a ng-show=\"showico\" id=\"tab{{index}}\" class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\" aria-selected=\"{{focused}}\" aria-controls=\"panel{{index}}\" ng-class=\"{focus: focused, selected: focused}\" aria-expanded=\"{{isOpen}}\" role=\"tab\" ng-click=\"toggle()\" accordion-transclude=\"heading\" style=\"cursor:pointer; text-decoration:none\">\n" +
16574 " <span>{{heading}}</span>\n" +
16575 " <i ng-class=\"{'icon-chevron-down':!isOpen,'icon-chevron-up':isOpen }\" class=\"pull-right\"></i>\n" +
16577 " <div ng-show=\"!showico\" ng-class=\"{focus: focused, selected: focused}\" id=\"tab{{index}}\" style=\"text-decoration:none\" accordion-transclude=\"heading\" aria-expanded=\"{{isOpen}}\" role=\"tab\" aria-selected=\"{{focused}}\" aria-controls=\"panel{{index}}\" class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\"><span>{{heading}}</span></div> \n" +
16578 " <div id=\"panel{{index}}\" aria-labelledby=\"tab{{index}}\" aria-hidden=\"{{!isOpen}}\" role=\"tabpanel\" collapse=\"!isOpen\" class=\"att-accordion__body\" ng-transclude>\n" +
16580 " <div class=\"att-accordion__bottom--border\"></div> \n" +
16584 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html", []).run(["$templateCache", function($templateCache) {
16585 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html",
16586 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
16587 " <a id=\"tab{{index}}\" class=\"toggle-header att-accordion__heading att-accordion__toggle\" aria-selected=\"{{focused}}\" aria-controls=\"panel{{index}}\" ng-class=\"{focus: focused, selected: focused}\" aria-expanded=\"{{isOpen}}\" role=\"tab\" ng-click=\"toggle()\" accordion-transclude=\"heading\"> \n" +
16589 " <span>{{heading}}</span>\n" +
16590 " <div id<span>{{heading}}</span>=\"panel{{index}}\" aria-labelledby=\"tab{{index}}\" aria-hidden=\"{{!isOpen}}\" role=\"tabpanel\" collapse=\"!isOpen\" class=\"att-accordion__body\" ng-transclude>\n" +
16595 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccord.html", []).run(["$templateCache", function($templateCache) {
16596 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccord.html",
16597 "<div ng-transclude></div>");
16600 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html", []).run(["$templateCache", function($templateCache) {
16601 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html",
16602 "<div ng-transclude></div>");
16605 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html", []).run(["$templateCache", function($templateCache) {
16606 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html",
16607 "<div ng-click=\"clickFunc()\">\n" +
16608 " <div ng-transclude>\n" +
16609 " <i class=\"icon-chevron-down\"></i>\n" +
16614 angular.module("app/scripts/ng_js_att_tpls/alert/alert.html", []).run(["$templateCache", function($templateCache) {
16615 $templateCache.put("app/scripts/ng_js_att_tpls/alert/alert.html",
16616 "<div class=\"alert\" ng-class=\"{'alert-success': alertType === 'success', 'alert-warning': alertType === 'warning', 'alert-error': alertType === 'error', 'alert-info': alertType === 'info', 'alert-inplace': showTop !== 'true'}\" ng-show=\"showAlert\" ng-style=\"cssStyle\">\n" +
16617 " <div class=\"container\">\n" +
16618 " <a href=\"javascript:void(0)\" alt=\"close\" class=\"close-role\" ng-click=\"close()\" tabindex=\"0\" att-accessibility-click=\"32,13\">Dismiss <i class=\"icon-circle-action-close\"></i></a>\n" +
16619 " <span ng-transclude> </span>\n" +
16624 angular.module("app/scripts/ng_js_att_tpls/colorselector/colorselector.html", []).run(["$templateCache", function($templateCache) {
16625 $templateCache.put("app/scripts/ng_js_att_tpls/colorselector/colorselector.html",
16626 "<div class=\"att-radio att-color-selector__item\" \n" +
16627 " ng-class=\"{'att-radio--on': (iconColor === selected)}\">\n" +
16628 " <div class=\"att-radio__indicator\" tabindex=\"0\" att-accessibility-click=\"32,13\"ng-click=\"selectedcolor(iconColor)\" \n" +
16629 " ng-style=\"applycolor\" ng-transclude></div>\n" +
16633 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html", []).run(["$templateCache", function($templateCache) {
16634 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html",
16635 "<div class=\"calendar\" ng-class=\"{'monthpicker':mode === 1}\">\n" +
16636 " <div class=\"select2-container\" ng-class=\"{'select2-container-active select2-dropdown-open': showDropdownList}\" style=\"width: 100%; z-index:0\">\n" +
16637 " <a tabindex=\"0\" class=\"select2-choice\" href=\"javascript:void(0)\" att-element-focus=\"focusInputButton\" ng-show=\"!showCalendar\" att-accessibility-click=\"13,32\" ng-click=\"showDropdown()\" ng-blur=\"focusInputButton=false\">\n" +
16638 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
16639 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" ng-change=\"getDropdownText()\" />\n" +
16640 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
16641 " <span ng-class=\"{'select2-arrow': mode !== 1, 'calendar-icon': mode === 1}\"><b></b></span>\n" +
16643 " <a class=\"select2-choice\" href=\"javascript:void(0)\" ng-show=\"showCalendar\">\n" +
16644 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
16645 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" ng-change=\"getDropdownText()\" />\n" +
16646 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
16647 " <span tabindex=\"0\" ng-class=\"{'select2-arrow': mode !== 1, 'calendar-icon': mode === 1}\" att-accessibility-click=\"13,32\" ng-click=\"showDropdown()\"><b></b></span>\n" +
16650 " <div class=\"select2-drop select2-drop-active select2-display-none\" ng-style=\"{display: (showDropdownList && 'block') || 'none', 'border-radius': showCalendar && '0 0 0 6px'}\" style=\"width: 100%\">\n" +
16651 " <div id=\"dateFilterList\" att-scrollbar ><ul class=\"select2-results options\" ng-transclude></ul></div>\n" +
16652 " <ul class=\"select2-results sttings\" style=\"margin-top:0px\">\n" +
16653 " <li tabindex=\"0\" class=\"select2-result select2-highlighted greyBorder\" ng-class=\"{'select2-result-current': checkCurrentSelection('Custom Single Date')}\" att-accessibility-click=\"13,32\" ng-click=\"selectAdvancedOption('Custom Single Date')\">\n" +
16654 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Single Date...</div>\n" +
16655 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom single month...</div>\n" +
16657 " <li tabindex=\"0\" class=\"select2-result select2-highlighted\" ng-class=\"{'select2-result-current': checkCurrentSelection('Custom Range')}\" att-accessibility-click=\"13,32\" ng-click=\"selectAdvancedOption('Custom Range')\">\n" +
16658 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Range...</div>\n" +
16659 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom month range...</div>\n" +
16661 " <li class=\"select2-result select2-highlighted btnContainer\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
16662 " <button tabindex=\"0\" ng-blur=\"resetFocus($event)\" att-element-focus=\"focusApplyButton\" att-button=\"\" btn-type=\"{{applyButtonType}}\" size=\"small\" att-accessibility-click=\"13,32\" ng-click=\"apply()\">Apply</button>\n" +
16663 " <button tabindex=\"0\" att-button=\"\" btn-type=\"secondary\" size=\"small\" att-accessibility-click=\"13,32\" ng-click=\"cancel()\">Cancel</button>\n" +
16665 " <a tabindex=\"0\" href=\"javascript:void(0)\" ng-if=\"mode !== 1\" style=\"text-decoration:underline;\" att-accessibility-click=\"13,32\" ng-click=\"clear()\">Clear Dates</a>\n" +
16666 " <a tabindex=\"0\" href=\"javascript:void(0)\" ng-if=\"mode === 1\" style=\"text-decoration:underline;\" att-accessibility-click=\"13,32\" ng-click=\"clear()\">Clear Months</a>\n" +
16671 " <div class=\"datepicker-wrapper show-right\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
16672 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusSingleDateCalendar\" ng-show=\"checkCurrentSelection('Custom Single Date')\"></span>\n" +
16673 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusRangeCalendar\" ng-show=\"checkCurrentSelection('Custom Range')\"></span>\n" +
16679 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html", []).run(["$templateCache", function($templateCache) {
16680 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html",
16681 "<li ng-click=\"!disabled && selectOption(fromDate,toDate,caption)\" att-accessibility-click=\"13,32\" ng-class=\"{'select2-result-current': checkCurrentSelection(caption)}\" class=\"select2-result select2-highlighted ng-scope\" tabindex=\"{{!disabled?'0':'-1'}}\">\n" +
16682 " <div class=\"select2-result-label\" ng-class=\"{'disabled':disabled}\" ng-transclude></div>\n" +
16686 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
16687 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepicker.html",
16688 "<ul id=\"datepicker\" class=\"datepicker\" ng-class=\"{'monthpicker': mode === 1}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
16689 " <div class=\"datepicker-days\" style=\"display: block;\">\n" +
16690 " <table class=\"table-condensed\">\n" +
16693 " <th id=\"month\" tabindex=\"0\" class=\"datepicker-switch\" colspan=\"{{(mode !== 1) && (currentRows[0].length - 2) || (currentRows[0].length)}}\" style=\"text-align:left\">{{currentTitle}}</th>\n" +
16694 " <th ng-if=\"mode !== 1\" id=\"prev\" aria-hidden=\"{{!disablePrev && 'false' || 'true'}}\" tabindex=\"{{!disablePrev && '0' || '-1'}}\" att-accessibility-click=\"13,32\" ng-click=\"!disablePrev && move(-1)\">\n" +
16695 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-left-circle\" ng-class=\"{'disabled': disablePrev}\"></i>\n" +
16696 " </div><span class=\"hidden-spoken\">Previous Month</span>\n" +
16698 " <th ng-if=\"mode !== 1\" id=\"next\" aria-hidden=\"{{!disableNext && 'false' || 'true'}}\" tabindex=\"{{!disableNext && '0' || '-1'}}\" att-accessibility-click=\"13,32\" ng-click=\"!disableNext && move(1)\">\n" +
16699 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-right-circle\" ng-class=\"{'disabled': disableNext}\"></i>\n" +
16700 " </div><span class=\"hidden-spoken\">Next Month</span>\n" +
16703 " <tr ng-if=\"labels.length > 0\">\n" +
16704 " <th id=\"{{label.post}}\" tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"><span>{{label.pre}}</span><span class=\"hidden-spoken\">{{label.post}}</span></th>\n" +
16709 " <td id=\"datepickerBody\" att-scrollbar colspan=\"{{currentRows[0].length}}\" style=\"padding: 0px;\">\n" +
16710 " <table ng-class=\"{'table-condensed': mode === 0, 'monthtable-condensed': mode === 1}\" style=\"padding: 0px;\">\n" +
16711 " <thead class=\"hidden-spoken\">\n" +
16712 " <tr ng-show=\"labels.length > 0\">\n" +
16713 " <th id=\"{{label.post}}\" tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"><span>{{label.post}}</span></th>\n" +
16717 " <tr ng-repeat=\"row in currentRows\">\n" +
16718 " <td headers=\"{{dt.header}}\" att-element-focus=\"dt.focused\" aria-hidden=\"{{(!dt.oldMonth && !dt.nextMonth && !dt.disabled && 'false') || 'true'}}\" tabindex=\"{{(!dt.oldMonth && !dt.nextMonth && !dt.disabled && '0') || '-1'}}\" ng-repeat=\"dt in row\" class=\"days\" ng-class=\"{'active': dt.selected || dt.from || dt.to, 'from': dt.from, 'to': dt.to, 'range': dt.dateRange, 'prev-month ': dt.oldMonth, 'next-month': dt.nextMonth, 'disabled': dt.disabled, 'today': dt.today, 'weekend': dt.weekend}\" ng-click=\"!dt.selected && !dt.from && !dt.to && !dt.disabled && !dt.oldMonth && !dt.nextMonth && select(dt.date)\" att-accessibility-click=\"13,32\"><span aria-label=\"{{dt.label}}\" class=\"day\">{{dt.label}}</span></td>\n" +
16720 " <tr ng-if=\"mode === 1\" class=\"divider\"><td colspan=\"{{nextRows[0].length}}\"><hr></td></tr>\n" +
16722 " <th id=\"month\" tabindex=\"0\" class=\"datepicker-switch internal\" colspan=\"{{nextRows[0].length}}\" style=\"text-align:left\">{{nextTitle}}</th>\n" +
16724 " <tr ng-repeat=\"row in nextRows\">\n" +
16725 " <td headers=\"{{dt.header}}\" att-element-focus=\"dt.focused\" aria-hidden=\"{{(!dt.oldMonth && !dt.nextMonth && !dt.disabled && 'false') || 'true'}}\" tabindex=\"{{(!dt.oldMonth && !dt.nextMonth && !dt.disabled && '0') || '-1'}}\" ng-repeat=\"dt in row\" class=\"days\" ng-class=\"{'active': dt.selected || dt.from || dt.to, 'from': dt.from, 'to': dt.to, 'range': dt.dateRange, 'prev-month ': dt.oldMonth, 'next-month': dt.nextMonth, 'disabled': dt.disabled, 'today': dt.today, 'weekend': dt.weekend}\" ng-click=\"!dt.selected && !dt.from && !dt.to && !dt.disabled && !dt.oldMonth && !dt.nextMonth && select(dt.date)\" att-accessibility-click=\"13,32\"><span aria-label=\"{{dt.label}}\" class=\"day\">{{dt.label}}</span></td>\n" +
16738 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html", []).run(["$templateCache", function($templateCache) {
16739 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html",
16740 "<div class=\"calendar\">\n" +
16741 " <div class=\"box\" ng-class=\"{'active': isOpen}\">\n" +
16742 " <span ng-transclude></span>\n" +
16743 " <i class=\"calendar-icon\" tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\"></i>\n" +
16745 " <div class=\"datepicker-wrapper datepicker-wrapper-display-none\" ng-style=\"{display: (isOpen && 'block') || 'none'}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
16746 " <span datepicker></span>\n" +
16752 angular.module("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html", []).run(["$templateCache", function($templateCache) {
16753 $templateCache.put("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html",
16754 "<div class=\"divider-container\" ng-class=\"{'divider-container-light': lightContainer}\">\n" +
16755 " <hr ng-class=\"{'divider-light': lightContainer}\">\n" +
16761 angular.module("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html", []).run(["$templateCache", function($templateCache) {
16762 $templateCache.put("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html",
16763 "<label class=\"fileContainer\"><span ng-transclude></span><input type=\"file\" att-file-change></label>");
16766 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html", []).run(["$templateCache", function($templateCache) {
16767 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html",
16768 "<div class=\"form-field\" ng-class=\"{'error': errorMessage, 'warning': warningMessage}\">\n" +
16769 " <label class=\"form-field__label\" ng-class=\"{'form-field__label--show': showLabel, 'form-field__label--hide': hideLabel}\"></label>\n" +
16770 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
16774 angular.module("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html", []).run(["$templateCache", function($templateCache) {
16775 $templateCache.put("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html",
16776 "<div class=\"hourpicker\">\n" +
16777 " <div class=\"dropdown-width\">\n" +
16778 " <div ng-model=\"showlist\" class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" >\n" +
16779 " <a class=\"select2-choice\" href=\"javascript:void(0)\" id=\"customSelect\" ng-keydown=\"selectOption(selectPrevNextValue($event,options,selectedOption))\" att-accessibility-click=\"13\" ng-click=\"showDropdown()\">\n" +
16780 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
16781 " <span class=\"select2-arrow\"><b></b></span>\n" +
16784 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultTopWidth\" ng-show=\"showlist\"> \n" +
16785 " <ul class=\"select2-results resultTopMargin\" > \n" +
16786 " <li ng-model=\"ListType\" ng-repeat=\"option in options\" att-accessibility-click=\"13\" ng-click=\"selectOption(option,$index)\" class=\"select2-results-dept-0 select2-result select2-result-selectable\"><div class=\"select2-result-label\"><span >{{option}}</span></div></li> \n" +
16790 " <div ng-show=\"showDaysSelector\" class=\"customdays-width\">\n" +
16791 " <div att-divider-lines class=\"divider-margin-f\"></div> \n" +
16792 " <div class=\"col-md-3 fromto-margin\">\n" +
16793 " <div>From</div> <br>\n" +
16794 " <div>To</div>\n" +
16796 " <div ng-repeat=\"day in days\">\n" +
16797 " <div class=\"col-md-3 col-md-days\">\n" +
16798 " <div class=\"col-md-1 daysselect-margin\">\n" +
16799 " <input type=\"checkbox\" ng-model=\"daysList[day]\" title=\"Day selection\" att-checkbox ng-change=\"addSelectedValue(day)\"> \n" +
16801 " <span>{{day}}</span><br>\n" +
16803 " <div class=\"dropDownMarginBottom\">\n" +
16804 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': FrtimeListDay[day]}\" >\n" +
16805 " <a class=\"select2-choice selectDropDown\" href=\"javascript:void(0)\" tabindex=\"{{daysList[day] ? '0' : '-1'}}\" att-accessibility-click=\"13\" ng-click=\"daysList[day] && showfromDayDropdown(day)\" ng-class=\"{'select2-chosen-disabled':!daysList[day]}\" ng-keydown=\"daysList[day] && selectFromDayOption(day , selectPrevNextValue($event,fromtime,selectedFromOption[day]));daysList[day] && addSelectedValue(day);\">\n" +
16806 " <span class=\"select2-chosen dropDownMarginRight\" >{{selectedFromOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"FrtimeListDay[day] ? 'icon-dropdown-up' : 'icon-dropdown-down'\"></i></span>\n" +
16810 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultFromDropDown\" ng-show=\"FrtimeListDay[day]\"> \n" +
16811 " <ul class=\"select2-results resultTopMargin\" > \n" +
16812 " <li ng-click=\"selectFromDayOption(day,time.value);addSelectedValue(day);\" ng-repeat=\"time in fromtime\" class=\"select2-results-dept-0 select2-result select2-result-selectable\"><div class=\"select2-result-label\" ng-class=\"{'selectedItemInDropDown': (time.value==selectedFromOption[day])}\"><span >{{time.value}}</span></div></li> \n" +
16817 " <div class=\"dropDownMarginBottom\">\n" +
16818 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': TotimeListDay[day]}\" >\n" +
16819 " <a class=\"select2-choice selectDropDown\" href=\"javascript:void(0)\" tabindex=\"{{daysList[day] ? '0' : '-1'}}\" att-accessibility-click=\"13\" ng-click=\"daysList[day] && showtoDayDropdown(day)\" ng-class=\"{'select2-chosen-disabled':!daysList[day]}\" ng-keydown=\"daysList[day] && selectToDayOption(day , selectPrevNextValue($event,totime,selectedToOption[day]));daysList[day] && addSelectedValue(day);\">\n" +
16820 " <span class=\"select2-chosen dropDownMarginRight\">{{selectedToOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"TotimeListDay[day] ? 'icon-dropdown-up' : 'icon-dropdown-down'\" ></i></span>\n" +
16824 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultToDropDown\" ng-show=\"TotimeListDay[day]\"> \n" +
16825 " <ul class=\"select2-results resultTopMargin\" > \n" +
16826 " <li ng-click=\"selectToDayOption(day,time.value);addSelectedValue(day);\" ng-repeat=\"time in totime\" class=\"select2-results-dept-0 select2-result select2-result-selectable\"><div class=\"select2-result-label\" ng-class=\"{'selectedItemInDropDown': (time.value==selectedToOption[day])}\"><span >{{time.value}}</span></div></li> \n" +
16832 " <div att-divider-lines class=\"divider-margin-s\"></div> \n" +
16834 " <div ng-transclude></div>\n" +
16838 angular.module("app/scripts/ng_js_att_tpls/links/readMore.html", []).run(["$templateCache", function($templateCache) {
16839 $templateCache.put("app/scripts/ng_js_att_tpls/links/readMore.html",
16841 " <div ng-bind-html=\"textToDisplay\" ng-class=\"{'att--readMore': readFlag, 'att--readLess': !readFlag}\" ng-style=\"readLinkStyle\"></div>\n" +
16842 " <span class=\"att--readmore__link\" ng-show=\"readMoreLink\">… <a href=\"#\" ng-click=\"readMore()\" att-accessbility-click=\"32,13\">Read More</a>\n" +
16845 "<span class=\"att--readless__link\" ng-show=\"readLessLink\">\n" +
16846 " <a href=\"#\" ng-click=\"readLess()\" att-accessbility-click=\"32,13\">Read Less</a>\n" +
16850 angular.module("app/scripts/ng_js_att_tpls/loading/loading.html", []).run(["$templateCache", function($templateCache) {
16851 $templateCache.put("app/scripts/ng_js_att_tpls/loading/loading.html",
16852 "<div data-progress=\"{{progressStatus}}\" class=\"{{colorClass}}\" ng-class=\"{'att-loading-count':icon == 'count','loading--small':icon == 'small','loading': icon != 'count'}\">\n" +
16853 " <div class=\"att-loading-circle\" ng-if=\"icon == 'count'\">\n" +
16854 " <div class=\"att-loading-circle__mask att-loading-circle__full\">\n" +
16855 " <div class=\"att-loading-circle__fill\"></div>\n" +
16857 " <div class=\"att-loading-circle__mask att-loading-circle__half\">\n" +
16858 " <div class=\"att-loading-circle__fill\"></div>\n" +
16859 " <div class=\"att-loading-circle__fill att-loading-circle__fix\"></div>\n" +
16862 " <div ng-class=\"{'att-loading-inset':icon == 'count','loading__inside':icon != 'count'}\"><div class=\"att-loading-inset__percentage\" ng-if=\"icon == 'count'\"></div></div>\n" +
16868 angular.module("app/scripts/ng_js_att_tpls/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
16869 $templateCache.put("app/scripts/ng_js_att_tpls/modal/backdrop.html",
16870 "<div class=\"overlayed\" ng-class=\"{show: animate}\" \n" +
16871 " ng-style=\"{'z-index': 2000 + index*10,'overflow':'scroll'}\"> \n" +
16875 angular.module("app/scripts/ng_js_att_tpls/modal/window.html", []).run(["$templateCache", function($templateCache) {
16876 $templateCache.put("app/scripts/ng_js_att_tpls/modal/window.html",
16877 "<div tabindex=\"-1\" role=\"dialog\" att-element-focus=\"focusModalFlag\" class=\"modals {{ windowClass }}\" ng-class=\"{show: animate}\" \n" +
16878 " ng-style=\"{'z-index': 2010 + index*10}\" ng-click=\"close($event)\" ng-transclude> \n" +
16883 angular.module("app/scripts/ng_js_att_tpls/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
16884 $templateCache.put("app/scripts/ng_js_att_tpls/pagination/pagination.html",
16885 "<div class=\"pager\">\n" +
16886 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"pager__item--prev\" att-accessibility-click=\"13,32\" ng-click=\"prev($event)\" ng-if=\"currentPage > 1\"><i class=\"icon-arrow-left\"></i> Previous</a>\n" +
16887 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"pager__item pager__item--link\" ng-if=\"totalPages > 7 && currentPage > 3\" att-accessibility-click=\"13,32\" ng-click=\"selectPage(1, $event)\">1</a>\n" +
16888 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage > 3\">...</span>\n" +
16889 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"pager__item pager__item--link\" att-element-focus=\"isFocused(page)\" ng-repeat=\"page in pages\" ng-class=\"{'pager__item--active': checkSelectedPage(page)}\" att-accessibility-click=\"13,32\" ng-click=\"selectPage(page, $event)\">{{page}}</a>\n" +
16890 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage < totalPages - 2 && showInput !== true\">...</span>\n" +
16891 " <span ng-show=\"totalPages > 7 && showInput === true\"><input class=\"pager__item--input\" type=\"text\" placeholder=\"...\" maxlength=\"2\" ng-model=\"currentPage\"/></span>\n" +
16892 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"pager__item pager__item--link\" ng-if=\"totalPages > 7 && currentPage < totalPages - 2\" att-accessibility-click=\"13,32\" ng-click=\"selectPage(totalPages, $event)\">{{totalPages}}</a>\n" +
16893 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"pager__item--next\" att-accessibility-click=\"13,32\" ng-click=\"next($event)\" ng-if=\"currentPage < totalPages\">Next <i class=\"icon-arrow-right\"></i></a>\n" +
16897 angular.module("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html", []).run(["$templateCache", function($templateCache) {
16898 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html",
16899 "<div class='inner-pane'>\n" +
16900 " <div ng-transclude>\n" +
16905 angular.module("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html", []).run(["$templateCache", function($templateCache) {
16906 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html",
16907 "<div class='pane-group'>\n" +
16908 " <div ng-transclude>\n" +
16913 angular.module("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html", []).run(["$templateCache", function($templateCache) {
16914 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html",
16915 "<div class='side-pane'> \n" +
16916 " <div ng-transclude>\n" +
16921 angular.module("app/scripts/ng_js_att_tpls/profileCard/addUser.html", []).run(["$templateCache", function($templateCache) {
16922 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/addUser.html",
16923 "<div class=\"col-md-9 profile-card add-user\">\n" +
16924 " <div class=\"atcenter\">\n" +
16925 " <div><i class=\"icon-add\"></i></div>\n" +
16926 " <span>add User</span>\n" +
16931 angular.module("app/scripts/ng_js_att_tpls/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
16932 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/profileCard.html",
16933 " <div class=\"col-md-9 profile-card\">\n" +
16934 " <div class=\"top-block\">\n" +
16935 " <div class=\"profile-image\">\n" +
16936 " <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
16937 " <span ng-hide=\"image\" class=\"default-img\">{{initials}}</span>\n" +
16938 " <p class=\"name\" tooltip-condition=\"{{profile.name}}\" height=\"true\"></p>\n" +
16939 " <p class=\"status\">\n" +
16940 " <span class=\"status-icon\" ng-class=\"{'icon-green':colorIcon==='green','icon-red':colorIcon==='red','icon-blue':colorIcon==='blue','icon-yellow':colorIcon==='yellow'}\"> \n" +
16942 " <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
16946 " <div class=\"bottom-block\">\n" +
16947 " <div class=\"profile-details\">\n" +
16948 " <label>Username</label>\n" +
16949 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.userName}}\">{{profile.userName}}</p>\n" +
16950 " <label>Email</label>\n" +
16951 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.email}}\">{{profile.email}}</p>\n" +
16952 " <label>Role</label>\n" +
16953 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.role}}\">{{profile.role}}</p>\n" +
16954 " <label>Last Login</label>\n" +
16955 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.lastLogin}}\">{{profile.lastLogin}}</p>\n" +
16961 angular.module("app/scripts/ng_js_att_tpls/progressBars/progressBars.html", []).run(["$templateCache", function($templateCache) {
16962 $templateCache.put("app/scripts/ng_js_att_tpls/progressBars/progressBars.html",
16963 "<div class=\"att-progress\">\n" +
16964 " <div class=\"att-progress-value\"> </div>\n" +
16968 angular.module("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html", []).run(["$templateCache", function($templateCache) {
16969 $templateCache.put("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html",
16970 "<div class=\"scroll-bar\">\n" +
16971 " <div class=\"scroll-thumb\"></div>\n" +
16973 "<div class=\"scroll-viewport\">\n" +
16974 " <div class=\"scroll-overview\" ng-transclude></div>\n" +
16978 angular.module("app/scripts/ng_js_att_tpls/search/search.html", []).run(["$templateCache", function($templateCache) {
16979 $templateCache.put("app/scripts/ng_js_att_tpls/search/search.html",
16980 "<div class=\"select2-container show-search\" ng-class=\"{'select2-dropdown-open': (showlist && !isDisabled),'select2-container-disabled':isDisabled, 'select2-container-active': isact}\" ng-init=\"isact=false;\" style=\"width: 100%;\">\n" +
16981 " <a href=\"javascript:void(0)\" class=\"select2-choice needsclick\" tabindex=\"0\" ng-click=\"showDropdown()\" ng-class=\"{'select2-chosen-disabled':isDisabled}\" ng-focus=\"isact=true;\" ng-blur=\"isact=false;\">\n" +
16982 " <span class=\"select2-chosen needsclick\">{{selectedOption}}</span>\n" +
16983 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
16984 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
16985 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
16988 " <label class=\"select2-offscreen\"></label>\n" +
16989 " <input class=\"select2-focusser select2-offscreen\" tabindex=\"-1\" type=\"text\" aria-haspopup=\"true\" role=\"button\">\n" +
16991 "<div class=\"select2-drop select2-with-searchbox select2-drop-auto-width select2-drop-active\" ng-class=\"{'select2-display-none':(!showlist || isDisabled),'show-search':showSearch}\" style=\"width:100%;z-index: 10\">\n" +
16992 " <div class=\"select2-search\">\n" +
16993 " <label class=\"select2-offscreen\"></label>\n" +
16994 " <input ng-model=\"title\" typeahead=\"c.title for c in cName | filter:$viewValue:startsWith\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"select2-input\" role=\"combobox\" aria-\n" +
16995 "expanded=\"true\" aria-autocomplete=\"list\" placeholder=\"\">\n" +
16997 " <ul class=\"select2-results\" role=\"listbox\">\n" +
16998 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\">No matches found</li>\n" +
16999 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17000 " ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\"\n" +
17001 " ng-click=\"selectOption(selectMsg, '-1')\"\n" +
17002 " ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\"\n" +
17003 " ng-mouseover=\"hoverIn(-1)\">\n" +
17004 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
17005 " <span class=\"select2-match\" ></span>\n" +
17007 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
17008 " <span class=\"select2-match\" ></span>\n" +
17011 " <li ng-if=\"startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17012 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | startsWith:title:item)\"\n" +
17013 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
17014 " ng-click=\"selectOption(item.title,item.index)\"\n" +
17015 " ng-mouseover=\"hoverIn(item.index)\">\n" +
17016 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
17017 " <span class=\"select2-match\" ></span>\n" +
17021 " <li ng-if=\"!startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17022 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\"\n" +
17023 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
17024 " ng-click=\"selectOption(item.title,item.index)\"\n" +
17025 " ng-mouseover=\"hoverIn(item.index)\"\n" +
17027 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
17028 " <span class=\"select2-match\" ></span>\n" +
17037 angular.module("app/scripts/ng_js_att_tpls/search/search_2.html", []).run(["$templateCache", function($templateCache) {
17038 $templateCache.put("app/scripts/ng_js_att_tpls/search/search_2.html",
17039 "<div ng-model=\"showlist\" class=\"select2-container\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" style=\"width: 100%; z-index:0\">\n" +
17040 " <a tabindex=\"-1\" class=\"select2-choice\" href=\"javascript:void(0)\" ng-click=\"showDropdown()\">\n" +
17041 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
17042 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
17043 " <span class=\"select2-arrow\"><b></b></span>\n" +
17045 " <input type=\"text\" class=\"select2-focusser select2-offscreen\">\n" +
17047 "<select ng-model=\"value\" ng-options=\"c.title for c in cName\" class=\"select2-offscreen\"></select>\n" +
17048 "<div class=\"select2-drop select2-display-none select2-with-searchbox select2-drop-active show-search\" style=\"display: block; width: 100%;\" ng-show=\"showlist\">\n" +
17049 " <div ng-show=\"showSearch\" class=\"select2-search\">\n" +
17050 " <input ng-model=\"title\" typeahead=\"c.title for c in cName | filter:$viewValue:startsWith\" type=\"text\" class=\"select2-input\" spellcheck=\"false\" autocapitalize=\"off\" autocorrect=\"off\" autocomplete=\"off\">\n" +
17052 " <ul class=\"select2-results\" style=\"margin-top:0px;max-height:205px\">\n" +
17053 " <li ng-model=\"ListType\" ng-repeat=\"(fIndex, country) in cName | filter:title\" ng-class=\"{'select2-result-current': selectedOption === country.title}\" ng-click=\"selectOption(country.title,country.index)\" class=\"select2-results-dept-0 select2-result select2-result-selectable select2-highlighted\">\n" +
17054 " <div class=\"select2-result-label\" ng-bind-html=\"country.title | highlight:title:className\"><span class=\"select2-match\"></span>\n" +
17062 angular.module("app/scripts/ng_js_att_tpls/select/select.html", []).run(["$templateCache", function($templateCache) {
17063 $templateCache.put("app/scripts/ng_js_att_tpls/select/select.html",
17064 "<div class=\"select2-container show-search\" ng-class=\"{'select2-dropdown-open': (showlist && !isDisabled),'select2-container-disabled':isDisabled, 'select2-container-active': isact}\" ng-init=\"isact=false;\" style=\"width: 100%;\">\n" +
17065 " <a href=\"javascript:void(0)\" class=\"select2-choice needsclick\" tabindex=\"0\" ng-click=\"showDropdown()\" ng-class=\"{'select2-chosen-disabled':isDisabled}\" ng-focus=\"isact=true;\" ng-blur=\"isact=false;\">\n" +
17066 " <span class=\"select2-chosen needsclick\">{{selectedOption}}</span>\n" +
17067 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
17068 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
17069 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
17072 " <label class=\"select2-offscreen\"></label>\n" +
17073 " <input class=\"select2-focusser select2-offscreen\" tabindex=\"-1\" type=\"text\" aria-haspopup=\"true\" role=\"button\">\n" +
17075 "<div class=\"select2-drop select2-with-searchbox select2-drop-auto-width select2-drop-active\" ng-class=\"{'select2-display-none':(!showlist || isDisabled),'show-search':showSearch}\" style=\"width:100%;z-index: 10\">\n" +
17076 " <div class=\"select2-search\">\n" +
17077 " <label class=\"select2-offscreen\"></label>\n" +
17078 " <input ng-model=\"title\" typeahead=\"c.title for c in cName | filter:$viewValue:startsWith\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"select2-input\" role=\"combobox\" aria-\n" +
17079 "expanded=\"true\" aria-autocomplete=\"list\" placeholder=\"\">\n" +
17081 " <ul class=\"select2-results\" role=\"listbox\">\n" +
17082 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\">No matches found</li>\n" +
17083 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17084 " ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\"\n" +
17085 " ng-click=\"selectOption(selectMsg, '-1')\"\n" +
17086 " ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\"\n" +
17087 " ng-mouseover=\"hoverIn(-1)\">\n" +
17088 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
17089 " <span class=\"select2-match\" ></span>\n" +
17091 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
17092 " <span class=\"select2-match\" ></span>\n" +
17095 " <li ng-if=\"startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17096 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | startsWith:title:item)\"\n" +
17097 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
17098 " ng-click=\"selectOption(item.title,item.index)\"\n" +
17099 " ng-mouseover=\"hoverIn(item.index)\">\n" +
17100 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
17101 " <span class=\"select2-match\" ></span>\n" +
17105 " <li ng-if=\"!startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17106 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\"\n" +
17107 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
17108 " ng-click=\"selectOption(item.title,item.index)\"\n" +
17109 " ng-mouseover=\"hoverIn(item.index)\"\n" +
17111 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
17112 " <span class=\"select2-match\" ></span>\n" +
17121 angular.module("app/scripts/ng_js_att_tpls/select/textDropdown.html", []).run(["$templateCache", function($templateCache) {
17122 $templateCache.put("app/scripts/ng_js_att_tpls/select/textDropdown.html",
17123 "<div tabindex=\"0\" class=\"text-dropdown\">\n" +
17124 " <div class=\"dropdown\" ng-class=\"{'not-visible': isActionsShown}\" ng-click=\"toggle()\" >\n" +
17125 " <span class=\"action--selected\" ng-bind=\"currentAction\"></span>\n" +
17126 " <i ng-class=\"isActionsShown ? 'icon-dropdown-up' : 'icon-dropdown-down'\"></i>\n" +
17129 " <ul ng-class=\"isActionsShown ? 'actionsOpened' : 'actionsClosed'\" ng-show=\"isActionsShown\">\n" +
17130 " <li ng-class=\"{'highlight': selectedIndex==$index}\" ng-repeat=\"action in actions track by $index\" ng-click=\"chooseAction($event, action)\" ng-mouseover=\"hoverIn($index)\">{{action}}<i ng-class=\"{'icon-included-checkmark': isCurrentAction(action)}\"></i></li>\n" +
17136 angular.module("app/scripts/ng_js_att_tpls/slider/maxContent.html", []).run(["$templateCache", function($templateCache) {
17137 $templateCache.put("app/scripts/ng_js_att_tpls/slider/maxContent.html",
17138 "<div class=\"att-slider__label att-slider__label--max att-slider__label--below\" ng-transclude></div>");
17141 angular.module("app/scripts/ng_js_att_tpls/slider/minContent.html", []).run(["$templateCache", function($templateCache) {
17142 $templateCache.put("app/scripts/ng_js_att_tpls/slider/minContent.html",
17143 " <div class=\"att-slider__label att-slider__label--min att-slider__label--below\" ng-transclude></div>");
17146 angular.module("app/scripts/ng_js_att_tpls/slider/slider.html", []).run(["$templateCache", function($templateCache) {
17147 $templateCache.put("app/scripts/ng_js_att_tpls/slider/slider.html",
17148 "<div class=\"att-slider\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\">\n" +
17149 " <div class=\"att-slider__track\">\n" +
17150 " <div class=\"att-slider__range att-slider__range--disabled\" ng-style=\"disabledStyle\"></div>\n" +
17151 " <div class=\"att-slider__range\" ng-style=\"rangeStyle\"></div>\n" +
17153 " <div class=\"att-slider__handles-container\">\n" +
17154 " <div class=\"att-slider__handle\" ng-style=\"handleStyle\" ng-mousedown=\"mouseDown($event,'ngModelSingle')\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\" tabindex=\"0\" ng-keydown=\"keyDown($event,'ngModelSingle')\"></div>\n" +
17155 " <div class=\"att-slider__handle\" ng-style=\"minHandleStyle\" ng-mousedown=\"mouseDown($event,'ngModelLow')\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\" tabindex=\"0\" ng-keydown=\"keyDown($event,'ngModelLow')\"></div>\n" +
17156 " <div class=\"att-slider__handle\" ng-style=\"maxHandleStyle\" ng-mousedown=\"mouseDown($event,'ngModelHigh')\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\" tabindex=\"0\" ng-keydown=\"keyDown($event,'ngModelHigh')\"></div>\n" +
17158 " <div ng-transclude></div>\n" +
17162 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html", []).run(["$templateCache", function($templateCache) {
17163 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html",
17164 "<div class=\" btn-group\" \n" +
17165 " ng-class=\"{'buttons-dropdown--large':!isSmall, \n" +
17166 " 'buttons-dropdown--small':isSmall, \n" +
17167 " 'action-dropdown':isActionDropdown, \n" +
17168 " 'open':isDropDownOpen}\">\n" +
17169 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"button btn buttons-dropdown__split\" \n" +
17170 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
17171 " 'button--secondary':btnType=='secondary', \n" +
17172 " 'button--disabled':btnType=='disabled', \n" +
17173 " 'button--small':isSmall}\" \n" +
17174 " ng-if=\"!isActionDropdown\"\n" +
17175 " ng-click=\"btnType==='disabled'?undefined:clickFxn()\" att-accessibility-click=\"13,32\">{{btnText}}</a>\n" +
17176 " <a tabindex=\"0\" href=\"javascript:void(0)\" role=\"button\" aria-label=\"Toggle Dropdown\" class=\"button buttons-dropdown__drop dropdown-toggle\" \n" +
17177 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
17178 " 'button--secondary':btnType=='secondary', \n" +
17179 " 'button--disabled':btnType=='disabled', \n" +
17180 " 'button--small':isSmall}\" ng-click=\"toggleDropdown()\" att-accessibility-click=\"13,32\"></a>\n" +
17181 " <ul class=\"dropdown-menu\" ng-click=\"hideDropdown()\" ng-transclude></ul>\n" +
17185 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html", []).run(["$templateCache", function($templateCache) {
17186 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html",
17187 "<div class='split-icon-button-container'>\n" +
17189 " <div class='split-icon-button' ng-class=\"{'icon-with-chevron': isRight && !isMiddle && !isLeftNextDropdown && !isNextToDropDown, 'split-icon-button-middle':isMiddle, 'split-icon-button-right':isRight, 'split-icon-button-left':isLeft, 'split-icon-button-left-dropdown': isLeftNextDropdown ,'split-icon-button-next-dropdown': isNextToDropDown,'split-icon-button-dropdown': isDropDownOpen,'split-icon-button-hover':isIconHovered || isDropDownOpen}\" ng-mouseover='isIconHovered = true;' ng-mouseleave='isIconHovered = false;' tabindex=\"-1\" att-accessibility-click=\"13,32\" ng-click='dropDownClicked();'>\n" +
17190 " <a class='{{icon}}' aria-label='{{icon}}' role='button' tabindex=\"0\"></a>\n" +
17191 " <i ng-if=\"isRight && !isMiddle && !isLeftNextDropdown && !isNextToDropDown\" \n" +
17192 " ng-class=\"isDropDownOpen ? 'icon-dropdown-up' : 'icon-dropdown-down'\"> </i>\n" +
17195 " <ul ng-if='isDropdown' class='dropdown-menu {{dropDownId}}' ng-show='\n" +
17196 " isDropDownOpen' ng-click='toggleDropdown(false)' ng-transclude>\n" +
17202 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html", []).run(["$templateCache", function($templateCache) {
17203 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html",
17205 " <div ng-if='isLeftLineShown' dir-type='{{iconStateConstants.DIR_TYPE.LEFT}}' expandable-line></div>\n" +
17206 " <div ng-click='clickHandler()' att-split-icon icon='{{icon}}' dir-type='{{iconStateConstants.DIR_TYPE.BUTTON}}' hover-watch='isHovered' drop-down-watch='dropDownWatch' drop-down-id='{{dropDownId}}'>\n" +
17207 " <div ng-transclude>\n" +
17210 " <div ng-if='isRightLineShown' dir-type='{{iconStateConstants.DIR_TYPE.RIGHT}}' expandable-line></div>\n" +
17214 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html", []).run(["$templateCache", function($templateCache) {
17215 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html",
17216 "<div ng-transclude>\n" +
17220 angular.module("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html", []).run(["$templateCache", function($templateCache) {
17221 $templateCache.put("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html",
17222 "<span ng-class=\"mainSliderClass\">\n" +
17226 " <div class=\"jslider-bg\">\n" +
17227 " <i class=\"l\"></i>\n" +
17228 " <i class=\"r\"></i>\n" +
17229 " <i class=\"v\" ng-class=\"{'step-slider-green':sliderColor == COLORS.GREEN, 'step-slider-blue': sliderColor == COLORS.BLUE_HIGHLIGHT, 'step-slider-magenta': sliderColor == COLORS.MAGENTA, 'step-slider-gold': sliderColor == COLORS.GOLD, 'step-slider-purple': sliderColor == COLORS.PURPLE, 'step-slider-dark-blue': sliderColor == COLORS.DARK_BLUE, 'step-slider-regular': sliderColor == COLORS.REGULAR, 'step-slider-white': sliderColor == COLORS.WHITE, 'cutoff-slider': isCutOffSlider}\"></i>\n" +
17231 " <div class=\"jslider-pointer\" id=\"left-pointer\"></div>\n" +
17232 " <div class=\"jslider-pointer jslider-pointer-to\" ng-class=\"{'step-slider-green':sliderColor == COLORS.GREEN, 'step-slider-blue': sliderColor == COLORS.BLUE_HIGHLIGHT, 'step-slider-magenta': sliderColor == COLORS.MAGENTA, 'step-slider-gold': sliderColor == COLORS.GOLD, 'step-slider-purple': sliderColor == COLORS.PURPLE, 'step-slider-dark-blue': sliderColor == COLORS.DARK_BLUE, 'step-slider-regular': sliderColor == COLORS.REGULAR, 'step-slider-white':sliderColor == COLORS.WHITE ,'cutoff-slider': isCutOffSlider}\"></div>\n" +
17233 " <div class=\"jslider-label\"><span ng-bind=\"from\"></span><span ng-bind=\"options.dimension\"></span></div>\n" +
17234 " <div class=\"jslider-label jslider-label-to\"><span ng-bind=\"toStr\"></span><span ng-bind=\"endDimension\"></span></div>\n" +
17235 " <div class=\"jslider-value\" id=\"jslider-value-left\"><span></span>{{options.dimension}}</div>\n" +
17236 " <div class=\"jslider-value jslider-value-to\"><span></span>{{toolTipDimension}}</div>\n" +
17237 " <div class=\"jslider-scale\" ng-class=\"{'show-dividers': showDividers, 'cutoff-slider-dividers':isCutOffSlider}\">\n" +
17239 " <div class=\"jslider-cutoff\">\n" +
17240 " <div class=\"jslider-label jslider-label-cutoff\">\n" +
17241 " <span ng-bind=\"cutOffVal\"></span>\n" +
17251 angular.module("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html", []).run(["$templateCache", function($templateCache) {
17252 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html",
17253 "<div class=\"steptracker1\">\n" +
17254 " <div class=\"steptracker-bg\">\n" +
17255 " <div class=\"steptracker-track size-onethird\" ng-repeat=\"step in sdata\"\n" +
17256 " ng-style=\"set_width($index)\"\n" +
17257 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index), 'incomplete': isIncomplete($index), 'disabled': disableClick}\">\n" +
17258 " <div class=\"circle\" tabindex=\"0\"\n" +
17259 " ng-click=\"stepclick($event, $index);\"\n" +
17260 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
17261 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
17268 angular.module("app/scripts/ng_js_att_tpls/steptracker/step.html", []).run(["$templateCache", function($templateCache) {
17269 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step.html",
17270 "<div class=\"steptracker1\">\n" +
17271 " <div class=\"steptracker-bg\">\n" +
17272 " <div class=\"steptracker-track size-onethird\" \n" +
17273 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index)}\">\n" +
17274 " <div class=\"circle\" tabindex=\"0\" \n" +
17275 " ng-click=\"stepclick($event, $index);\" \n" +
17276 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
17277 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
17284 angular.module("app/scripts/ng_js_att_tpls/steptracker/timeline.html", []).run(["$templateCache", function($templateCache) {
17285 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timeline.html",
17286 "<div class='att-timeline'>\n" +
17287 " <div timeline-dot order='0' title='{{steps[0].title}}' description='{{steps[0].description}}' by='{{steps[0].by}}' date='{{steps[0].date}}' type='{{steps[0].type}}'></div>\n" +
17289 " <div ng-repeat=\"m in middleSteps track by $index\">\n" +
17290 " <div timeline-bar order='{{$index}}'></div>\n" +
17291 " <div timeline-dot order='{{$index + 1}}' title='{{m.title}}' description='{{m.description}}' by='{{m.by}}' date='{{m.date}}' type='{{m.type}}'>\n" +
17298 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html", []).run(["$templateCache", function($templateCache) {
17299 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html",
17300 "<div class='timeline-bar'>\n" +
17301 " <div class='progress-bar' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
17307 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html", []).run(["$templateCache", function($templateCache) {
17308 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html",
17309 "<div class='timeline-dot'>\n" +
17311 " <div class='bigger-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
17314 " <div class='inactive-circle'>\n" +
17317 " <div class='expandable-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
17320 " <div ng-class=\"{'below-info-box':isBelowInfoBoxShown, 'above-info-box': !isBelowInfoBoxShown}\">\n" +
17322 " <div ng-if='isBelowInfoBoxShown' class='vertical-line'>\n" +
17325 " <div class='info-container' ng-init='isContentShown=false'>\n" +
17326 " <div ng-class=\"{'current-step-title':isCurrentStep, 'title':!isCurrentStep,'completed-color-text':isCompleted,'cancelled-color-text':isCancelled,'alert-color-text':isAlert, 'inactive-color-text':isInactive}\" ng-mouseover='titleMouseover(1)' ng-mouseleave='titleMouseleave()' ng-bind='title' ></div>\n" +
17327 " <div class='content'>\n" +
17328 " <div class='description' ng-bind='description'></div>\n" +
17329 " <div class='submitter' ng-bind='by'></div>\n" +
17331 " <div class='date' ng-mouseover='titleMouseover(2)' ng-mouseleave='titleMouseleave()' ng-bind='date'></div>\n" +
17334 " <div ng-if='!isBelowInfoBoxShown' class='vertical-line'>\n" +
17341 angular.module("app/scripts/ng_js_att_tpls/table/attTable.html", []).run(["$templateCache", function($templateCache) {
17342 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTable.html",
17343 "<table class=\"tablesorter tablesorter-default\" ng-transclude></table>\n" +
17347 angular.module("app/scripts/ng_js_att_tpls/table/attTableBody.html", []).run(["$templateCache", function($templateCache) {
17348 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableBody.html",
17349 "<td ng-transclude></td>\n" +
17353 angular.module("app/scripts/ng_js_att_tpls/table/attTableHeader.html", []).run(["$templateCache", function($templateCache) {
17354 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableHeader.html",
17355 "<th tabindex=\"{{sortable !== 'false' && '0' || '-1'}}\" class=\"tablesorter-header\" ng-class=\"{'tablesorter-headerAsc': sortPattern === 'asc', 'tablesorter-headerDesc': sortPattern === 'desc', 'tablesort-sortable': sortable !== 'false', 'sorter-false': sortable === 'false'}\" att-accessibility-click=\"13,32\" ng-click=\"(sortable !== 'false') && sort(); clickFunc && clickFunc()\"><div class=\"tablesorter-header-inner\" ng-transclude></div></th>\n" +
17359 angular.module("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html", []).run(["$templateCache", function($templateCache) {
17360 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html",
17361 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
17362 " <li ng-repeat=\"tab in tabs\" ng-class=\"{'tabsbid__item tabsbid__item--active': isActiveTab(tab.url), 'tabsbid__item': !isActiveTab(tab.url)}\" ng-click=\"onClickTab(tab)\">\n" +
17363 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
17368 angular.module("app/scripts/ng_js_att_tpls/tabs/genericTabs.html", []).run(["$templateCache", function($templateCache) {
17369 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/genericTabs.html",
17370 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
17371 " <li ng-repeat=\"tab in tabs\" ng-class=\"{'tabsbid__item tabsbid__item--active': isActive(tab.id), 'tabsbid__item': !isActive(tab.id),'tabs__item--active': isActive(tab.id)}\" ng-click=\"clickTab(tab)\">\n" +
17372 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
17378 angular.module("app/scripts/ng_js_att_tpls/tabs/menuTab.html", []).run(["$templateCache", function($templateCache) {
17379 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/menuTab.html",
17380 "<li class=\"megamenu__item\" ng-mouseover=\"showHoverChild($event)\" ng-click=\"showChildren($event);!clickInactive||resetMenu()\" ng-class=\"{'tabs__item--active': menuItem.active==true && !hoverChild==true}\" ng-transclude att-accessibility-click=\"13,32\" tabindex=\"0\"></li>");
17383 angular.module("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html", []).run(["$templateCache", function($templateCache) {
17384 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html",
17385 "<div ng-class=\"{'megamenu-tabs': megaMenu,'submenu-tabs': !megaMenu}\">\n" +
17386 " <ul class=\"megamenu__items\" ng-transclude>\n" +
17391 angular.module("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html", []).run(["$templateCache", function($templateCache) {
17392 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html",
17393 "<div class=\"simplified-tabs\">\n" +
17394 "<ul class=\"simplified-tabs__items\">\n" +
17395 " <li ng-repeat=\"tab in tabs\" class=\"simplified-tabs__item\" ng-class=\"{'tabs__item--active': isActive(tab.id)}\" ng-click=\"clickTab(tab)\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</li>\n" +
17396 " <li class=\"tabs__pointer\"></li>\n" +
17401 angular.module("app/scripts/ng_js_att_tpls/tabs/submenuTab.html", []).run(["$templateCache", function($templateCache) {
17402 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/submenuTab.html",
17403 "<li class=\"tabsbid__item megamenu__item\" ng-class=\"{'subMenuHover': menuItem.active==true}\" ng-mouseover=\"!subMenu || showChildren($event)\" ng-focus=\"!subMenu ||showChildren($event)\" tabindex=\"{{subMenu=='true'?0:-1}}\" ng-click=\"!subMenu ||showMenuClick() ; subMenu ||showSubMenuClick()\" att-accessibility-click=\"13,32\" ng-transclude>\n" +
17407 angular.module("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html", []).run(["$templateCache", function($templateCache) {
17408 $templateCache.put("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html",
17409 "<div class=\"tags__item\" \n" +
17410 " ng-class=\"{'tags__item--small':isSmall, \n" +
17411 " 'tags__item--color':isColor, \n" +
17412 " 'tags__item--cloud':!isClosable && !isColor,'active':applyActiveClass}\"\n" +
17413 " ng-if=\"display\" \n" +
17414 " ng-style=\"{borderColor: border_type_borderColor, background: isHighlight?'#bbb':undefined, color: isHighlight?'#444':undefined }\"\n" +
17415 " ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\">\n" +
17416 " <i class=\"icon-filter tags__item--icon\" ng-if=\"isIcon\"> </i>\n" +
17417 " <i class=\"tags__item--color-icon\" ng-if=\"isColor\" ng-style=\"{backgroundColor: background_type_backgroundColor, borderColor: background_type_borderColor}\"></i>\n" +
17418 " <span class=\"tags__item--title\" tabindex=0 aria-label ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\" ng-transclude></span>\n" +
17419 " <a href=\"javascript:void(0)\" title=\"Dismiss Link\" class=\"tags__item--action\" ng-click=\"closeMe();$event.preventDefault()\" ng-if=\"isClosable\"\n" +
17420 " ng-style=\"{color: (isHighlight && '#444') || '#888' , borderLeft: (isHighlight && '1px solid #444')|| '1px solid #888' }\">\n" +
17421 " <i class=\"icon-erase\"> </i>\n" +
17426 angular.module("app/scripts/ng_js_att_tpls/toggle/demoToggle.html", []).run(["$templateCache", function($templateCache) {
17427 $templateCache.put("app/scripts/ng_js_att_tpls/toggle/demoToggle.html",
17428 "<span ng-transclude></span>\n" +
17429 "<div tabindex=\"0\" class=\"att-switch-content\" hm-drag = \"drag($event)\" att-accessibility-click=\"13,32\" ng-click = \"updateModel($event)\" hm-dragstart = \"alert('hello')\" hm-dragend = \"drag($event)\" ng-class=\"{'large' : directiveValue == 'large'}\" style=\"-webkit-user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\">\n" +
17430 " <div class=\"att-switch-onText\" ng-style=\"\" ng-class=\"{'icon-included-checkmark ico' : on === undefined,'large' : directiveValue == 'large'}\">{{on}}<span class=\"hidden-spoken\">when checked.</span></div>\n" +
17431 " <div class=\"att-switch-thumb\" tabindex=\"0\" ng-class=\"{'large' : directiveValue == 'large'}\"></div>\n" +
17432 " <div class=\"att-switch-offText\" ng-class=\"{'icon-erase ico' : on === undefined,'large' : directiveValue == 'large'}\">{{off}}<span class=\"hidden-spoken\">when unchecked.</span></div>\n" +
17437 angular.module("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
17438 $templateCache.put("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html",
17439 "<div class=\"att-tooltip \" \n" +
17440 " ng-class=\"{ 'att-tooltip--on': isOpen, \n" +
17441 " 'att-tooltip--dark att-tooltip--dark--hover':stylett=='dark', \n" +
17442 " 'att-tooltip--light att-tooltip--light--hover':stylett=='light',\n" +
17443 " 'att-tooltip--left':placement=='left', \n" +
17444 " 'att-tooltip--above':placement=='above', \n" +
17445 " 'att-tooltip--right':placement=='right', \n" +
17446 " 'att-tooltip--below':placement=='below'}\" \n" +
17447 " ng-bind-html=\"content\" ></div>");
17450 angular.module("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html", []).run(["$templateCache", function($templateCache) {
17451 $templateCache.put("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html",
17452 "<div class=\"typeahead mainContainerOuter\">\n" +
17453 " <span class=\"message\">To</span> \n" +
17454 " <div class='maincontainer' ng-click=\"setFocus()\" ng-class =\"{'typeahed_active':inputActive}\">\n" +
17455 " <span tag-badges closable ng-repeat =\"lineItem in lineItems track by $index\" on-close=\"theMethodToBeCalled($index)\" >{{lineItem}}</span>\n" +
17456 " <input type=\"text\" focus-me=\"clickFocus\" id=\"inpute\" aria-label=\"model\" role=\"textfiled\" ng-model=\"model\" ng-keydown=\"selected = false; selectionIndex($event)\"/><br/> \n" +
17458 " <div ng-hide=\"!model.length || selected\">\n" +
17459 " <div class=\"filtercontainer list-scrollable\" ng-show=\"( items | filter:model).length\">\n" +
17460 " <div class=\"item\" ng-repeat=\"item in items| filter:model track by $index\" ng-click=\"handleSelection(item[title],item[subtitle])\" att-accessibility-click=\"13,32\" style=\"cursor:pointer\" ng-class=\"{active:isCurrent($index,item[title],item[subtitle],( items | filter:model).length)}\" aria-label=\"item[title]\" ng-mouseenter=\"setCurrent($index)\">\n" +
17461 " <span class=\"title\" >{{item[title]}}</span>\n" +
17462 " <span class=\"subtitle\">{{item[subtitle]}}</span>\n" +
17467 " <div class=\"textAreaEmailContentDiv\">\n" +
17468 " <span class=\"message\">Message</span>\n" +
17469 " <textarea rows=\"4\" cols=\"50\" role=\"textarea\" class=\"textAreaEmailContent\" ng-model=\"emailMessage\">To send \n" +
17470 " a text, picture, or video message1 to an AT&T wireless device from your email:my message.</textarea>\n" +
17477 angular.module("app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html", []).run(["$templateCache", function($templateCache) {
17478 $templateCache.put("app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html",
17479 "<div class=\"att-table-message\">\n" +
17480 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.noMatching\">\n" +
17481 " <div class=\"img-magnify-glass\"></div> \n" +
17483 " <div ng-transclude></div>\n" +
17486 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.errorLoading\">\n" +
17487 " <div class=\"img-oops-exclamation\"></div> \n" +
17488 " <div>Oops!</div>\n" +
17489 " <div>The information could not load at this time.</div>\n" +
17490 " <div>Please <a href=\"javascript:void(0)\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
17493 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.magnifySearch\">\n" +
17494 " <div class=\"img-magnify-glass\"></div>\n" +
17496 " <p class=\"title\">Please input values to <br/> begin your search.</p>\n" +
17499 " <div class=\"message loading-message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.isLoading\">\n" +
17500 " <div class=\"img-loading-dots\"></div>\n" +
17501 " <div ng-transclude></div>\n" +
17506 angular.module("app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html", []).run(["$templateCache", function($templateCache) {
17507 $templateCache.put("app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html",
17508 "<div class=\"att-user-message\">\n" +
17509 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.error && trigger ? 'message-wrapper-error' : 'hidden'\">\n" +
17510 " <div class=\"message-icon-error\"> <i class=\"icon-info-alert\"></i> </div>\n" +
17512 " <div class=\"message-body-wrapper\">\n" +
17513 " <div class=\"message-title-error\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\"></span> </div>\n" +
17514 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\"> </div>\n" +
17515 " <div class=\"message-bottom\">\n" +
17516 " <div ng-transclude></div>\n" +
17521 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.success && trigger ? 'message-wrapper-success' : 'hidden'\">\n" +
17522 " <div class=\"message-icon-success\"> <i class=\"icon-included-checkmark\"></i> </div>\n" +
17524 " <div class=\"message-body-wrapper\">\n" +
17525 " <div class=\"message-title-success\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\"></span> </div>\n" +
17526 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\"> </div>\n" +
17527 " <div class=\"message-bottom\">\n" +
17528 " <div ng-transclude></div>\n" +
17537 angular.module("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html", []).run(["$templateCache", function($templateCache) {
17538 $templateCache.put("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html",
17540 " <i ng-class=\"{'icon-tickets-active' : type == 'actual' && id =='Active','icon-tickets-referred' : type == 'actual' && id =='Requested Closed','icon-ticket-regular' : type == 'progress' && id =='In Progress','icon-tickets-contested' : type == 'actual' && id =='Contested','icon-tickets-returned' : type == 'actual' && id =='Deferred','icon-tickets-closed' : type == 'actual' && id =='Ready to Close','icon-tickets-cleared' : type == 'actual' && id =='Cleared'}\"></i>\n" +
17541 " <span ng-transclude></span>\n" +
17547 angular.module("app/scripts/ng_js_att_tpls/videoControls/photoControls.html", []).run(["$templateCache", function($templateCache) {
17548 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/photoControls.html",
17550 " <a title=\"Previous Link\" ng-href=\"{{links.prevLink}}\"><i class=\"icon-arrow-left\"> </i></a>\n" +
17551 " <span ng-transclude></span>\n" +
17552 " <a title=\"Next Link\" ng-href=\"{{links.nextLink}}\"><i class=\"icon-arrow-right\"> </i></a>\n" +
17556 angular.module("app/scripts/ng_js_att_tpls/videoControls/videoControls.html", []).run(["$templateCache", function($templateCache) {
17557 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/videoControls.html",
17558 "<div class=\"video-player\">\n" +
17559 " <div class=\"video-player__control video-player__play-button\">\n" +
17560 " <a class=\"video-player__button gigant-play\" data-toggle-buttons=\"icon-play, icon-pause\" data-target=\"i\"><i class=\"icon-play\"></i></a>\n" +
17562 " <div class=\"video-player__control video-player__track\">\n" +
17564 " <div class=\"video-player__track--inner\">\n" +
17565 " <div class=\"video-player__track--loaded\" style=\"width: 75%\"></div>\n" +
17566 " <div class=\"video-player__track--played\" style=\"width: 40%\">\n" +
17567 " <div class=\"att-tooltip att-tooltip--on att-tooltip--dark att-tooltip--above video-player__track-tooltip\" ng-transclude></div>\n" +
17568 " <div class=\"video-player__track-handle\"></div>\n" +
17572 " <a class=\"video-player__time\" ng-transclude></a>\n" +
17573 " <div class=\"video-player__control video-player__volume_icon\">\n" +
17574 " <a class=\"video-player__button\" data-toggle-buttons=\"icon-volume-mute, icon-volume-up\" data-target=\"i\"><i class=\"icon-volume-up\"></i></a>\n" +
17576 " <ul class=\"video-player__control video-player__volume\">\n" +
17577 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
17578 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
17579 " <li class=\"video-player__volume-bar\"> </li>\n" +
17580 " <li class=\"video-player__volume-bar\"> </li>\n" +
17581 " <li class=\"video-player__volume-bar\"> </li>\n" +
17583 " <div class=\"video-player__control video-player__toggle-fullscreen-button\">\n" +
17584 " <a class=\"video-player__button\" data-toggle-buttons=\"icon-full-screen, icon-normal-screen\" data-target=\"i\"><i class=\"icon-full-screen\"> </i></a>\n" +