1 /*Sandbox version 1.2.51*/
2 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.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"]);
3 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/attStepSlider.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/splitButtonDropdown/splitIcon.html","app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButton.html","app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButtonGroup.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"]);
4 angular.module('att.abs.position', [])
6 .factory('$position', ['$document', '$window', function ($document, $window) {
7 function getStyle(el, cssprop) {
8 if (el.currentStyle) { //IE
9 return el.currentStyle[cssprop];
10 } else if ($window.getComputedStyle) {
11 return $window.getComputedStyle(el)[cssprop];
13 // finally try and get inline style
14 return el.style[cssprop];
18 * Checks if a given element is statically positioned
19 * @param element - raw DOM element
21 function isStaticPositioned(element) {
22 return (getStyle(element, "position") || 'static') === 'static';
26 * returns the closest, non-statically positioned parentOffset of a given element
29 var parentOffsetEl = function (element) {
30 var docDomEl = $document[0];
31 var offsetParent = element.offsetParent || docDomEl;
32 while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
33 offsetParent = offsetParent.offsetParent;
35 return offsetParent || docDomEl;
40 * Provides read-only equivalent of jQuery's position function:
41 * http://api.jquery.com/position/
43 position: function (element) {
44 var elBCR = this.offset(element);
45 var offsetParentBCR = {
49 var offsetParentEl = parentOffsetEl(element[0]);
50 if (offsetParentEl != $document[0]) {
51 offsetParentBCR = this.offset(angular.element(offsetParentEl));
52 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
53 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
57 width: element.prop('offsetWidth'),
58 height: element.prop('offsetHeight'),
59 top: elBCR.top - offsetParentBCR.top,
60 left: elBCR.left - offsetParentBCR.left
65 * Provides read-only equivalent of jQuery's offset function:
66 * http://api.jquery.com/offset/
68 offset: function (element) {
69 var boundingClientRect = element[0].getBoundingClientRect();
71 width: element.prop('offsetWidth'),
72 height: element.prop('offsetHeight'),
73 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
74 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
80 .factory('$isElement', [function () {
81 var isElement = function (currentElem, targetElem, alternateElem) {
82 if (currentElem[0] === targetElem[0]) {
84 } else if (currentElem[0] === alternateElem[0]) {
87 return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
97 * UPDATES AND DOCS AT: http://www.greensock.com
99 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
100 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
101 * Club GreenSock members, the software agreement that was issued with your membership.
103 * @author: Jack Doyle, jack@greensock.com
105 (window._gsQueue || (window._gsQueue = [])).push( function() {
109 var _doc = document.documentElement,
111 _max = function(element, axis) {
112 var dim = (axis === "x") ? "Width" : "Height",
113 scroll = "scroll" + dim,
114 client = "client" + dim,
115 body = document.body;
116 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];
119 ScrollToPlugin = window._gsDefine.plugin({
120 propName: "scrollTo",
124 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
125 init: function(target, value, tween) {
126 this._wdw = (target === _window);
127 this._target = target;
129 if (typeof(value) !== "object") {
130 value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
132 this._autoKill = (value.autoKill !== false);
133 this.x = this.xPrev = this.getX();
134 this.y = this.yPrev = this.getY();
135 if (value.x != null) {
136 this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
137 this._overwriteProps.push("scrollTo_x");
141 if (value.y != null) {
142 this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
143 this._overwriteProps.push("scrollTo_y");
150 //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.)
152 this._super.setRatio.call(this, v);
154 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
155 y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
156 yDif = y - this.yPrev,
157 xDif = x - this.xPrev;
159 if (this._autoKill) {
160 //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.
161 if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
162 this.skipX = true; //if the user scrolls separately, we should stop tweening!
164 if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
165 this.skipY = true; //if the user scrolls separately, we should stop tweening!
167 if (this.skipX && this.skipY) {
172 _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
175 this._target.scrollTop = this.y;
178 this._target.scrollLeft = this.x;
186 p = ScrollToPlugin.prototype;
188 ScrollToPlugin.max = _max;
190 p.getX = function() {
191 return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
194 p.getY = function() {
195 return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
198 p._kill = function(lookup) {
199 if (lookup.scrollTo_x) {
202 if (lookup.scrollTo_y) {
205 return this._super._kill.call(this, lookup);
208 }); if (window._gsDefine) { window._gsQueue.pop()(); }
212 * UPDATES AND DOCS AT: http://www.greensock.com
214 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
216 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
217 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
218 * Club GreenSock members, the software agreement that was issued with your membership.
220 * @author: Jack Doyle, jack@greensock.com
223 (window._gsQueue || (window._gsQueue = [])).push( function() {
227 window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
229 var _slice = [].slice,
230 TweenMax = function(target, duration, vars) {
231 TweenLite.call(this, target, duration, vars);
233 this._yoyo = (this.vars.yoyo === true);
234 this._repeat = this.vars.repeat || 0;
235 this._repeatDelay = this.vars.repeatDelay || 0;
236 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
237 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
239 _tinyNum = 0.0000000001,
240 TweenLiteInternals = TweenLite._internals,
241 _isSelector = TweenLiteInternals.isSelector,
242 _isArray = TweenLiteInternals.isArray,
243 p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
246 TweenMax.version = "1.12.1";
247 p.constructor = TweenMax;
248 p.kill()._gc = false;
249 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
250 TweenMax.getTweensOf = TweenLite.getTweensOf;
251 TweenMax.lagSmoothing = TweenLite.lagSmoothing;
252 TweenMax.ticker = TweenLite.ticker;
253 TweenMax.render = TweenLite.render;
255 p.invalidate = function() {
256 this._yoyo = (this.vars.yoyo === true);
257 this._repeat = this.vars.repeat || 0;
258 this._repeatDelay = this.vars.repeatDelay || 0;
260 return TweenLite.prototype.invalidate.call(this);
263 p.updateTo = function(vars, resetDuration) {
264 var curRatio = this.ratio, p;
265 if (resetDuration && this._startTime < this._timeline._time) {
266 this._startTime = this._timeline._time;
267 this._uncache(false);
269 this._enabled(true, false);
271 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.
275 this.vars[p] = vars[p];
279 this._initted = false;
282 this._enabled(true, false);
284 if (this._notifyPluginsOfEnabled && this._firstPT) {
285 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
287 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.
288 var prevTime = this._time;
289 this.render(0, true, false);
290 this._initted = false;
291 this.render(prevTime, true, false);
292 } else if (this._time > 0) {
293 this._initted = false;
295 var inv = 1 / (1 - curRatio),
296 pt = this._firstPT, endValue;
298 endValue = pt.s + pt.c;
300 pt.s = endValue - pt.c;
309 p.render = function(time, suppressEvents, force) {
310 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.
313 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
314 prevTime = this._time,
315 prevTotalTime = this._totalTime,
316 prevCycle = this._cycle,
317 duration = this._duration,
318 prevRawPrevTime = this._rawPrevTime,
319 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
320 if (time >= totalDur) {
321 this._totalTime = totalDur;
322 this._cycle = this._repeat;
323 if (this._yoyo && (this._cycle & 1) !== 0) {
325 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
327 this._time = duration;
328 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
330 if (!this._reversed) {
332 callback = "onComplete";
334 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.
335 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.
338 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
340 if (prevRawPrevTime > _tinyNum) {
341 callback = "onReverseComplete";
344 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.
347 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
348 this._totalTime = this._time = this._cycle = 0;
349 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
350 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
351 callback = "onReverseComplete";
352 isComplete = this._reversed;
355 this._active = false;
356 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.
357 if (prevRawPrevTime >= 0) {
360 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.
362 } 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.
366 this._totalTime = this._time = time;
368 if (this._repeat !== 0) {
369 cycleDuration = duration + this._repeatDelay;
370 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!)
371 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
372 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
374 this._time = this._totalTime - (this._cycle * cycleDuration);
375 if (this._yoyo) if ((this._cycle & 1) !== 0) {
376 this._time = duration - this._time;
378 if (this._time > duration) {
379 this._time = duration;
380 } else if (this._time < 0) {
385 if (this._easeType) {
386 r = this._time / duration;
387 type = this._easeType;
388 pow = this._easePower;
389 if (type === 1 || (type === 3 && r >= 0.5)) {
397 } else if (pow === 2) {
399 } else if (pow === 3) {
401 } else if (pow === 4) {
407 } else if (type === 2) {
409 } else if (this._time / duration < 0.5) {
412 this.ratio = 1 - (r / 2);
416 this.ratio = this._ease.getRatio(this._time / duration);
421 if (prevTime === this._time && !force && prevCycle === this._cycle) {
422 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.
423 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
426 } else if (!this._initted) {
428 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.
430 } 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.
431 this._time = prevTime;
432 this._totalTime = prevTotalTime;
433 this._rawPrevTime = prevRawPrevTime;
434 this._cycle = prevCycle;
435 TweenLiteInternals.lazyTweens.push(this);
439 //_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.
440 if (this._time && !isComplete) {
441 this.ratio = this._ease.getRatio(this._time / duration);
442 } else if (isComplete && this._ease._calcEnd) {
443 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
446 if (this._lazy !== false) {
450 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
451 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.
453 if (prevTotalTime === 0) {
454 if (this._initted === 2 && time > 0) {
456 this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
460 this._startAt.render(time, suppressEvents, force);
461 } else if (!callback) {
462 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.
465 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
466 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
473 pt.t[pt.p](pt.c * this.ratio + pt.s);
475 pt.t[pt.p] = pt.c * this.ratio + pt.s;
480 if (this._onUpdate) {
481 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.
482 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.
484 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
485 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
488 if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
489 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
491 if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
492 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.
493 this._startAt.render(time, suppressEvents, force);
496 if (this._timeline.autoRemoveChildren) {
497 this._enabled(false, false);
499 this._active = false;
501 if (!suppressEvents && this.vars[callback]) {
502 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
504 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.
505 this._rawPrevTime = 0;
510 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
512 TweenMax.to = function(target, duration, vars) {
513 return new TweenMax(target, duration, vars);
516 TweenMax.from = function(target, duration, vars) {
517 vars.runBackwards = true;
518 vars.immediateRender = (vars.immediateRender != false);
519 return new TweenMax(target, duration, vars);
522 TweenMax.fromTo = function(target, duration, fromVars, toVars) {
523 toVars.startAt = fromVars;
524 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
525 return new TweenMax(target, duration, toVars);
528 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
529 stagger = stagger || 0;
530 var delay = vars.delay || 0,
532 finalComplete = function() {
533 if (vars.onComplete) {
534 vars.onComplete.apply(vars.onCompleteScope || this, arguments);
536 onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
539 if (!_isArray(targets)) {
540 if (typeof(targets) === "string") {
541 targets = TweenLite.selector(targets) || targets;
543 if (_isSelector(targets)) {
544 targets = _slice.call(targets, 0);
548 for (i = 0; i < l; i++) {
554 if (i === l - 1 && onCompleteAll) {
555 copy.onComplete = finalComplete;
557 a[i] = new TweenMax(targets[i], duration, copy);
563 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
564 vars.runBackwards = true;
565 vars.immediateRender = (vars.immediateRender != false);
566 return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
569 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
570 toVars.startAt = fromVars;
571 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
572 return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
575 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
576 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});
579 TweenMax.set = function(target, vars) {
580 return new TweenMax(target, 0, vars);
583 TweenMax.isTweening = function(target) {
584 return (TweenLite.getTweensOf(target, true).length > 0);
587 var _getChildrenOf = function(timeline, includeTimelines) {
590 tween = timeline._first;
592 if (tween instanceof TweenLite) {
595 if (includeTimelines) {
598 a = a.concat(_getChildrenOf(tween, includeTimelines));
605 getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
606 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
609 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
610 if (tweens == null) {
613 if (delayedCalls == null) {
616 var a = getAllTweens((timelines != false)),
618 allTrue = (tweens && delayedCalls && timelines),
620 for (i = 0; i < l; i++) {
622 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
624 tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
626 tween._enabled(false, false);
632 TweenMax.killChildTweensOf = function(parent, complete) {
633 if (parent == null) {
636 var tl = TweenLiteInternals.tweenLookup,
637 a, curParent, p, i, l;
638 if (typeof(parent) === "string") {
639 parent = TweenLite.selector(parent) || parent;
641 if (_isSelector(parent)) {
642 parent = _slice.call(parent, 0);
644 if (_isArray(parent)) {
647 TweenMax.killChildTweensOf(parent[i], complete);
653 curParent = tl[p].target.parentNode;
655 if (curParent === parent) {
656 a = a.concat(tl[p].tweens);
658 curParent = curParent.parentNode;
662 for (i = 0; i < l; i++) {
664 a[i].totalTime(a[i].totalDuration());
666 a[i]._enabled(false, false);
670 var _changePause = function(pause, tweens, delayedCalls, timelines) {
671 tweens = (tweens !== false);
672 delayedCalls = (delayedCalls !== false);
673 timelines = (timelines !== false);
674 var a = getAllTweens(timelines),
675 allTrue = (tweens && delayedCalls && timelines),
680 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
686 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
687 _changePause(true, tweens, delayedCalls, timelines);
690 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
691 _changePause(false, tweens, delayedCalls, timelines);
694 TweenMax.globalTimeScale = function(value) {
695 var tl = Animation._rootTimeline,
696 t = TweenLite.ticker.time;
697 if (!arguments.length) {
698 return tl._timeScale;
700 value = value || _tinyNum; //can't allow zero because it'll throw the math off
701 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
702 tl = Animation._rootFramesTimeline;
703 t = TweenLite.ticker.frame;
704 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
705 tl._timeScale = Animation._rootTimeline._timeScale = value;
710 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
712 p.progress = function(value) {
713 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);
716 p.totalProgress = function(value) {
717 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
720 p.time = function(value, suppressEvents) {
721 if (!arguments.length) {
725 this.totalDuration();
727 if (value > this._duration) {
728 value = this._duration;
730 if (this._yoyo && (this._cycle & 1) !== 0) {
731 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
732 } else if (this._repeat !== 0) {
733 value += this._cycle * (this._duration + this._repeatDelay);
735 return this.totalTime(value, suppressEvents);
738 p.duration = function(value) {
739 if (!arguments.length) {
740 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.
742 return Animation.prototype.duration.call(this, value);
745 p.totalDuration = function(value) {
746 if (!arguments.length) {
748 //instead of Infinity, we use 999999999999 so that we can accommodate reverses
749 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
752 return this._totalDuration;
754 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
757 p.repeat = function(value) {
758 if (!arguments.length) {
761 this._repeat = value;
762 return this._uncache(true);
765 p.repeatDelay = function(value) {
766 if (!arguments.length) {
767 return this._repeatDelay;
769 this._repeatDelay = value;
770 return this._uncache(true);
773 p.yoyo = function(value) {
774 if (!arguments.length) {
794 * ----------------------------------------------------------------
796 * ----------------------------------------------------------------
798 window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
800 var TimelineLite = function(vars) {
801 SimpleTimeline.call(this, vars);
803 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
804 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
805 this._sortChildren = true;
806 this._onUpdate = this.vars.onUpdate;
811 if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
812 v[p] = this._swapSelfInParams(val);
815 if (_isArray(v.tweens)) {
816 this.add(v.tweens, 0, v.align, v.stagger);
819 _tinyNum = 0.0000000001,
820 _isSelector = TweenLite._internals.isSelector,
821 _isArray = TweenLite._internals.isArray,
823 _globals = window._gsDefine.globals,
824 _copy = function(vars) {
831 _pauseCallback = function(tween, callback, params, scope) {
832 tween._timeline.pause(tween._startTime);
834 callback.apply(scope || tween._timeline, params || _blankArray);
837 _slice = _blankArray.slice,
838 p = TimelineLite.prototype = new SimpleTimeline();
840 TimelineLite.version = "1.12.1";
841 p.constructor = TimelineLite;
842 p.kill()._gc = false;
844 p.to = function(target, duration, vars, position) {
845 var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
846 return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
849 p.from = function(target, duration, vars, position) {
850 return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
853 p.fromTo = function(target, duration, fromVars, toVars, position) {
854 var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
855 return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
858 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
859 var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
861 if (typeof(targets) === "string") {
862 targets = TweenLite.selector(targets) || targets;
864 if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
865 targets = _slice.call(targets, 0);
867 stagger = stagger || 0;
868 for (i = 0; i < targets.length; i++) {
870 vars.startAt = _copy(vars.startAt);
872 tl.to(targets[i], duration, _copy(vars), i * stagger);
874 return this.add(tl, position);
877 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
878 vars.immediateRender = (vars.immediateRender != false);
879 vars.runBackwards = true;
880 return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
883 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
884 toVars.startAt = fromVars;
885 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
886 return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
889 p.call = function(callback, params, scope, position) {
890 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
893 p.set = function(target, vars, position) {
894 position = this._parseTimeOrLabel(position, 0, true);
895 if (vars.immediateRender == null) {
896 vars.immediateRender = (position === this._time && !this._paused);
898 return this.add( new TweenLite(target, 0, vars), position);
901 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
903 if (vars.smoothChildTiming == null) {
904 vars.smoothChildTiming = true;
906 var tl = new TimelineLite(vars),
909 if (ignoreDelayedCalls == null) {
910 ignoreDelayedCalls = true;
912 root._remove(tl, true);
914 tl._rawPrevTime = tl._time = tl._totalTime = root._time;
918 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
919 tl.add(tween, tween._startTime - tween._delay);
927 p.add = function(value, position, align, stagger) {
928 var curTime, l, i, child, tl, beforeRawTime;
929 if (typeof(position) !== "number") {
930 position = this._parseTimeOrLabel(position, 0, true, value);
932 if (!(value instanceof Animation)) {
933 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
934 align = align || "normal";
935 stagger = stagger || 0;
938 for (i = 0; i < l; i++) {
939 if (_isArray(child = value[i])) {
940 child = new TimelineLite({tweens:child});
942 this.add(child, curTime);
943 if (typeof(child) !== "string" && typeof(child) !== "function") {
944 if (align === "sequence") {
945 curTime = child._startTime + (child.totalDuration() / child._timeScale);
946 } else if (align === "start") {
947 child._startTime -= child.delay();
952 return this._uncache(true);
953 } else if (typeof(value) === "string") {
954 return this.addLabel(value, position);
955 } else if (typeof(value) === "function") {
956 value = TweenLite.delayedCall(0, value);
958 throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
962 SimpleTimeline.prototype.add.call(this, value, position);
964 //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.
965 if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
966 //in case any of the ancestors had completed but should now be enabled...
968 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.
969 while (tl._timeline) {
970 if (beforeRawTime && tl._timeline.smoothChildTiming) {
971 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
973 tl._enabled(true, false);
982 p.remove = function(value) {
983 if (value instanceof Animation) {
984 return this._remove(value, false);
985 } else if (value instanceof Array || (value && value.push && _isArray(value))) {
986 var i = value.length;
988 this.remove(value[i]);
991 } else if (typeof(value) === "string") {
992 return this.removeLabel(value);
994 return this.kill(null, value);
997 p._remove = function(tween, skipDisable) {
998 SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
999 var last = this._last;
1001 this._time = this._totalTime = this._duration = this._totalDuration = 0;
1002 } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
1003 this._time = this.duration();
1004 this._totalTime = this._totalDuration;
1009 p.append = function(value, offsetOrLabel) {
1010 return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
1013 p.insert = p.insertMultiple = function(value, position, align, stagger) {
1014 return this.add(value, position || 0, align, stagger);
1017 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
1018 return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
1021 p.addLabel = function(label, position) {
1022 this._labels[label] = this._parseTimeOrLabel(position);
1026 p.addPause = function(position, callback, params, scope) {
1027 return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
1030 p.removeLabel = function(label) {
1031 delete this._labels[label];
1035 p.getLabelTime = function(label) {
1036 return (this._labels[label] != null) ? this._labels[label] : -1;
1039 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
1041 //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().
1042 if (ignore instanceof Animation && ignore.timeline === this) {
1043 this.remove(ignore);
1044 } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
1047 if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
1048 this.remove(ignore[i]);
1052 if (typeof(offsetOrLabel) === "string") {
1053 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
1055 offsetOrLabel = offsetOrLabel || 0;
1056 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).
1057 i = timeOrLabel.indexOf("=");
1059 if (this._labels[timeOrLabel] == null) {
1060 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
1062 return this._labels[timeOrLabel] + offsetOrLabel;
1064 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
1065 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
1066 } else if (timeOrLabel == null) {
1067 timeOrLabel = this.duration();
1069 return Number(timeOrLabel) + offsetOrLabel;
1072 p.seek = function(position, suppressEvents) {
1073 return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
1076 p.stop = function() {
1077 return this.paused(true);
1080 p.gotoAndPlay = function(position, suppressEvents) {
1081 return this.play(position, suppressEvents);
1084 p.gotoAndStop = function(position, suppressEvents) {
1085 return this.pause(position, suppressEvents);
1088 p.render = function(time, suppressEvents, force) {
1090 this._enabled(true, false);
1092 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
1093 prevTime = this._time,
1094 prevStart = this._startTime,
1095 prevTimeScale = this._timeScale,
1096 prevPaused = this._paused,
1097 tween, isComplete, next, callback, internalForce;
1098 if (time >= totalDur) {
1099 this._totalTime = this._time = totalDur;
1100 if (!this._reversed) if (!this._hasPausedChild()) {
1102 callback = "onComplete";
1103 if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
1104 internalForce = true;
1105 if (this._rawPrevTime > _tinyNum) {
1106 callback = "onReverseComplete";
1110 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.
1111 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.
1113 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
1114 this._totalTime = this._time = 0;
1115 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
1116 callback = "onReverseComplete";
1117 isComplete = this._reversed;
1120 this._active = false;
1121 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.
1122 internalForce = true;
1124 this._rawPrevTime = time;
1126 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.
1128 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
1129 if (!this._initted) {
1130 internalForce = true;
1135 this._totalTime = this._time = this._rawPrevTime = time;
1137 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
1139 } else if (!this._initted) {
1140 this._initted = true;
1143 if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
1144 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.
1147 if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
1148 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1151 if (this._time >= prevTime) {
1152 tween = this._first;
1154 next = tween._next; //record it here because the value could change after rendering...
1155 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1157 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
1158 if (!tween._reversed) {
1159 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1161 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1169 next = tween._prev; //record it here because the value could change after rendering...
1170 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1172 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
1173 if (!tween._reversed) {
1174 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1176 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1183 if (this._onUpdate) if (!suppressEvents) {
1184 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1187 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
1189 if (this._timeline.autoRemoveChildren) {
1190 this._enabled(false, false);
1192 this._active = false;
1194 if (!suppressEvents && this.vars[callback]) {
1195 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1200 p._hasPausedChild = function() {
1201 var tween = this._first;
1203 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
1206 tween = tween._next;
1211 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
1212 ignoreBeforeTime = ignoreBeforeTime || -9999999999;
1214 tween = this._first,
1217 if (tween._startTime < ignoreBeforeTime) {
1219 } else if (tween instanceof TweenLite) {
1220 if (tweens !== false) {
1224 if (timelines !== false) {
1227 if (nested !== false) {
1228 a = a.concat(tween.getChildren(true, tweens, timelines));
1232 tween = tween._next;
1237 p.getTweensOf = function(target, nested) {
1238 var disabled = this._gc,
1243 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.
1245 tweens = TweenLite.getTweensOf(target);
1248 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
1249 a[cnt++] = tweens[i];
1253 this._enabled(false, true);
1258 p._contains = function(tween) {
1259 var tl = tween.timeline;
1269 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
1270 ignoreBeforeTime = ignoreBeforeTime || 0;
1271 var tween = this._first,
1272 labels = this._labels,
1275 if (tween._startTime >= ignoreBeforeTime) {
1276 tween._startTime += amount;
1278 tween = tween._next;
1282 if (labels[p] >= ignoreBeforeTime) {
1283 labels[p] += amount;
1287 return this._uncache(true);
1290 p._kill = function(vars, target) {
1291 if (!vars && !target) {
1292 return this._enabled(false, false);
1294 var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
1298 if (tweens[i]._kill(vars, target)) {
1305 p.clear = function(labels) {
1306 var tweens = this.getChildren(false, true, true),
1308 this._time = this._totalTime = 0;
1310 tweens[i]._enabled(false, false);
1312 if (labels !== false) {
1315 return this._uncache(true);
1318 p.invalidate = function() {
1319 var tween = this._first;
1322 tween = tween._next;
1327 p._enabled = function(enabled, ignoreTimeline) {
1328 if (enabled === this._gc) {
1329 var tween = this._first;
1331 tween._enabled(enabled, true);
1332 tween = tween._next;
1335 return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
1338 p.duration = function(value) {
1339 if (!arguments.length) {
1341 this.totalDuration(); //just triggers recalculation
1343 return this._duration;
1345 if (this.duration() !== 0 && value !== 0) {
1346 this.timeScale(this._duration / value);
1351 p.totalDuration = function(value) {
1352 if (!arguments.length) {
1356 prevStart = 999999999999,
1359 prev = tween._prev; //record it here in case the tween changes position in the sequence...
1361 tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
1363 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
1364 this.add(tween, tween._startTime - tween._delay);
1366 prevStart = tween._startTime;
1368 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.
1369 max -= tween._startTime;
1370 if (this._timeline.smoothChildTiming) {
1371 this._startTime += tween._startTime / this._timeScale;
1373 this.shiftChildren(-tween._startTime, false, -9999999999);
1376 end = tween._startTime + (tween._totalDuration / tween._timeScale);
1382 this._duration = this._totalDuration = max;
1383 this._dirty = false;
1385 return this._totalDuration;
1387 if (this.totalDuration() !== 0) if (value !== 0) {
1388 this.timeScale(this._totalDuration / value);
1393 p.usesFrames = function() {
1394 var tl = this._timeline;
1395 while (tl._timeline) {
1398 return (tl === Animation._rootFramesTimeline);
1401 p.rawTime = function() {
1402 return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
1405 return TimelineLite;
1422 * ----------------------------------------------------------------
1424 * ----------------------------------------------------------------
1426 window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
1428 var TimelineMax = function(vars) {
1429 TimelineLite.call(this, vars);
1430 this._repeat = this.vars.repeat || 0;
1431 this._repeatDelay = this.vars.repeatDelay || 0;
1433 this._yoyo = (this.vars.yoyo === true);
1436 _tinyNum = 0.0000000001,
1438 _easeNone = new Ease(null, null, 1, 0),
1439 p = TimelineMax.prototype = new TimelineLite();
1441 p.constructor = TimelineMax;
1442 p.kill()._gc = false;
1443 TimelineMax.version = "1.12.1";
1445 p.invalidate = function() {
1446 this._yoyo = (this.vars.yoyo === true);
1447 this._repeat = this.vars.repeat || 0;
1448 this._repeatDelay = this.vars.repeatDelay || 0;
1449 this._uncache(true);
1450 return TimelineLite.prototype.invalidate.call(this);
1453 p.addCallback = function(callback, position, params, scope) {
1454 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
1457 p.removeCallback = function(callback, position) {
1459 if (position == null) {
1460 this._kill(null, callback);
1462 var a = this.getTweensOf(callback, false),
1464 time = this._parseTimeOrLabel(position);
1466 if (a[i]._startTime === time) {
1467 a[i]._enabled(false, false);
1475 p.tweenTo = function(position, vars) {
1477 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.
1482 copy.time = this._parseTimeOrLabel(position);
1483 duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
1484 t = new TweenLite(this, duration, copy);
1485 copy.onStart = function() {
1486 t.target.paused(true);
1487 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.
1488 t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
1490 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
1491 vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
1497 p.tweenFromTo = function(fromPosition, toPosition, vars) {
1499 fromPosition = this._parseTimeOrLabel(fromPosition);
1500 vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
1501 vars.immediateRender = (vars.immediateRender !== false);
1502 var t = this.tweenTo(toPosition, vars);
1503 return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
1506 p.render = function(time, suppressEvents, force) {
1508 this._enabled(true, false);
1510 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
1511 dur = this._duration,
1512 prevTime = this._time,
1513 prevTotalTime = this._totalTime,
1514 prevStart = this._startTime,
1515 prevTimeScale = this._timeScale,
1516 prevRawPrevTime = this._rawPrevTime,
1517 prevPaused = this._paused,
1518 prevCycle = this._cycle,
1519 tween, isComplete, next, callback, internalForce, cycleDuration;
1520 if (time >= totalDur) {
1521 if (!this._locked) {
1522 this._totalTime = totalDur;
1523 this._cycle = this._repeat;
1525 if (!this._reversed) if (!this._hasPausedChild()) {
1527 callback = "onComplete";
1528 if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
1529 internalForce = true;
1530 if (prevRawPrevTime > _tinyNum) {
1531 callback = "onReverseComplete";
1535 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.
1536 if (this._yoyo && (this._cycle & 1) !== 0) {
1537 this._time = time = 0;
1540 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.
1543 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
1544 if (!this._locked) {
1545 this._totalTime = this._cycle = 0;
1548 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)
1549 callback = "onReverseComplete";
1550 isComplete = this._reversed;
1553 this._active = false;
1554 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.
1555 internalForce = true;
1557 this._rawPrevTime = time;
1559 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.
1560 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
1561 if (!this._initted) {
1562 internalForce = true;
1567 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.
1568 internalForce = true;
1570 this._time = this._rawPrevTime = time;
1571 if (!this._locked) {
1572 this._totalTime = time;
1573 if (this._repeat !== 0) {
1574 cycleDuration = dur + this._repeatDelay;
1575 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!)
1576 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
1577 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
1579 this._time = this._totalTime - (this._cycle * cycleDuration);
1580 if (this._yoyo) if ((this._cycle & 1) !== 0) {
1581 this._time = dur - this._time;
1583 if (this._time > dur) {
1585 time = dur + 0.0001; //to avoid occasional floating point rounding error
1586 } else if (this._time < 0) {
1587 this._time = time = 0;
1595 if (this._cycle !== prevCycle) if (!this._locked) {
1597 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
1598 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
1599 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
1600 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
1601 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
1602 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
1604 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
1605 wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
1606 recTotalTime = this._totalTime,
1607 recCycle = this._cycle,
1608 recRawPrevTime = this._rawPrevTime,
1609 recTime = this._time;
1611 this._totalTime = prevCycle * dur;
1612 if (this._cycle < prevCycle) {
1613 backwards = !backwards;
1615 this._totalTime += dur;
1617 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.
1619 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
1620 this._cycle = prevCycle;
1621 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
1622 prevTime = (backwards) ? 0 : dur;
1623 this.render(prevTime, suppressEvents, (dur === 0));
1624 if (!suppressEvents) if (!this._gc) {
1625 if (this.vars.onRepeat) {
1626 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
1630 prevTime = (backwards) ? dur + 0.0001 : -0.0001;
1631 this.render(prevTime, true, false);
1633 this._locked = false;
1634 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
1637 this._time = recTime;
1638 this._totalTime = recTotalTime;
1639 this._cycle = recCycle;
1640 this._rawPrevTime = recRawPrevTime;
1643 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
1644 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.
1645 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1648 } else if (!this._initted) {
1649 this._initted = true;
1652 if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
1653 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.
1656 if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
1657 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1660 if (this._time >= prevTime) {
1661 tween = this._first;
1663 next = tween._next; //record it here because the value could change after rendering...
1664 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1666 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
1667 if (!tween._reversed) {
1668 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1670 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1679 next = tween._prev; //record it here because the value could change after rendering...
1680 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1682 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
1683 if (!tween._reversed) {
1684 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1686 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1693 if (this._onUpdate) if (!suppressEvents) {
1694 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1696 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
1698 if (this._timeline.autoRemoveChildren) {
1699 this._enabled(false, false);
1701 this._active = false;
1703 if (!suppressEvents && this.vars[callback]) {
1704 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1709 p.getActive = function(nested, tweens, timelines) {
1710 if (nested == null) {
1713 if (tweens == null) {
1716 if (timelines == null) {
1720 all = this.getChildren(nested, tweens, timelines),
1724 for (i = 0; i < l; i++) {
1726 if (tween.isActive()) {
1734 p.getLabelAfter = function(time) {
1735 if (!time) if (time !== 0) { //faster than isNan()
1738 var labels = this.getLabelsArray(),
1741 for (i = 0; i < l; i++) {
1742 if (labels[i].time > time) {
1743 return labels[i].name;
1749 p.getLabelBefore = function(time) {
1753 var labels = this.getLabelsArray(),
1756 if (labels[i].time < time) {
1757 return labels[i].name;
1763 p.getLabelsArray = function() {
1767 for (p in this._labels) {
1768 a[cnt++] = {time:this._labels[p], name:p};
1770 a.sort(function(a,b) {
1771 return a.time - b.time;
1777 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
1779 p.progress = function(value) {
1780 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);
1783 p.totalProgress = function(value) {
1784 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
1787 p.totalDuration = function(value) {
1788 if (!arguments.length) {
1790 TimelineLite.prototype.totalDuration.call(this); //just forces refresh
1791 //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
1792 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
1794 return this._totalDuration;
1796 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
1799 p.time = function(value, suppressEvents) {
1800 if (!arguments.length) {
1804 this.totalDuration();
1806 if (value > this._duration) {
1807 value = this._duration;
1809 if (this._yoyo && (this._cycle & 1) !== 0) {
1810 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
1811 } else if (this._repeat !== 0) {
1812 value += this._cycle * (this._duration + this._repeatDelay);
1814 return this.totalTime(value, suppressEvents);
1817 p.repeat = function(value) {
1818 if (!arguments.length) {
1819 return this._repeat;
1821 this._repeat = value;
1822 return this._uncache(true);
1825 p.repeatDelay = function(value) {
1826 if (!arguments.length) {
1827 return this._repeatDelay;
1829 this._repeatDelay = value;
1830 return this._uncache(true);
1833 p.yoyo = function(value) {
1834 if (!arguments.length) {
1841 p.currentLabel = function(value) {
1842 if (!arguments.length) {
1843 return this.getLabelBefore(this._time + 0.00000001);
1845 return this.seek(value, true);
1864 * ----------------------------------------------------------------
1866 * ----------------------------------------------------------------
1870 var _RAD2DEG = 180 / Math.PI,
1875 Segment = function(a, b, c, d) {
1884 _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
1885 cubicToQuadratic = function(a, b, c, d) {
1893 mabc = (mab + mbc) / 2,
1894 mbcd = (mbc + mcd) / 2,
1895 m8 = (mbcd - mabc) / 8;
1896 q1.b = mab + (a - mab) / 4;
1898 q1.c = q2.a = (q1.b + q2.b) / 2;
1899 q2.c = q3.a = (mabc + mbcd) / 2;
1901 q4.b = mcd + (d - mcd) / 4;
1902 q3.c = q4.a = (q3.b + q4.b) / 2;
1903 return [q1, q2, q3, q4];
1905 _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
1906 var l = a.length - 1,
1909 i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
1910 for (i = 0; i < l; i++) {
1919 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
1920 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
1921 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
1922 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
1924 m1 = p2 - (p2 - p1) * curviness * 0.5;
1925 m2 = p2 + (p3 - p2) * curviness * 0.5;
1926 mm = p2 - (m1 + m2) / 2;
1935 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.
1943 qb = cubicToQuadratic(p1, cp1, cp2, p2);
1944 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
1954 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.
1955 seg.da = seg.d - seg.a;
1956 seg.ca = seg.c - seg.a;
1957 seg.ba = cp1 - seg.a;
1959 qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
1960 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
1963 _parseAnchors = function(values, p, correlate, prepend) {
1965 l, i, p1, p2, p3, tmp;
1967 values = [prepend].concat(values);
1970 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
1971 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
1975 l = values.length - 2;
1977 a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
1980 for (i = 0; i < l; i++) {
1982 p2 = values[i+1][p];
1983 a[i] = new Segment(p1, 0, 0, p2);
1985 p3 = values[i+2][p];
1986 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
1987 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
1990 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
1993 bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
1996 first = prepend || values[0],
1997 i, p, a, j, r, l, seamless, last;
1998 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
1999 if (curviness == null) {
2002 for (p in values[0]) {
2005 //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)
2006 if (values.length > 1) {
2007 last = values[values.length - 1];
2012 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
2018 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
2020 values.unshift(prepend);
2022 values.push(values[1]);
2023 prepend = values[values.length - 3];
2026 _r1.length = _r2.length = _r3.length = 0;
2030 _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
2031 obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
2035 _r1[i] = Math.sqrt(_r1[i]);
2036 _r2[i] = Math.sqrt(_r2[i]);
2044 for (j = 0; j < l; j++) {
2045 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
2046 _r3[j] = (_r3[j] || 0) + r * r;
2052 _r3[i] = Math.sqrt(_r3[i]);
2056 j = quadratic ? 4 : 1;
2060 _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
2063 a.splice(a.length - j, j);
2068 _parseBezierData = function(values, type, prepend) {
2069 type = type || "soft";
2071 inc = (type === "cubic") ? 3 : 2,
2072 soft = (type === "soft"),
2074 a, b, c, d, cur, i, j, l, p, cnt, tmp;
2075 if (soft && prepend) {
2076 values = [prepend].concat(values);
2078 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
2079 for (p in values[0]) {
2088 for (j = 0; j < l; j++) {
2089 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);
2090 if (soft) if (j > 1) if (j < l - 1) {
2091 cur[cnt++] = (a + cur[cnt-2]) / 2;
2097 for (j = 0; j < l; j += inc) {
2101 d = (inc === 2) ? 0 : cur[j+3];
2102 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2108 _addCubicLengths = function(a, steps, resolution) {
2109 var inc = 1 / resolution,
2111 d, d1, s, da, ca, ba, p, i, inv, bez, index;
2119 for (i = 1; i <= resolution; i++) {
2122 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
2123 index = j * resolution + i - 1;
2124 steps[index] = (steps[index] || 0) + d * d;
2128 _parseLengthData = function(obj, resolution) {
2129 resolution = resolution >> 0 || 6;
2134 threshold = resolution - 1,
2136 curLS = [], //current length segments array
2139 _addCubicLengths(obj[p], a, resolution);
2142 for (i = 0; i < l; i++) {
2143 d += Math.sqrt(a[i]);
2144 index = i % resolution;
2146 if (index === threshold) {
2148 index = (i / resolution) >> 0;
2149 segments[index] = curLS;
2150 lengths[index] = total;
2155 return {length:total, lengths:lengths, segments:segments};
2160 BezierPlugin = window._gsDefine.plugin({
2167 //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
2168 init: function(target, vars, tween) {
2169 this._target = target;
2170 if (vars instanceof Array) {
2171 vars = {values:vars};
2176 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
2177 var values = vars.values || [],
2180 autoRotate = vars.autoRotate || tween.vars.orientToBezier,
2181 p, isFunc, i, j, prepend;
2183 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
2185 this._props.push(p);
2188 i = this._props.length;
2192 this._overwriteProps.push(p);
2193 isFunc = this._func[p] = (typeof(target[p]) === "function");
2194 first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
2195 if (!prepend) if (first[p] !== values[0][p]) {
2199 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);
2200 this._segCount = this._beziers[p].length;
2202 if (this._timeRes) {
2203 var ld = _parseLengthData(this._beziers, this._timeRes);
2204 this._length = ld.length;
2205 this._lengths = ld.lengths;
2206 this._segments = ld.segments;
2207 this._l1 = this._li = this._s1 = this._si = 0;
2208 this._l2 = this._lengths[0];
2209 this._curSeg = this._segments[0];
2210 this._s2 = this._curSeg[0];
2211 this._prec = 1 / this._curSeg.length;
2214 if ((autoRotate = this._autoRotate)) {
2215 this._initialRotations = [];
2216 if (!(autoRotate[0] instanceof Array)) {
2217 this._autoRotate = autoRotate = [autoRotate];
2219 i = autoRotate.length;
2221 for (j = 0; j < 3; j++) {
2222 p = autoRotate[i][j];
2223 this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
2225 p = autoRotate[i][2];
2226 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
2229 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.
2233 //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.)
2235 var segments = this._segCount,
2237 target = this._target,
2238 notStart = (v !== this._startRatio),
2239 curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
2240 if (!this._timeRes) {
2241 curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
2242 t = (v - (curIndex * (1 / segments))) * segments;
2244 lengths = this._lengths;
2245 curSeg = this._curSeg;
2248 //find the appropriate segment (if the currently cached one isn't correct)
2249 if (v > this._l2 && i < segments - 1) {
2251 while (i < l && (this._l2 = lengths[++i]) <= v) { }
2252 this._l1 = lengths[i-1];
2254 this._curSeg = curSeg = this._segments[i];
2255 this._s2 = curSeg[(this._s1 = this._si = 0)];
2256 } else if (v < this._l1 && i > 0) {
2257 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
2258 if (i === 0 && v < this._l1) {
2263 this._l2 = lengths[i];
2265 this._curSeg = curSeg = this._segments[i];
2266 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
2267 this._s2 = curSeg[this._si];
2270 //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
2273 if (v > this._s2 && i < curSeg.length - 1) {
2274 l = curSeg.length - 1;
2275 while (i < l && (this._s2 = curSeg[++i]) <= v) { }
2276 this._s1 = curSeg[i-1];
2278 } else if (v < this._s1 && i > 0) {
2279 while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
2280 if (i === 0 && v < this._s1) {
2285 this._s2 = curSeg[i];
2288 t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
2292 i = this._props.length;
2295 b = this._beziers[p][curIndex];
2296 val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
2297 if (this._round[p]) {
2298 val = Math.round(val);
2307 if (this._autoRotate) {
2308 var ar = this._autoRotate,
2309 b2, x1, y1, x2, y2, add, conv;
2313 add = ar[i][3] || 0;
2314 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
2315 b = this._beziers[ar[i][0]];
2316 b2 = this._beziers[ar[i][1]];
2318 if (b && b2) { //in case one of the properties got overwritten.
2322 x1 = b.a + (b.b - b.a) * t;
2323 x2 = b.b + (b.c - b.b) * t;
2324 x1 += (x2 - x1) * t;
2325 x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
2327 y1 = b2.a + (b2.b - b2.a) * t;
2328 y2 = b2.b + (b2.c - b2.b) * t;
2329 y1 += (y2 - y1) * t;
2330 y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
2332 val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
2344 p = BezierPlugin.prototype;
2347 BezierPlugin.bezierThrough = bezierThrough;
2348 BezierPlugin.cubicToQuadratic = cubicToQuadratic;
2349 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
2350 BezierPlugin.quadraticToCubic = function(a, b, c) {
2351 return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2354 BezierPlugin._cssRegister = function() {
2355 var CSSPlugin = window._gsDefine.globals.CSSPlugin;
2359 var _internals = CSSPlugin._internals,
2360 _parseToProxy = _internals._parseToProxy,
2361 _setPluginRatio = _internals._setPluginRatio,
2362 CSSPropTween = _internals.CSSPropTween;
2363 _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
2364 if (e instanceof Array) {
2367 plugin = new BezierPlugin();
2368 var values = e.values,
2369 l = values.length - 1,
2376 for (i = 0; i <= l; i++) {
2377 data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
2378 pluginValues[i] = data.end;
2381 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.
2383 v.values = pluginValues;
2384 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
2387 pt.setRatio = _setPluginRatio;
2388 if (v.autoRotate === 0) {
2389 v.autoRotate = true;
2391 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
2392 i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
2393 v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
2396 if (!cssp._transform) {
2397 cssp._enableTransforms(false);
2399 data.autoRotate = cssp._target._gsTransform;
2401 plugin._onInitTween(data.proxy, v, cssp._tween);
2406 p._roundProps = function(lookup, value) {
2407 var op = this._overwriteProps,
2410 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
2411 this._round[op[i]] = value;
2416 p._kill = function(lookup) {
2417 var a = this._props,
2419 for (p in this._beziers) {
2421 delete this._beziers[p];
2422 delete this._func[p];
2431 return this._super._kill.call(this, lookup);
2450 * ----------------------------------------------------------------
2452 * ----------------------------------------------------------------
2454 window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
2456 /** @constructor **/
2457 var CSSPlugin = function() {
2458 TweenPlugin.call(this, "css");
2459 this._overwriteProps.length = 0;
2460 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
2462 _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.
2463 _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
2464 _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
2465 _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.
2467 p = CSSPlugin.prototype = new TweenPlugin("css");
2469 p.constructor = CSSPlugin;
2470 CSSPlugin.version = "1.12.1";
2472 CSSPlugin.defaultTransformPerspective = 0;
2473 CSSPlugin.defaultSkewType = "compensated";
2474 p = "px"; //we'll reuse the "p" variable to keep file size down
2475 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
2478 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
2479 _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
2480 _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)"
2481 _NaNExp = /[^\d\-\.]/g,
2482 _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
2483 _opacityExp = /opacity *= *([^)]*)/i,
2484 _opacityValExp = /opacity:([^;]*)/i,
2485 _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
2486 _rgbhslExp = /^(rgb|hsl)/,
2487 _capsExp = /([A-Z])/g,
2488 _camelExp = /-([a-z])/gi,
2489 _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)
2490 _camelFunc = function(s, g) { return g.toUpperCase(); },
2491 _horizExp = /(?:Left|Right|Width)/i,
2492 _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
2493 _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
2494 _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
2495 _DEG2RAD = Math.PI / 180,
2496 _RAD2DEG = 180 / Math.PI,
2499 _tempDiv = _doc.createElement("div"),
2500 _tempImg = _doc.createElement("img"),
2501 _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
2502 _agent = navigator.userAgent,
2504 _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).
2507 _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
2508 _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!)
2510 _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
2511 var i = _agent.indexOf("Android"),
2512 d = _doc.createElement("div"), a;
2514 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
2515 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
2516 _isFirefox = (_agent.indexOf("Firefox") !== -1);
2518 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
2519 _ieVers = parseFloat( RegExp.$1 );
2522 d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>";
2523 a = d.getElementsByTagName("a")[0];
2524 return a ? /^0.55/.test(a.style.opacity) : false;
2526 _getIEOpacity = function(v) {
2527 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
2529 _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
2530 if (window.console) {
2534 _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
2535 _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
2537 // @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)
2538 _checkPropPrefix = function(p, e) {
2542 if (s[p] !== undefined) {
2545 p = p.charAt(0).toUpperCase() + p.substr(1);
2546 a = ["O","Moz","ms","Ms","Webkit"];
2548 while (--i > -1 && s[a[i]+p] === undefined) { }
2550 _prefix = (i === 3) ? "ms" : a[i];
2551 _prefixCSS = "-" + _prefix.toLowerCase() + "-";
2557 _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
2560 * @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:
2561 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
2563 * @param {!Object} t Target element whose style property you want to query
2564 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
2565 * @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.
2566 * @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.
2567 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
2568 * @return {?string} The current property value
2570 _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
2572 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.
2573 return _getIEOpacity(t);
2575 if (!calc && t.style[p]) {
2577 } else if ((cs = cs || _getComputedStyle(t))) {
2578 rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
2579 } else if (t.currentStyle) {
2580 rv = t.currentStyle[p];
2582 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
2586 * @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.
2587 * @param {!Object} t Target element
2588 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
2589 * @param {!number} v Value
2590 * @param {string=} sfx Suffix (like "px" or "%" or "em")
2591 * @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.
2592 * @return {number} value in pixels
2594 _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
2595 if (sfx === "px" || !sfx) { return v; }
2596 if (sfx === "auto" || !v) { return 0; }
2597 var horiz = _horizExp.test(p),
2599 style = _tempDiv.style,
2605 if (sfx === "%" && p.indexOf("border") !== -1) {
2606 pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
2608 style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
2609 if (sfx === "%" || !node.appendChild) {
2610 node = t.parentNode || _doc.body;
2611 cache = node._gsCache;
2612 time = TweenLite.ticker.frame;
2613 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)
2614 return cache.width * v / 100;
2616 style[(horiz ? "width" : "height")] = v + sfx;
2618 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
2620 node.appendChild(_tempDiv);
2621 pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
2622 node.removeChild(_tempDiv);
2623 if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
2624 cache = node._gsCache = node._gsCache || {};
2626 cache.width = pix / v * 100;
2628 if (pix === 0 && !recurse) {
2629 pix = _convertToPixels(t, p, v, sfx, true);
2632 return neg ? -pix : pix;
2634 _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
2635 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
2636 var dim = ((p === "left") ? "Left" : "Top"),
2637 v = _getStyle(t, "margin" + dim, cs);
2638 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
2641 // @private returns at object containing ALL of the style properties in camelCase and their associated values.
2642 _getAllStyles = function(t, cs) {
2645 if ((cs = cs || _getComputedStyle(t, null))) {
2646 if ((i = cs.length)) {
2648 s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
2650 } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
2655 } else if ((cs = t.currentStyle || t.style)) {
2657 if (typeof(i) === "string" && s[i] === undefined) {
2658 s[i.replace(_camelExp, _camelFunc)] = cs[i];
2662 if (!_supportsOpacity) {
2663 s.opacity = _getIEOpacity(t);
2665 tr = _getTransform(t, cs, false);
2666 s.rotation = tr.rotation;
2668 s.scaleX = tr.scaleX;
2669 s.scaleY = tr.scaleY;
2674 s.rotationX = tr.rotationX;
2675 s.rotationY = tr.rotationY;
2676 s.scaleZ = tr.scaleZ;
2684 // @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.
2685 _cssDif = function(t, s1, s2, vars, forceLookup) {
2690 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") {
2691 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.
2692 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.
2693 mpt = new MiniPropTween(style, p, style[p], mpt);
2698 for (p in vars) { //copy properties (except className)
2699 if (p !== "className") {
2704 return {difs:difs, firstMPT:mpt};
2706 _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
2707 _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
2710 * @private Gets the width or height of an element
2711 * @param {!Object} t Target element
2712 * @param {!string} p Property name ("width" or "height")
2713 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
2714 * @return {number} Dimension (in pixels)
2716 _getDimension = function(t, p, cs) {
2717 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
2720 cs = cs || _getComputedStyle(t, null);
2722 v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
2723 v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
2728 // @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)
2729 _parsePosition = function(v, recObj) {
2730 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
2733 var a = v.split(" "),
2734 x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
2735 y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
2738 } else if (y === "center") {
2741 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.
2745 recObj.oxp = (x.indexOf("%") !== -1);
2746 recObj.oyp = (y.indexOf("%") !== -1);
2747 recObj.oxr = (x.charAt(1) === "=");
2748 recObj.oyr = (y.charAt(1) === "=");
2749 recObj.ox = parseFloat(x.replace(_NaNExp, ""));
2750 recObj.oy = parseFloat(y.replace(_NaNExp, ""));
2752 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
2756 * @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!)
2757 * @param {(number|string)} e End value which is typically a string, but could be a number
2758 * @param {(number|string)} b Beginning value which is typically a string but could be a number
2759 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
2761 _parseChange = function(e, b) {
2762 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
2766 * @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.
2767 * @param {Object} v Value to be parsed
2768 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
2769 * @return {number} Parsed value
2771 _parseVal = function(v, d) {
2772 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
2776 * @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.
2777 * @param {Object} v Value to be parsed
2778 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
2779 * @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"
2780 * @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.
2781 * @return {number} parsed angle in radians
2783 _parseAngle = function(v, d, p, directionalEnd) {
2785 cap, split, dif, result;
2788 } else if (typeof(v) === "number") {
2792 split = v.split("_");
2793 dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
2795 if (directionalEnd) {
2796 directionalEnd[p] = d + dif;
2798 if (v.indexOf("short") !== -1) {
2800 if (dif !== dif % (cap / 2)) {
2801 dif = (dif < 0) ? dif + cap : dif - cap;
2804 if (v.indexOf("_cw") !== -1 && dif < 0) {
2805 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
2806 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
2807 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
2812 if (result < min && result > -min) {
2818 _colorLookup = {aqua:[0,255,255],
2820 silver:[192,192,192],
2826 white:[255,255,255],
2827 fuchsia:[255,0,255],
2837 transparent:[255,255,255,0]},
2839 _hue = function(h, m1, m2) {
2840 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
2841 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;
2845 * @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)
2846 * @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.
2847 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
2849 _parseColor = function(v) {
2850 var c1, c2, c3, h, s, l;
2851 if (!v || v === "") {
2852 return _colorLookup.black;
2854 if (typeof(v) === "number") {
2855 return [v >> 16, (v >> 8) & 255, v & 255];
2857 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.
2858 v = v.substr(0, v.length - 1);
2860 if (_colorLookup[v]) {
2861 return _colorLookup[v];
2863 if (v.charAt(0) === "#") {
2864 if (v.length === 4) { //for shorthand like #9F0
2868 v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
2870 v = parseInt(v.substr(1), 16);
2871 return [v >> 16, (v >> 8) & 255, v & 255];
2873 if (v.substr(0, 3) === "hsl") {
2874 v = v.match(_numExp);
2875 h = (Number(v[0]) % 360) / 360;
2876 s = Number(v[1]) / 100;
2877 l = Number(v[2]) / 100;
2878 c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
2881 v[3] = Number(v[3]);
2883 v[0] = _hue(h + 1 / 3, c1, c2);
2884 v[1] = _hue(h, c1, c2);
2885 v[2] = _hue(h - 1 / 3, c1, c2);
2888 v = v.match(_numExp) || _colorLookup.transparent;
2889 v[0] = Number(v[0]);
2890 v[1] = Number(v[1]);
2891 v[2] = Number(v[2]);
2893 v[3] = Number(v[3]);
2897 _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.
2899 for (p in _colorLookup) {
2900 _colorExp += "|" + p + "\\b";
2902 _colorExp = new RegExp(_colorExp+")", "gi");
2905 * @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.
2906 * @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.
2907 * @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.
2908 * @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.
2909 * @return {Function} formatter function
2911 var _getFormatter = function(dflt, clr, collapsible, multi) {
2913 return function(v) {return v;};
2915 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
2916 dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
2917 pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
2918 sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
2919 delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
2920 numVals = dVals.length,
2921 dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
2924 return function(v) {return v;};
2927 formatter = function(v) {
2928 var color, vals, i, a;
2929 if (typeof(v) === "number") {
2931 } else if (multi && _commasOutsideParenExp.test(v)) {
2932 a = v.replace(_commasOutsideParenExp, "|").split("|");
2933 for (i = 0; i < a.length; i++) {
2934 a[i] = formatter(a[i]);
2938 color = (v.match(_colorExp) || [dColor])[0];
2939 vals = v.split(color).join("").match(_valuesExp) || [];
2941 if (numVals > i--) {
2942 while (++i < numVals) {
2943 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
2946 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
2951 formatter = function(v) {
2953 if (typeof(v) === "number") {
2955 } else if (multi && _commasOutsideParenExp.test(v)) {
2956 a = v.replace(_commasOutsideParenExp, "|").split("|");
2957 for (i = 0; i < a.length; i++) {
2958 a[i] = formatter(a[i]);
2962 vals = v.match(_valuesExp) || [];
2964 if (numVals > i--) {
2965 while (++i < numVals) {
2966 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
2969 return pfx + vals.join(delim) + sfx;
2975 * @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.
2976 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
2977 * @return {Function} a formatter function
2979 _getEdgeParser = function(props) {
2980 props = props.split(",");
2981 return function(t, e, p, cssp, pt, plugin, vars) {
2982 var a = (e + "").split(" "),
2985 for (i = 0; i < 4; i++) {
2986 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
2988 return cssp.parse(t, vars, pt, plugin);
2992 // @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.
2993 _setPluginRatio = _internals._setPluginRatio = function(v) {
2994 this.plugin.setRatio(v);
3003 val = Math.round(val);
3004 } else if (val < min && val > -min) {
3011 d.autoRotate.rotation = proxy.rotation;
3013 //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.
3019 pt.e = pt.s + pt.xs0;
3020 } else if (pt.type === 1) {
3021 str = pt.xs0 + pt.s + pt.xs1;
3022 for (i = 1; i < pt.l; i++) {
3023 str += pt["xn"+i] + pt["xs"+(i+1)];
3033 * @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.
3034 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
3035 * @param {!string} p property name
3036 * @param {(number|string|object)} v value
3037 * @param {MiniPropTween=} next next MiniPropTween in the linked list
3038 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
3040 MiniPropTween = function(t, p, v, next, r) {
3052 * @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.
3053 * This method returns an object that has the following properties:
3054 * - 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
3055 * - 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
3056 * - firstMPT: the first MiniPropTween in the linked list
3057 * - 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.
3058 * @param {!Object} t target object to be tweened
3059 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
3060 * @param {!CSSPlugin} cssp The CSSPlugin instance
3061 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
3062 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
3063 * @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.
3064 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
3066 _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
3070 transform = cssp._transform,
3071 oldForce = _forcePT,
3072 i, p, xp, mpt, firstPT;
3073 cssp._transform = null;
3075 pt = firstPT = cssp.parse(t, vars, pt, plugin);
3076 _forcePT = oldForce;
3077 //break off from the linked list so the new ones are isolated.
3079 cssp._transform = transform;
3083 bpt._prev._next = null;
3087 while (pt && pt !== bpt) {
3090 end[p] = pt.s + pt.c;
3093 mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
3096 if (pt.type === 1) {
3100 p = pt.p + "_" + xp;
3101 end[p] = pt.data[xp];
3104 mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
3111 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
3117 * @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.
3118 * CSSPropTweens have the following optional properties as well (not defined through the constructor):
3119 * - 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.
3120 * - 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)
3121 * - 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.
3122 * - 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.
3123 * - 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.
3124 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
3125 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
3126 * @param {number} s Starting numeric value
3127 * @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.
3128 * @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.
3129 * @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.
3130 * @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"
3131 * @param {boolean=} r If true, the value(s) should be rounded
3132 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
3133 * @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.
3134 * @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.
3136 CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
3137 this.t = t; //target
3138 this.p = p; //property
3139 this.s = s; //starting value
3140 this.c = c; //change value
3141 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)
3142 if (!(t instanceof CSSPropTween)) {
3143 _overwriteProps.push(this.n);
3145 this.r = r; //round (boolean)
3146 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
3149 _hasPriority = true;
3151 this.b = (b === undefined) ? s : b;
3152 this.e = (e === undefined) ? s + c : e;
3160 * 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:
3161 * 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);
3162 * 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().
3163 * 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.
3165 * @param {!Object} t Target whose property will be tweened
3166 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
3167 * @param {string} b Beginning value
3168 * @param {string} e Ending value
3169 * @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)
3170 * @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
3171 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
3172 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
3173 * @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}
3174 * @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.
3175 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
3177 _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
3178 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
3179 b = b || dflt || "";
3180 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
3181 e += ""; //ensures it's a string
3182 var ba = b.split(", ").join(",").split(" "), //beginning array
3183 ea = e.split(", ").join(",").split(" "), //ending array
3185 autoRound = (_autoRound !== false),
3186 i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
3187 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
3188 ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3189 ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3192 if (l !== ea.length) {
3193 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3194 ba = (dflt || "").split(" ");
3198 pt.setRatio = setRatio;
3199 for (i = 0; i < l; i++) {
3202 bn = parseFloat(bv);
3204 //if the value begins with a number (most common). It's fine if it has a suffix like px
3205 if (bn || bn === 0) {
3206 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
3208 //if the value is a color
3209 } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
3210 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
3211 bv = _parseColor(bv);
3212 ev = _parseColor(ev);
3213 rgba = (bv.length + ev.length > 6);
3214 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
3215 pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
3216 pt.e = pt.e.split(ea[i]).join("transparent");
3218 if (!_supportsOpacity) { //old versions of IE don't support rgba().
3221 pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
3222 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
3223 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
3225 bv = (bv.length < 4) ? 1 : bv[3];
3226 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
3231 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
3233 //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
3235 pt["xs" + pt.l] += pt.l ? " " + bv : bv;
3237 //loop through all the numbers that are found and construct the extra values on the pt.
3239 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
3240 if (!enums || enums.length !== bnums.length) {
3241 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3245 for (xi = 0; xi < bnums.length; xi++) {
3247 temp = bv.indexOf(cv, ni);
3248 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
3249 ni = temp + cv.length;
3251 pt["xs" + pt.l] += bv.substr(ni);
3255 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
3256 if (e.indexOf("=") !== -1) if (pt.data) {
3257 str = pt.xs0 + pt.data.s;
3258 for (i = 1; i < pt.l; i++) {
3259 str += pt["xs" + i] + pt.data["xn" + i];
3261 pt.e = str + pt["xs" + i];
3267 return pt.xfirst || pt;
3272 p = CSSPropTween.prototype;
3273 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
3279 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
3283 * 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:
3284 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
3285 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
3286 * @param {string=} pfx Prefix (if any)
3287 * @param {!number} s Starting value
3288 * @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.
3289 * @param {string=} sfx Suffix (if any)
3290 * @param {boolean=} r Round (if true).
3291 * @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.
3292 * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
3294 p.appendXtra = function(pfx, s, c, sfx, r, pad) {
3297 pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
3298 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!
3299 pt["xs" + l] += s + (sfx || "");
3303 pt.type = pt.setRatio ? 2 : 1;
3304 pt["xs" + pt.l] = sfx || "";
3306 pt.data["xn" + l] = s + c;
3307 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
3310 pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
3311 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.
3315 pt.data = {s:s + c};
3324 * @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.
3325 * @param {!string} p Property name (like "boxShadow" or "throwProps")
3326 * @param {Object=} options An object containing any of the following configuration options:
3327 * - defaultValue: the default value
3328 * - 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)
3329 * - 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.)
3330 * - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
3331 * - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
3332 * - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
3333 * - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
3334 * - 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.
3335 * - 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).
3337 var SpecialProp = function(p, options) {
3338 options = options || {};
3339 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
3340 _specialProps[p] = _specialProps[this.p] = this;
3341 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
3342 if (options.parser) {
3343 this.parse = options.parser;
3345 this.clrs = options.color;
3346 this.multi = options.multi;
3347 this.keyword = options.keyword;
3348 this.dflt = options.defaultValue;
3349 this.pr = options.priority || 0;
3352 //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.
3353 _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
3354 if (typeof(options) !== "object") {
3355 options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
3357 var a = p.split(","),
3358 d = options.defaultValue,
3360 defaults = defaults || [d];
3361 for (i = 0; i < a.length; i++) {
3362 options.prefix = (i === 0 && options.prefix);
3363 options.defaultValue = defaults[i] || d;
3364 temp = new SpecialProp(a[i], options);
3368 //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.
3369 _registerPluginProp = function(p) {
3370 if (!_specialProps[p]) {
3371 var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
3372 _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
3373 var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
3375 _log("Error: " + pluginName + " js file not loaded.");
3378 pluginClass._cssRegister();
3379 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
3385 p = SpecialProp.prototype;
3388 * 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)
3389 * @param {!Object} t target element
3390 * @param {(string|number|object)} b beginning value
3391 * @param {(string|number|object)} e ending (destination) value
3392 * @param {CSSPropTween=} pt next CSSPropTween in the linked list
3393 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
3394 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
3395 * @return {CSSPropTween=} First CSSPropTween in the linked list
3397 p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
3398 var kwd = this.keyword,
3399 i, ba, ea, l, bi, ei;
3400 //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)
3401 if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
3402 ba = b.replace(_commasOutsideParenExp, "|").split("|");
3403 ea = e.replace(_commasOutsideParenExp, "|").split("|");
3409 l = (ea.length > ba.length) ? ea.length : ba.length;
3410 for (i = 0; i < l; i++) {
3411 b = ba[i] = ba[i] || this.dflt;
3412 e = ea[i] = ea[i] || this.dflt;
3414 bi = b.indexOf(kwd);
3415 ei = e.indexOf(kwd);
3417 e = (ei === -1) ? ea : ba;
3425 return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
3429 * 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:
3430 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
3431 * 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).
3432 * @param {!Object} t Target object whose property is being tweened
3433 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
3434 * @param {!string} p Property name
3435 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
3436 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
3437 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
3438 * @param {Object=} vars Original vars object that contains the data for parsing.
3439 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
3441 p.parse = function(t, e, p, cssp, pt, plugin, vars) {
3442 return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
3446 * 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:
3447 * 1) Target object whose property should be tweened (typically a DOM element)
3448 * 2) The end/destination value (could be a string, number, object, or whatever you want)
3449 * 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)
3451 * 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:
3453 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
3454 * var start = target.style.width;
3455 * return function(ratio) {
3456 * target.style.width = (start + value * ratio) + "px";
3457 * console.log("set width to " + target.style.width);
3461 * Then, when I do this tween, it will trigger my special property:
3463 * TweenLite.to(element, 1, {css:{myCustomProp:100}});
3465 * In the example, of course, we're just changing the width, but you can do anything you want.
3467 * @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}})
3468 * @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.
3469 * @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.
3471 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
3472 _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
3473 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
3475 rv.setRatio = onInitTween(t, e, cssp._tween, p);
3477 }, priority:priority});
3487 //transform-related methods and properties
3488 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
3489 _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
3490 _transformPropCSS = _prefixCSS + "transform",
3491 _transformOriginProp = _checkPropPrefix("transformOrigin"),
3492 _supports3D = (_checkPropPrefix("perspective") !== null),
3493 Transform = _internals.Transform = function() {
3498 * 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.
3499 * @param {!Object} t target element
3500 * @param {Object=} cs computed style object (optional)
3501 * @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...}
3502 * @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)
3503 * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
3505 _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
3506 if (t._gsTransform && rec && !parse) {
3507 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.
3509 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
3510 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.
3514 minPI = minAngle * _DEG2RAD,
3515 zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0,
3516 s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
3517 if (_transformProp) {
3518 s = _getStyle(t, _transformPropCSS, cs, true);
3519 } else if (t.currentStyle) {
3520 //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.
3521 s = t.currentStyle.filter.match(_ieGetMatrixExp);
3522 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(",") : "";
3524 //split the matrix values out into an array (m for matrix)
3525 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
3529 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).
3531 if (m.length === 16) {
3533 //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)
3534 var a13 = m[8], a23 = m[9], a33 = m[10],
3535 a14 = m[12], a24 = m[13], a34 = m[14];
3537 //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
3540 a14 = a13*a34-m[12];
3541 a24 = a23*a34-m[13];
3542 a34 = a33*a34+tm.zOrigin-m[14];
3545 //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.
3546 if (!rec || parse || tm.rotationX == null) {
3547 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
3548 a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
3550 angle = Math.atan2(a32, a33),
3551 xFlip = (angle < -minPI || angle > minPI),
3552 t1, t2, t3, cos, sin, yFlip, zFlip;
3553 tm.rotationX = angle * _RAD2DEG;
3556 cos = Math.cos(-angle);
3557 sin = Math.sin(-angle);
3558 t1 = a12*cos+a13*sin;
3559 t2 = a22*cos+a23*sin;
3560 t3 = a32*cos+a33*sin;
3561 a13 = a12*-sin+a13*cos;
3562 a23 = a22*-sin+a23*cos;
3563 a33 = a32*-sin+a33*cos;
3564 a43 = a42*-sin+a43*cos;
3570 angle = Math.atan2(a13, a11);
3571 tm.rotationY = angle * _RAD2DEG;
3573 yFlip = (angle < -minPI || angle > minPI);
3574 cos = Math.cos(-angle);
3575 sin = Math.sin(-angle);
3576 t1 = a11*cos-a13*sin;
3577 t2 = a21*cos-a23*sin;
3578 t3 = a31*cos-a33*sin;
3579 a23 = a21*sin+a23*cos;
3580 a33 = a31*sin+a33*cos;
3581 a43 = a41*sin+a43*cos;
3587 angle = Math.atan2(a21, a22);
3588 tm.rotation = angle * _RAD2DEG;
3590 zFlip = (angle < -minPI || angle > minPI);
3591 cos = Math.cos(-angle);
3592 sin = Math.sin(-angle);
3593 a11 = a11*cos+a12*sin;
3594 t2 = a21*cos+a22*sin;
3595 a22 = a21*-sin+a22*cos;
3596 a32 = a31*-sin+a32*cos;
3600 if (zFlip && xFlip) {
3601 tm.rotation = tm.rotationX = 0;
3602 } else if (zFlip && yFlip) {
3603 tm.rotation = tm.rotationY = 0;
3604 } else if (yFlip && xFlip) {
3605 tm.rotationY = tm.rotationX = 0;
3608 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
3609 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
3610 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
3612 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
3618 } 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.
3619 var k = (m.length >= 6),
3626 scaleX = Math.sqrt(a * a + b * b);
3627 scaleY = Math.sqrt(d * d + c * c);
3628 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).
3629 skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
3630 difX = scaleX - Math.abs(tm.scaleX || 0);
3631 difY = scaleY - Math.abs(tm.scaleY || 0);
3632 if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
3635 skewX += (rotation <= 0) ? 180 : -180;
3636 rotation += (rotation <= 0) ? 180 : -180;
3639 skewX += (skewX <= 0) ? 180 : -180;
3642 difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
3643 difS = (skewX - tm.skewX) % 180;
3644 //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.
3645 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)) {
3648 tm.rotation = rotation;
3652 tm.rotationX = tm.rotationY = tm.z = 0;
3653 tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
3657 tm.zOrigin = zOrigin;
3659 //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.
3661 if (tm[i] < min) if (tm[i] > -min) {
3665 //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);
3667 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)
3672 //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
3673 _setIETransformRatio = function(v) {
3674 var t = this.data, //refers to the element's _gsTransform object
3675 ang = -t.rotation * _DEG2RAD,
3676 skew = ang + t.skewX * _DEG2RAD,
3678 a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
3679 b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
3680 c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
3681 d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
3682 style = this.t.style,
3683 cs = this.t.currentStyle,
3688 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)
3691 filters = cs.filter;
3692 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
3693 var w = this.t.offsetWidth,
3694 h = this.t.offsetHeight,
3695 clip = (cs.position !== "absolute"),
3696 m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
3701 //if transformOrigin is being used, adjust the offset x and y
3703 dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
3704 dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
3705 ox += dx - (dx * a + dy * b);
3706 oy += dy - (dx * c + dy * d);
3710 m += ", sizingMethod='auto expand')";
3714 //translate to ensure that transformations occur around the correct origin (default is center).
3715 m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
3717 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
3718 style.filter = filters.replace(_ieSetMatrixExp, m);
3720 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.
3723 //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.
3724 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) {
3725 style.removeAttribute("filter");
3728 //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).
3730 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
3732 dx = t.ieOffsetX || 0;
3733 dy = t.ieOffsetY || 0;
3734 t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
3735 t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
3736 for (i = 0; i < 4; i++) {
3739 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
3740 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
3741 if (val !== t[prop]) {
3742 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.
3744 dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
3746 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
3751 _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
3752 var t = this.data, //refers to the element's _gsTransform object
3753 style = this.t.style,
3754 angle = t.rotation * _DEG2RAD,
3758 perspective = t.perspective,
3759 a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
3760 zOrigin, rnd, cos, sin, t1, t2, t3, t4;
3761 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
3762 _set2DTransformRatio.call(this, v);
3767 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.
3770 if (sy < n && sy > -n) {
3773 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).
3777 if (angle || t.skewX) {
3778 cos = Math.cos(angle);
3779 sin = Math.sin(angle);
3783 angle -= t.skewX * _DEG2RAD;
3784 cos = Math.cos(angle);
3785 sin = Math.sin(angle);
3786 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
3787 t1 = Math.tan(t.skewX * _DEG2RAD);
3788 t1 = Math.sqrt(1 + t1 * t1);
3796 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
3797 style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
3804 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
3805 a43 = (perspective) ? -1 / perspective : 0;
3806 zOrigin = t.zOrigin;
3808 angle = t.rotationY * _DEG2RAD;
3810 cos = Math.cos(angle);
3811 sin = Math.sin(angle);
3821 angle = t.rotationX * _DEG2RAD;
3823 cos = Math.cos(angle);
3824 sin = Math.sin(angle);
3825 t1 = a12*cos+a13*sin;
3826 t2 = a22*cos+a23*sin;
3827 t3 = a32*cos+a33*sin;
3828 t4 = a42*cos+a43*sin;
3829 a13 = a12*-sin+a13*cos;
3830 a23 = a22*-sin+a23*cos;
3831 a33 = a32*-sin+a33*cos;
3832 a43 = a42*-sin+a43*cos;
3860 a34 = a33*a34+zOrigin;
3862 //we round the x, y, and z slightly differently to allow even larger values.
3863 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
3864 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
3865 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
3866 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(",") + ")";
3869 _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
3870 var t = this.data, //refers to the element's _gsTransform object
3873 ang, skew, rnd, sx, sy;
3874 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.
3875 this.setRatio = _set3DTransformRatio;
3876 _set3DTransformRatio.call(this, v);
3879 if (!t.rotation && !t.skewX) {
3880 style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
3882 ang = t.rotation * _DEG2RAD;
3883 skew = ang - t.skewX * _DEG2RAD;
3885 sx = t.scaleX * rnd;
3886 sy = t.scaleY * rnd;
3887 //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.
3888 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 + ")";
3892 _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) {
3893 if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
3894 var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
3897 i = _transformProps.length,
3900 m2, skewY, copy, orig, has3D, hasChange, dr;
3901 if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
3902 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.
3903 copy[_transformProp] = v.transform;
3904 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
3905 copy.position = "absolute";
3906 _doc.body.appendChild(_tempDiv);
3907 m2 = _getTransform(_tempDiv, null, false);
3908 _doc.body.removeChild(_tempDiv);
3909 } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
3910 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
3911 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
3912 scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
3913 x:_parseVal(v.x, m1.x),
3914 y:_parseVal(v.y, m1.y),
3915 z:_parseVal(v.z, m1.z),
3916 perspective:_parseVal(v.transformPerspective, m1.perspective)};
3917 dr = v.directionalRotation;
3919 if (typeof(dr) === "object") {
3927 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);
3929 m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
3930 m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
3932 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
3934 //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.
3935 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
3936 if ((skewY = m2.skewY - m1.skewY)) {
3938 m2.rotation += skewY;
3942 if (_supports3D && v.force3D != null) {
3943 m1.force3D = v.force3D;
3947 m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
3949 has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
3950 if (!has3D && v.scale != null) {
3951 m2.scaleZ = 1; //no need to tween scaleZ.
3955 p = _transformProps[i];
3956 orig = m2[p] - m1[p];
3957 if (orig > min || orig < -min || _forcePT[p] != null) {
3959 pt = new CSSPropTween(m1, p, m1[p], orig, pt);
3960 if (p in endRotations) {
3961 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
3963 pt.xs0 = 0; //ensures the value stays numeric in setRatio()
3965 cssp._overwriteProps.push(pt.n);
3969 orig = v.transformOrigin;
3970 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).
3971 if (_transformProp) {
3973 p = _transformOriginProp;
3974 orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
3975 pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
3980 orig = orig.split(" ");
3981 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.
3982 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)!
3983 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)
3985 pt.xs0 = pt.e = m1.zOrigin;
3987 pt.xs0 = pt.e = orig;
3990 //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).
3992 _parsePosition(orig + "", m1);
3997 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
4002 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
4004 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
4006 var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
4008 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
4009 w = parseFloat(t.offsetWidth);
4010 h = parseFloat(t.offsetHeight);
4012 for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
4013 if (this.p.indexOf("border")) { //older browsers used a prefix
4014 props[i] = _checkPropPrefix(props[i]);
4016 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
4017 if (bs.indexOf(" ") !== -1) {
4018 bs2 = bs.split(" ");
4023 bn = parseFloat(bs);
4024 bsfx = bs.substr((bn + "").length);
4025 rel = (es.charAt(1) === "=");
4027 en = parseInt(es.charAt(0)+"1", 10);
4029 en *= parseFloat(es);
4030 esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
4032 en = parseFloat(es);
4033 esfx = es.substr((en + "").length);
4036 esfx = _suffixMap[p] || bsfx;
4038 if (esfx !== bsfx) {
4039 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.
4040 vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
4042 bs = (hn / w * 100) + "%";
4043 bs2 = (vn / h * 100) + "%";
4044 } else if (esfx === "em") {
4045 em = _convertToPixels(t, "borderLeft", 1, "em");
4046 bs = (hn / em) + "em";
4047 bs2 = (vn / em) + "em";
4053 es = (parseFloat(bs) + en) + esfx;
4054 es2 = (parseFloat(bs2) + en) + esfx;
4057 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
4060 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
4061 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
4062 var bp = "background-position",
4063 cs = (_cs || _getComputedStyle(t, null)),
4064 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
4065 es = this.format(e),
4066 ba, ea, i, pct, overlap, src;
4067 if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
4068 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
4069 if (src && src !== "none") {
4072 _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
4076 pct = (bs.indexOf("%") !== -1);
4077 if (pct !== (ea[i].indexOf("%") !== -1)) {
4078 overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
4079 ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
4085 return this.parseComplex(t.style, bs, es, pt, plugin);
4086 }, formatter:_parsePosition});
4087 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
4088 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
4089 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
4090 _registerComplexSpecialProp("transformStyle", {prefix:true});
4091 _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
4092 _registerComplexSpecialProp("userSelect", {prefix:true});
4093 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
4094 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
4095 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
4097 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.
4098 cs = t.currentStyle;
4099 delim = _ieVers < 8 ? " " : ",";
4100 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
4101 e = this.format(e).split(",").join(delim);
4103 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
4106 return this.parseComplex(t.style, b, e, pt, plugin);
4108 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
4109 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
4110 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
4111 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);
4112 }, color:true, formatter:function(v) {
4113 var a = v.split(" ");
4114 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
4116 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
4117 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
4119 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
4120 return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
4124 var _setIEOpacityRatio = function(v) {
4125 var t = this.t, //refers to the element's style property
4126 filters = t.filter || _getStyle(this.data, "filter"),
4127 val = (this.s + this.c * v) | 0,
4129 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.
4130 if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
4131 t.removeAttribute("filter");
4132 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.
4134 t.filter = filters.replace(_alphaFilterExp, "");
4140 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.
4142 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
4143 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)
4144 t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
4147 t.filter = filters.replace(_opacityExp, "opacity=" + val);
4151 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
4152 var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
4154 isAutoAlpha = (p === "autoAlpha");
4155 if (typeof(e) === "string" && e.charAt(1) === "=") {
4156 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
4158 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)
4161 if (_supportsOpacity) {
4162 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
4164 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
4165 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.
4166 style.zoom = 1; //helps correct an IE issue.
4168 pt.b = "alpha(opacity=" + pt.s + ")";
4169 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
4172 pt.setRatio = _setIEOpacityRatio;
4174 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
4175 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
4177 cssp._overwriteProps.push(pt.n);
4178 cssp._overwriteProps.push(p);
4184 var _removeProp = function(s, p) {
4186 if (s.removeProperty) {
4187 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)
4188 p = "M" + p.substr(1);
4190 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
4191 } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
4192 s.removeAttribute(p);
4196 _setClassNameRatio = function(v) {
4197 this.t._gsClassPT = this;
4198 if (v === 1 || v === 0) {
4199 this.t.setAttribute("class", (v === 0) ? this.b : this.e);
4200 var mpt = this.data, //first MiniPropTween
4204 _removeProp(s, mpt.p);
4210 if (v === 1 && this.t._gsClassPT === this) {
4211 this.t._gsClassPT = null;
4213 } else if (this.t.getAttribute("class") !== this.e) {
4214 this.t.setAttribute("class", this.e);
4217 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
4218 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.
4219 cssText = t.style.cssText,
4220 difData, bs, cnpt, cnptLookup, mpt;
4221 pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
4222 pt.setRatio = _setClassNameRatio;
4224 _hasPriority = true;
4226 bs = _getAllStyles(t, _cs);
4227 //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)
4228 cnpt = t._gsClassPT;
4231 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.
4233 cnptLookup[mpt.p] = 1;
4239 pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
4240 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.
4241 t.setAttribute("class", pt.e);
4242 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
4243 t.setAttribute("class", b);
4244 pt.data = difData.firstMPT;
4245 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).
4246 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)
4252 var _setClearPropsRatio = function(v) {
4253 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).
4254 var s = this.t.style,
4255 transformParse = _specialProps.transform.parse,
4256 a, p, i, clearTransform;
4257 if (this.e === "all") {
4259 clearTransform = true;
4261 a = this.e.split(",");
4265 if (_specialProps[p]) {
4266 if (_specialProps[p].parse === transformParse) {
4267 clearTransform = true;
4269 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"
4275 if (clearTransform) {
4276 _removeProp(s, _transformProp);
4277 if (this.t._gsTransform) {
4278 delete this.t._gsTransform;
4284 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
4285 pt = new CSSPropTween(t, p, 0, 0, pt, 2);
4286 pt.setRatio = _setClearPropsRatio;
4289 pt.data = cssp._tween;
4290 _hasPriority = true;
4294 p = "bezier,throwProps,physicsProps,physics2D".split(",");
4297 _registerPluginProp(p[i]);
4307 p = CSSPlugin.prototype;
4310 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
4311 p._onInitTween = function(target, vars, tween) {
4312 if (!target.nodeType) { //css is only for dom elements
4315 this._target = target;
4316 this._tween = tween;
4318 _autoRound = vars.autoRound;
4319 _hasPriority = false;
4320 _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
4321 _cs = _getComputedStyle(target, "");
4322 _overwriteProps = this._overwriteProps;
4323 var style = target.style,
4324 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
4325 if (_reqSafariFix) if (style.zIndex === "") {
4326 v = _getStyle(target, "zIndex", _cs);
4327 if (v === "auto" || v === "") {
4328 //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.
4329 this._addLazySet(style, "zIndex", 0);
4333 if (typeof(vars) === "string") {
4334 first = style.cssText;
4335 v = _getAllStyles(target, _cs);
4336 style.cssText = first + ";" + vars;
4337 v = _cssDif(target, v, _getAllStyles(target)).difs;
4338 if (!_supportsOpacity && _opacityValExp.test(vars)) {
4339 v.opacity = parseFloat( RegExp.$1 );
4342 style.cssText = first;
4344 this._firstPT = pt = this.parse(target, vars, null);
4346 if (this._transformType) {
4347 threeD = (this._transformType === 3);
4348 if (!_transformProp) {
4349 style.zoom = 1; //helps correct an IE issue.
4350 } else if (_isSafari) {
4351 _reqSafariFix = true;
4352 //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
4353 if (style.zIndex === "") {
4354 zIndex = _getStyle(target, "zIndex", _cs);
4355 if (zIndex === "auto" || zIndex === "") {
4356 this._addLazySet(style, "zIndex", 0);
4359 //Setting WebkitBackfaceVisibility corrects 3 bugs:
4360 // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
4361 // 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.
4362 // 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.
4363 //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
4365 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
4369 while (pt2 && pt2._next) {
4372 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
4373 this._linkCSSP(tpt, null, pt2);
4374 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
4375 tpt.data = this._transform || _getTransform(target, _cs, true);
4376 _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.
4380 //reorders the linked list in order of pr (priority)
4384 while (pt2 && pt2.pr > pt.pr) {
4387 if ((pt._prev = pt2 ? pt2._prev : last)) {
4388 pt._prev._next = pt;
4392 if ((pt._next = pt2)) {
4399 this._firstPT = first;
4405 p.parse = function(target, vars, pt, plugin) {
4406 var style = target.style,
4407 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
4409 es = vars[p]; //ending value string
4410 sp = _specialProps[p]; //SpecialProp lookup.
4412 pt = sp.parse(target, es, p, this, pt, plugin, vars);
4415 bs = _getStyle(target, p, _cs) + "";
4416 isStr = (typeof(es) === "string");
4417 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:
4419 es = _parseColor(es);
4420 es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
4422 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
4424 } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
4425 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
4428 bn = parseFloat(bs);
4429 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.
4431 if (bs === "" || bs === "auto") {
4432 if (p === "width" || p === "height") {
4433 bn = _getDimension(target, p, _cs);
4435 } else if (p === "left" || p === "top") {
4436 bn = _calculateOffset(target, p, _cs);
4439 bn = (p !== "opacity") ? 0 : 1;
4444 rel = (isStr && es.charAt(1) === "=");
4446 en = parseInt(es.charAt(0) + "1", 10);
4448 en *= parseFloat(es);
4449 esfx = es.replace(_suffixExp, "");
4451 en = parseFloat(es);
4452 esfx = isStr ? es.substr((en + "").length) || "" : "";
4456 esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
4459 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.
4461 //if the beginning/ending suffixes don't match, normalize them...
4462 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!
4463 bn = _convertToPixels(target, p, bn, bsfx);
4465 bn /= _convertToPixels(target, p, 100, "%") / 100;
4466 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.
4470 } else if (esfx === "em") {
4471 bn /= _convertToPixels(target, p, 1, "em");
4473 //otherwise convert to pixels.
4474 } else if (esfx !== "px") {
4475 en = _convertToPixels(target, p, en, esfx);
4476 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
4478 if (rel) if (en || en === 0) {
4479 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
4487 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.
4488 pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
4490 //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
4491 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
4492 _log("invalid " + p + " tween value: " + vars[p]);
4494 pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
4495 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.
4496 //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
4500 if (plugin) if (pt && !pt.plugin) {
4508 //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.
4509 p.setRatio = function(v) {
4510 var pt = this._firstPT,
4514 //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).
4515 if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
4517 if (pt.type !== 2) {
4525 } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
4527 val = pt.c * v + pt.s;
4529 val = Math.round(val);
4530 } else if (val < min) if (val > -min) {
4534 pt.t[pt.p] = val + pt.xs0;
4535 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
4538 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
4539 } else if (i === 3) {
4540 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
4541 } else if (i === 4) {
4542 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
4543 } else if (i === 5) {
4544 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;
4546 str = pt.xs0 + val + pt.xs1;
4547 for (i = 1; i < pt.l; i++) {
4548 str += pt["xn"+i] + pt["xs"+(i+1)];
4553 } else if (pt.type === -1) { //non-tweening value
4554 pt.t[pt.p] = pt.xs0;
4556 } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
4562 //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).
4565 if (pt.type !== 2) {
4577 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
4578 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
4579 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
4580 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
4581 * doesn't have any transform-related properties of its own. You can call this method as many times as you
4582 * want and it won't create duplicate CSSPropTweens.
4584 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
4586 p._enableTransforms = function(threeD) {
4587 this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
4588 this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
4591 var lazySet = function(v) {
4592 this.t[this.p] = this.e;
4593 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.
4595 /** @private Gives us a way to set a value on the first render (and only the first render). **/
4596 p._addLazySet = function(t, p, v) {
4597 var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
4599 pt.setRatio = lazySet;
4604 p._linkCSSP = function(pt, next, prev, remove) {
4610 pt._next._prev = pt._prev;
4613 pt._prev._next = pt._next;
4614 } else if (this._firstPT === pt) {
4615 this._firstPT = pt._next;
4616 remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
4620 } else if (!remove && this._firstPT === null) {
4629 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
4630 p._kill = function(lookup) {
4633 if (lookup.autoAlpha || lookup.alpha) {
4635 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
4636 copy[p] = lookup[p];
4639 if (copy.autoAlpha) {
4640 copy.visibility = 1;
4643 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".
4645 if (xfirst && xfirst._prev) {
4646 this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
4647 } else if (xfirst === this._firstPT) {
4648 this._firstPT = pt._next;
4651 this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
4653 this._classNamePT = null;
4655 return TweenPlugin.prototype._kill.call(this, copy);
4660 //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
4661 var _getChildStyles = function(e, props, targets) {
4662 var children, i, child, type;
4666 _getChildStyles(e[i], props, targets);
4670 children = e.childNodes;
4671 i = children.length;
4673 child = children[i];
4676 props.push(_getAllStyles(child));
4678 targets.push(child);
4681 if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
4682 _getChildStyles(child, props, targets);
4688 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
4689 * and then compares the style properties of all the target's child elements at the tween's start and end, and
4690 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
4691 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
4692 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
4693 * is because it creates entirely new tweens that may have completely different targets than the original tween,
4694 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
4695 * and it would create other problems. For example:
4696 * - 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)
4697 * - 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.
4698 * - 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.
4700 * @param {Object} target object to be tweened
4701 * @param {number} Duration in seconds (or frames for frames-based tweens)
4702 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
4703 * @return {Array} An array of TweenLite instances
4705 CSSPlugin.cascadeTo = function(target, duration, vars) {
4706 var tween = TweenLite.to(target, duration, vars),
4711 _reservedProps = TweenLite._internals.reservedProps,
4713 target = tween._targets || tween.target;
4714 _getChildStyles(target, b, targets);
4715 tween.render(duration, true);
4716 _getChildStyles(target, e);
4717 tween.render(0, true);
4718 tween._enabled(true);
4721 difs = _cssDif(targets[i], b[i], e[i]);
4722 if (difs.firstMPT) {
4725 if (_reservedProps[p]) {
4729 results.push( TweenLite.to(targets[i], duration, difs) );
4735 TweenPlugin.activate([CSSPlugin]);
4751 * ----------------------------------------------------------------
4753 * ----------------------------------------------------------------
4757 var RoundPropsPlugin = window._gsDefine.plugin({
4758 propName: "roundProps",
4762 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4763 init: function(target, value, tween) {
4764 this._tween = tween;
4769 p = RoundPropsPlugin.prototype;
4771 p._onInitAllProps = function() {
4772 var tween = this._tween,
4773 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
4776 rpt = tween._propLookup.roundProps,
4784 pt = tween._firstPT;
4786 next = pt._next; //record here, because it may get removed
4788 pt.t._roundProps(lookup, true);
4789 } else if (pt.n === prop) {
4790 this._add(pt.t, prop, pt.s, pt.c);
4791 //remove from linked list
4793 next._prev = pt._prev;
4796 pt._prev._next = next;
4797 } else if (tween._firstPT === pt) {
4798 tween._firstPT = next;
4800 pt._next = pt._prev = null;
4801 tween._propLookup[prop] = rpt;
4809 p._add = function(target, p, s, c) {
4810 this._addTween(target, p, s, s + c, p, true);
4811 this._overwriteProps.push(p);
4826 * ----------------------------------------------------------------
4828 * ----------------------------------------------------------------
4830 window._gsDefine.plugin({
4835 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4836 init: function(target, value, tween) {
4838 if (typeof(target.setAttribute) !== "function") {
4841 this._target = target;
4843 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.
4846 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
4847 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
4848 this._end[p] = end ? end.s + end.c : value[p];
4849 this._overwriteProps.push(p);
4854 //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.)
4855 set: function(ratio) {
4856 this._super.setRatio.call(this, ratio);
4857 var props = this._overwriteProps,
4859 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
4863 this._target.setAttribute(p, lookup[p] + "");
4879 * ----------------------------------------------------------------
4880 * DirectionalRotationPlugin
4881 * ----------------------------------------------------------------
4883 window._gsDefine.plugin({
4884 propName: "directionalRotation",
4888 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
4889 init: function(target, value, tween) {
4890 if (typeof(value) !== "object") {
4891 value = {rotation:value};
4894 var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
4896 p, v, start, end, dif, split;
4898 if (p !== "useRadians") {
4899 split = (value[p] + "").split("_");
4901 start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
4902 end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
4905 v = split.join("_");
4906 if (v.indexOf("short") !== -1) {
4908 if (dif !== dif % (cap / 2)) {
4909 dif = (dif < 0) ? dif + cap : dif - cap;
4912 if (v.indexOf("_cw") !== -1 && dif < 0) {
4913 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
4914 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
4915 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
4918 if (dif > min || dif < -min) {
4919 this._addTween(target, p, start, start + dif, p);
4920 this._overwriteProps.push(p);
4927 //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.)
4928 set: function(ratio) {
4931 this._super.setRatio.call(this, ratio);
4936 pt.t[pt.p](this.finals[pt.p]);
4938 pt.t[pt.p] = this.finals[pt.p];
4958 * ----------------------------------------------------------------
4960 * ----------------------------------------------------------------
4962 window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
4964 var w = (window.GreenSockGlobals || window),
4965 gs = w.com.greensock,
4967 _HALF_PI = Math.PI / 2,
4969 _create = function(n, f) {
4970 var C = _class("easing." + n, function(){}, true),
4971 p = C.prototype = new Ease();
4976 _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.
4977 _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
4978 var C = _class("easing."+name, {
4979 easeOut:new EaseOut(),
4980 easeIn:new EaseIn(),
4981 easeInOut:new EaseInOut()
4986 EasePoint = function(time, value, next) {
4992 this.c = next.v - value;
4993 this.gap = next.t - time;
4998 _createBack = function(n, f) {
4999 var C = _class("easing." + n, function(overshoot) {
5000 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
5001 this._p2 = this._p1 * 1.525;
5003 p = C.prototype = new Ease();
5006 p.config = function(overshoot) {
5007 return new C(overshoot);
5012 Back = _wrap("Back",
5013 _createBack("BackOut", function(p) {
5014 return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
5016 _createBack("BackIn", function(p) {
5017 return p * p * ((this._p1 + 1) * p - this._p1);
5019 _createBack("BackInOut", function(p) {
5020 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);
5026 SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
5027 power = (power || power === 0) ? power : 0.7;
5028 if (linearRatio == null) {
5030 } else if (linearRatio > 1) {
5033 this._p = (linearRatio !== 1) ? power : 0;
5034 this._p1 = (1 - linearRatio) / 2;
5035 this._p2 = linearRatio;
5036 this._p3 = this._p1 + this._p2;
5037 this._calcEnd = (yoyoMode === true);
5039 p = SlowMo.prototype = new Ease(),
5040 SteppedEase, RoughEase, _createElastic;
5042 p.constructor = SlowMo;
5043 p.getRatio = function(p) {
5044 var r = p + (0.5 - p) * this._p;
5046 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
5047 } else if (p > this._p3) {
5048 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
5050 return this._calcEnd ? 1 : r;
5052 SlowMo.ease = new SlowMo(0.7, 0.7);
5054 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
5055 return new SlowMo(linearRatio, power, yoyoMode);
5060 SteppedEase = _class("easing.SteppedEase", function(steps) {
5062 this._p1 = 1 / steps;
5063 this._p2 = steps + 1;
5065 p = SteppedEase.prototype = new Ease();
5066 p.constructor = SteppedEase;
5067 p.getRatio = function(p) {
5070 } else if (p >= 1) {
5073 return ((this._p2 * p) >> 0) * this._p1;
5075 p.config = SteppedEase.config = function(steps) {
5076 return new SteppedEase(steps);
5081 RoughEase = _class("easing.RoughEase", function(vars) {
5083 var taper = vars.taper || "none",
5086 points = (vars.points || 20) | 0,
5088 randomize = (vars.randomize !== false),
5089 clamp = (vars.clamp === true),
5090 template = (vars.template instanceof Ease) ? vars.template : null,
5091 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
5092 x, y, bump, invX, obj, pnt;
5094 x = randomize ? Math.random() : (1 / points) * i;
5095 y = template ? template.getRatio(x) : x;
5096 if (taper === "none") {
5098 } else if (taper === "out") {
5100 bump = invX * invX * strength;
5101 } else if (taper === "in") {
5102 bump = x * x * strength;
5103 } else if (x < 0.5) { //"both" (start)
5105 bump = invX * invX * 0.5 * strength;
5106 } else { //"both" (end)
5108 bump = invX * invX * 0.5 * strength;
5111 y += (Math.random() * bump) - (bump * 0.5);
5124 a[cnt++] = {x:x, y:y};
5126 a.sort(function(a, b) {
5130 pnt = new EasePoint(1, 1, null);
5134 pnt = new EasePoint(obj.x, obj.y, pnt);
5137 this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
5139 p = RoughEase.prototype = new Ease();
5140 p.constructor = RoughEase;
5141 p.getRatio = function(p) {
5142 var pnt = this._prev;
5144 while (pnt.next && p >= pnt.t) {
5149 while (pnt.prev && p <= pnt.t) {
5154 return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
5156 p.config = function(vars) {
5157 return new RoughEase(vars);
5159 RoughEase.ease = new RoughEase();
5164 _create("BounceOut", function(p) {
5166 return 7.5625 * p * p;
5167 } else if (p < 2 / 2.75) {
5168 return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5169 } else if (p < 2.5 / 2.75) {
5170 return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5172 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5174 _create("BounceIn", function(p) {
5175 if ((p = 1 - p) < 1 / 2.75) {
5176 return 1 - (7.5625 * p * p);
5177 } else if (p < 2 / 2.75) {
5178 return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
5179 } else if (p < 2.5 / 2.75) {
5180 return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
5182 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
5184 _create("BounceInOut", function(p) {
5185 var invert = (p < 0.5);
5193 } else if (p < 2 / 2.75) {
5194 p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5195 } else if (p < 2.5 / 2.75) {
5196 p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5198 p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5200 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
5207 _create("CircOut", function(p) {
5208 return Math.sqrt(1 - (p = p - 1) * p);
5210 _create("CircIn", function(p) {
5211 return -(Math.sqrt(1 - (p * p)) - 1);
5213 _create("CircInOut", function(p) {
5214 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
5220 _createElastic = function(n, f, def) {
5221 var C = _class("easing." + n, function(amplitude, period) {
5222 this._p1 = amplitude || 1;
5223 this._p2 = period || def;
5224 this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
5226 p = C.prototype = new Ease();
5229 p.config = function(amplitude, period) {
5230 return new C(amplitude, period);
5235 _createElastic("ElasticOut", function(p) {
5236 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
5238 _createElastic("ElasticIn", function(p) {
5239 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
5241 _createElastic("ElasticInOut", function(p) {
5242 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;
5249 _create("ExpoOut", function(p) {
5250 return 1 - Math.pow(2, -10 * p);
5252 _create("ExpoIn", function(p) {
5253 return Math.pow(2, 10 * (p - 1)) - 0.001;
5255 _create("ExpoInOut", function(p) {
5256 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
5263 _create("SineOut", function(p) {
5264 return Math.sin(p * _HALF_PI);
5266 _create("SineIn", function(p) {
5267 return -Math.cos(p * _HALF_PI) + 1;
5269 _create("SineInOut", function(p) {
5270 return -0.5 * (Math.cos(Math.PI * p) - 1);
5274 _class("easing.EaseLookup", {
5280 //register the non-standard eases
5281 _easeReg(w.SlowMo, "SlowMo", "ease,");
5282 _easeReg(RoughEase, "RoughEase", "ease,");
5283 _easeReg(SteppedEase, "SteppedEase", "ease,");
5303 * ----------------------------------------------------------------
5304 * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
5305 * ----------------------------------------------------------------
5310 var _globals = window.GreenSockGlobals || window;
5311 if (_globals.TweenLite) {
5312 return; //in case the core set of classes is already loaded, don't instantiate twice.
5314 var _namespace = function(ns) {
5315 var a = ns.split("."),
5317 for (i = 0; i < a.length; i++) {
5318 p[a[i]] = p = p[a[i]] || {};
5322 gs = _namespace("com.greensock"),
5323 _tinyNum = 0.0000000001,
5325 _emptyFunc = function() {},
5326 _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)
5327 var toString = Object.prototype.toString,
5328 array = toString.call([]);
5329 return function(obj) {
5330 return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
5333 a, i, p, _ticker, _tickerActive,
5338 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
5339 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
5340 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
5341 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
5343 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
5344 * 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,
5345 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
5346 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
5347 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
5348 * 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
5349 * sandbox the banner one like:
5352 * 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.
5354 * <script src="js/greensock/v1.7/TweenMax.js"></script>
5356 * 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(...)
5358 * <script src="js/greensock/v1.6/TweenMax.js"></script>
5360 * gs.TweenLite.to(...); //would use v1.7
5361 * TweenLite.to(...); //would use v1.6
5364 * @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".
5365 * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
5366 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
5367 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
5369 Definition = function(ns, dependencies, func, global) {
5370 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
5371 _defLookup[ns] = this;
5372 this.gsClass = null;
5375 this.check = function(init) {
5376 var i = dependencies.length,
5380 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
5381 _classes[i] = cur.gsClass;
5387 if (missing === 0 && func) {
5388 a = ("com.greensock." + ns).split(".");
5390 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
5392 //exports to multiple environments
5394 _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.)
5395 if (typeof(define) === "function" && define.amd){ //AMD
5396 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
5397 } else if (typeof(module) !== "undefined" && module.exports){ //node
5398 module.exports = cl;
5401 for (i = 0; i < this.sc.length; i++) {
5409 //used to create Definition instances (which basically registers a class that has dependencies).
5410 _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
5411 return new Definition(ns, dependencies, func, global);
5414 //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).
5415 _class = gs._class = function(ns, func, global) {
5416 func = func || function() {};
5417 _gsDefine(ns, [], function(){ return func; }, global);
5421 _gsDefine.globals = _globals;
5426 * ----------------------------------------------------------------
5428 * ----------------------------------------------------------------
5430 var _baseParams = [0, 0, 1, 1],
5432 Ease = _class("easing.Ease", function(func, extraParams, type, power) {
5434 this._type = type || 0;
5435 this._power = power || 0;
5436 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
5438 _easeMap = Ease.map = {},
5439 _easeReg = Ease.register = function(ease, names, types, create) {
5440 var na = names.split(","),
5442 ta = (types || "easeIn,easeOut,easeInOut").split(","),
5446 e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
5450 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
5457 p.getRatio = function(p) {
5459 this._params[0] = p;
5460 return this._func.apply(null, this._params);
5464 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
5467 } else if (pw === 2) {
5469 } else if (pw === 3) {
5471 } else if (pw === 4) {
5474 return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
5477 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
5478 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
5481 p = a[i]+",Power"+i;
5482 _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
5483 _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
5484 _easeReg(new Ease(null,null,3,i), p, "easeInOut");
5486 _easeMap.linear = gs.easing.Linear.easeIn;
5487 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
5491 * ----------------------------------------------------------------
5493 * ----------------------------------------------------------------
5495 var EventDispatcher = _class("events.EventDispatcher", function(target) {
5496 this._listeners = {};
5497 this._eventTarget = target || this;
5499 p = EventDispatcher.prototype;
5501 p.addEventListener = function(type, callback, scope, useParam, priority) {
5502 priority = priority || 0;
5503 var list = this._listeners[type],
5507 this._listeners[type] = list = [];
5512 if (listener.c === callback && listener.s === scope) {
5514 } else if (index === 0 && listener.pr < priority) {
5518 list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
5519 if (this === _ticker && !_tickerActive) {
5524 p.removeEventListener = function(type, callback) {
5525 var list = this._listeners[type], i;
5529 if (list[i].c === callback) {
5537 p.dispatchEvent = function(type) {
5538 var list = this._listeners[type],
5542 t = this._eventTarget;
5546 listener.c.call(listener.s || t, {type:type, target:t});
5548 listener.c.call(listener.s || t);
5556 * ----------------------------------------------------------------
5558 * ----------------------------------------------------------------
5560 var _reqAnimFrame = window.requestAnimationFrame,
5561 _cancelAnimFrame = window.cancelAnimationFrame,
5562 _getTime = Date.now || function() {return new Date().getTime();},
5563 _lastUpdate = _getTime();
5565 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
5566 a = ["ms","moz","webkit","o"];
5568 while (--i > -1 && !_reqAnimFrame) {
5569 _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
5570 _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
5573 _class("Ticker", function(fps, useRAF) {
5575 _startTime = _getTime(),
5576 _useRAF = (useRAF !== false && _reqAnimFrame),
5577 _lagThreshold = 500,
5579 _fps, _req, _id, _gap, _nextTime,
5580 _tick = function(manual) {
5581 var elapsed = _getTime() - _lastUpdate,
5583 if (elapsed > _lagThreshold) {
5584 _startTime += elapsed - _adjustedLag;
5586 _lastUpdate += elapsed;
5587 _self.time = (_lastUpdate - _startTime) / 1000;
5588 overlap = _self.time - _nextTime;
5589 if (!_fps || overlap > 0 || manual === true) {
5591 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
5594 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.
5598 _self.dispatchEvent("tick");
5602 EventDispatcher.call(_self);
5603 _self.time = _self.frame = 0;
5604 _self.tick = function() {
5608 _self.lagSmoothing = function(threshold, adjustedLag) {
5609 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
5610 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
5613 _self.sleep = function() {
5617 if (!_useRAF || !_cancelAnimFrame) {
5620 _cancelAnimFrame(_id);
5624 if (_self === _ticker) {
5625 _tickerActive = false;
5629 _self.wake = function() {
5632 } 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().
5633 _lastUpdate = _getTime() - _lagThreshold + 5;
5635 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
5636 if (_self === _ticker) {
5637 _tickerActive = true;
5642 _self.fps = function(value) {
5643 if (!arguments.length) {
5647 _gap = 1 / (_fps || 60);
5648 _nextTime = this.time + _gap;
5652 _self.useRAF = function(value) {
5653 if (!arguments.length) {
5662 //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.
5663 setTimeout(function() {
5664 if (_useRAF && (!_id || _self.frame < 5)) {
5665 _self.useRAF(false);
5670 p = gs.Ticker.prototype = new gs.events.EventDispatcher();
5671 p.constructor = gs.Ticker;
5675 * ----------------------------------------------------------------
5677 * ----------------------------------------------------------------
5679 var Animation = _class("core.Animation", function(duration, vars) {
5680 this.vars = vars = vars || {};
5681 this._duration = this._totalDuration = duration || 0;
5682 this._delay = Number(vars.delay) || 0;
5683 this._timeScale = 1;
5684 this._active = (vars.immediateRender === true);
5685 this.data = vars.data;
5686 this._reversed = (vars.reversed === true);
5688 if (!_rootTimeline) {
5691 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.
5695 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
5696 tl.add(this, tl._time);
5698 if (this.vars.paused) {
5703 _ticker = Animation.ticker = new gs.Ticker();
5704 p = Animation.prototype;
5705 p._dirty = p._gc = p._initted = p._paused = false;
5706 p._totalTime = p._time = 0;
5707 p._rawPrevTime = -1;
5708 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
5712 //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.
5713 var _checkTimeout = function() {
5714 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
5717 setTimeout(_checkTimeout, 2000);
5722 p.play = function(from, suppressEvents) {
5724 this.seek(from, suppressEvents);
5726 return this.reversed(false).paused(false);
5729 p.pause = function(atTime, suppressEvents) {
5730 if (atTime != null) {
5731 this.seek(atTime, suppressEvents);
5733 return this.paused(true);
5736 p.resume = function(from, suppressEvents) {
5738 this.seek(from, suppressEvents);
5740 return this.paused(false);
5743 p.seek = function(time, suppressEvents) {
5744 return this.totalTime(Number(time), suppressEvents !== false);
5747 p.restart = function(includeDelay, suppressEvents) {
5748 return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
5751 p.reverse = function(from, suppressEvents) {
5753 this.seek((from || this.totalDuration()), suppressEvents);
5755 return this.reversed(true).paused(false);
5758 p.render = function(time, suppressEvents, force) {
5759 //stub - we override this method in subclasses.
5762 p.invalidate = function() {
5766 p.isActive = function() {
5767 var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
5768 startTime = this._startTime,
5770 return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
5773 p._enabled = function (enabled, ignoreTimeline) {
5774 if (!_tickerActive) {
5777 this._gc = !enabled;
5778 this._active = this.isActive();
5779 if (ignoreTimeline !== true) {
5780 if (enabled && !this.timeline) {
5781 this._timeline.add(this, this._startTime - this._delay);
5782 } else if (!enabled && this.timeline) {
5783 this._timeline._remove(this, true);
5790 p._kill = function(vars, target) {
5791 return this._enabled(false, false);
5794 p.kill = function(vars, target) {
5795 this._kill(vars, target);
5799 p._uncache = function(includeSelf) {
5800 var tween = includeSelf ? this : this.timeline;
5802 tween._dirty = true;
5803 tween = tween.timeline;
5808 p._swapSelfInParams = function(params) {
5809 var i = params.length,
5810 copy = params.concat();
5812 if (params[i] === "{self}") {
5819 //----Animation getters/setters --------------------------------------------------------
5821 p.eventCallback = function(type, callback, params, scope) {
5822 if ((type || "").substr(0,2) === "on") {
5824 if (arguments.length === 1) {
5827 if (callback == null) {
5831 v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
5832 v[type + "Scope"] = scope;
5834 if (type === "onUpdate") {
5835 this._onUpdate = callback;
5841 p.delay = function(value) {
5842 if (!arguments.length) {
5845 if (this._timeline.smoothChildTiming) {
5846 this.startTime( this._startTime + value - this._delay );
5848 this._delay = value;
5852 p.duration = function(value) {
5853 if (!arguments.length) {
5854 this._dirty = false;
5855 return this._duration;
5857 this._duration = this._totalDuration = value;
5858 this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
5859 if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
5860 this.totalTime(this._totalTime * (value / this._duration), true);
5865 p.totalDuration = function(value) {
5866 this._dirty = false;
5867 return (!arguments.length) ? this._totalDuration : this.duration(value);
5870 p.time = function(value, suppressEvents) {
5871 if (!arguments.length) {
5875 this.totalDuration();
5877 return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
5880 p.totalTime = function(time, suppressEvents, uncapped) {
5881 if (!_tickerActive) {
5884 if (!arguments.length) {
5885 return this._totalTime;
5887 if (this._timeline) {
5888 if (time < 0 && !uncapped) {
5889 time += this.totalDuration();
5891 if (this._timeline.smoothChildTiming) {
5893 this.totalDuration();
5895 var totalDuration = this._totalDuration,
5896 tl = this._timeline;
5897 if (time > totalDuration && !uncapped) {
5898 time = totalDuration;
5900 this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
5901 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.
5902 this._uncache(false);
5904 //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.
5906 while (tl._timeline) {
5907 if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
5908 tl.totalTime(tl._totalTime, true);
5915 this._enabled(true, false);
5917 if (this._totalTime !== time || this._duration === 0) {
5918 this.render(time, suppressEvents, false);
5919 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.
5927 p.progress = p.totalProgress = function(value, suppressEvents) {
5928 return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
5931 p.startTime = function(value) {
5932 if (!arguments.length) {
5933 return this._startTime;
5935 if (value !== this._startTime) {
5936 this._startTime = value;
5937 if (this.timeline) if (this.timeline._sortChildren) {
5938 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.
5944 p.timeScale = function(value) {
5945 if (!arguments.length) {
5946 return this._timeScale;
5948 value = value || _tinyNum; //can't allow zero because it'll throw the math off
5949 if (this._timeline && this._timeline.smoothChildTiming) {
5950 var pauseTime = this._pauseTime,
5951 t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
5952 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
5954 this._timeScale = value;
5955 return this._uncache(false);
5958 p.reversed = function(value) {
5959 if (!arguments.length) {
5960 return this._reversed;
5962 if (value != this._reversed) {
5963 this._reversed = value;
5964 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
5969 p.paused = function(value) {
5970 if (!arguments.length) {
5971 return this._paused;
5973 if (value != this._paused) if (this._timeline) {
5974 if (!_tickerActive && !value) {
5977 var tl = this._timeline,
5979 elapsed = raw - this._pauseTime;
5980 if (!value && tl.smoothChildTiming) {
5981 this._startTime += elapsed;
5982 this._uncache(false);
5984 this._pauseTime = value ? raw : null;
5985 this._paused = value;
5986 this._active = this.isActive();
5987 if (!value && elapsed !== 0 && this._initted && this.duration()) {
5988 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.
5991 if (this._gc && !value) {
5992 this._enabled(true, false);
5999 * ----------------------------------------------------------------
6001 * ----------------------------------------------------------------
6003 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
6004 Animation.call(this, 0, vars);
6005 this.autoRemoveChildren = this.smoothChildTiming = true;
6008 p = SimpleTimeline.prototype = new Animation();
6009 p.constructor = SimpleTimeline;
6010 p.kill()._gc = false;
6011 p._first = p._last = null;
6012 p._sortChildren = false;
6014 p.add = p.insert = function(child, position, align, stagger) {
6016 child._startTime = Number(position || 0) + child._delay;
6017 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).
6018 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
6020 if (child.timeline) {
6021 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
6023 child.timeline = child._timeline = this;
6025 child._enabled(true, true);
6027 prevTween = this._last;
6028 if (this._sortChildren) {
6029 st = child._startTime;
6030 while (prevTween && prevTween._startTime > st) {
6031 prevTween = prevTween._prev;
6035 child._next = prevTween._next;
6036 prevTween._next = child;
6038 child._next = this._first;
6039 this._first = child;
6042 child._next._prev = child;
6046 child._prev = prevTween;
6047 if (this._timeline) {
6048 this._uncache(true);
6053 p._remove = function(tween, skipDisable) {
6054 if (tween.timeline === this) {
6056 tween._enabled(false, true);
6058 tween.timeline = null;
6061 tween._prev._next = tween._next;
6062 } else if (this._first === tween) {
6063 this._first = tween._next;
6066 tween._next._prev = tween._prev;
6067 } else if (this._last === tween) {
6068 this._last = tween._prev;
6071 if (this._timeline) {
6072 this._uncache(true);
6078 p.render = function(time, suppressEvents, force) {
6079 var tween = this._first,
6081 this._totalTime = this._time = this._rawPrevTime = time;
6083 next = tween._next; //record it here because the value could change after rendering...
6084 if (tween._active || (time >= tween._startTime && !tween._paused)) {
6085 if (!tween._reversed) {
6086 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
6088 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
6095 p.rawTime = function() {
6096 if (!_tickerActive) {
6099 return this._totalTime;
6103 * ----------------------------------------------------------------
6105 * ----------------------------------------------------------------
6107 var TweenLite = _class("TweenLite", function(target, duration, vars) {
6108 Animation.call(this, duration, vars);
6109 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
6111 if (target == null) {
6112 throw "Cannot tween a null target.";
6115 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
6117 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
6118 overwrite = this.vars.overwrite,
6121 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
6123 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
6124 this._targets = targets = _slice.call(target, 0);
6125 this._propLookup = [];
6126 this._siblings = [];
6127 for (i = 0; i < targets.length; i++) {
6130 targets.splice(i--, 1);
6132 } else if (typeof(targ) === "string") {
6133 targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
6134 if (typeof(targ) === "string") {
6135 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
6138 } 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.
6139 targets.splice(i--, 1);
6140 this._targets = targets = targets.concat(_slice.call(targ, 0));
6143 this._siblings[i] = _register(targ, this, false);
6144 if (overwrite === 1) if (this._siblings[i].length > 1) {
6145 _applyOverwrite(targ, this, null, 1, this._siblings[i]);
6150 this._propLookup = {};
6151 this._siblings = _register(target, this, false);
6152 if (overwrite === 1) if (this._siblings.length > 1) {
6153 _applyOverwrite(target, this, null, 1, this._siblings);
6156 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
6157 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)
6158 this.render(-this._delay);
6161 _isSelector = function(v) {
6162 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.
6164 _autoCSS = function(vars, target) {
6168 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.
6176 p = TweenLite.prototype = new Animation();
6177 p.constructor = TweenLite;
6178 p.kill()._gc = false;
6180 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
6183 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
6184 p._notifyPluginsOfEnabled = p._lazy = false;
6186 TweenLite.version = "1.12.1";
6187 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
6188 TweenLite.defaultOverwrite = "auto";
6189 TweenLite.ticker = _ticker;
6190 TweenLite.autoSleep = true;
6191 TweenLite.lagSmoothing = function(threshold, adjustedLag) {
6192 _ticker.lagSmoothing(threshold, adjustedLag);
6194 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; };
6196 var _lazyTweens = [],
6198 _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.
6199 _plugins = TweenLite._plugins = {},
6200 _tweenLookup = _internals.tweenLookup = {},
6201 _tweenLookupNum = 0,
6202 _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},
6203 _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
6204 _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
6205 _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
6206 _lazyRender = function() {
6207 var i = _lazyTweens.length;
6211 if (a && a._lazy !== false) {
6212 a.render(a._lazy, false, true);
6216 _lazyTweens.length = 0;
6219 _rootTimeline._startTime = _ticker.time;
6220 _rootFramesTimeline._startTime = _ticker.frame;
6221 _rootTimeline._active = _rootFramesTimeline._active = true;
6222 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".
6224 Animation._updateRoot = TweenLite.render = function() {
6226 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.
6229 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
6230 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
6231 if (_lazyTweens.length) {
6234 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
6235 for (p in _tweenLookup) {
6236 a = _tweenLookup[p].tweens;
6243 if (a.length === 0) {
6244 delete _tweenLookup[p];
6247 //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
6248 p = _rootTimeline._first;
6249 if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
6250 while (p && p._paused) {
6260 _ticker.addEventListener("tick", Animation._updateRoot);
6262 var _register = function(target, tween, scrub) {
6263 var id = target._gsTweenID, a, i;
6264 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
6265 _tweenLookup[id] = {target:target, tweens:[]};
6268 a = _tweenLookup[id].tweens;
6269 a[(i = a.length)] = tween;
6272 if (a[i] === tween) {
6278 return _tweenLookup[id].tweens;
6281 _applyOverwrite = function(target, tween, props, mode, siblings) {
6282 var i, changed, curTween, l;
6283 if (mode === 1 || mode >= 4) {
6284 l = siblings.length;
6285 for (i = 0; i < l; i++) {
6286 if ((curTween = siblings[i]) !== tween) {
6287 if (!curTween._gc) if (curTween._enabled(false, false)) {
6290 } else if (mode === 5) {
6296 //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)
6297 var startTime = tween._startTime + _tinyNum,
6300 zeroDur = (tween._duration === 0),
6302 i = siblings.length;
6304 if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
6306 } else if (curTween._timeline !== tween._timeline) {
6307 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
6308 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
6309 overlaps[oCount++] = curTween;
6311 } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
6312 overlaps[oCount++] = curTween;
6318 curTween = overlaps[i];
6319 if (mode === 2) if (curTween._kill(props, target)) {
6322 if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
6323 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
6331 _checkOverlap = function(tween, reference, zeroDur) {
6332 var tl = tween._timeline,
6334 t = tween._startTime;
6335 while (tl._timeline) {
6337 ts *= tl._timeScale;
6344 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;
6348 //---- TweenLite instance methods -----------------------------------------------------------------------------
6350 p._init = function() {
6352 op = this._overwrittenProps,
6353 dur = this._duration,
6354 immediate = !!v.immediateRender,
6356 i, initPlugins, pt, p, startVars;
6358 if (this._startAt) {
6359 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.
6360 this._startAt.kill();
6363 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);
6364 startVars[p] = v.startAt[p];
6366 startVars.overwrite = false;
6367 startVars.immediateRender = true;
6368 startVars.lazy = (immediate && v.lazy !== false);
6369 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
6370 this._startAt = TweenLite.to(this.target, 0, startVars);
6372 if (this._time > 0) {
6373 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()).
6374 } else if (dur !== 0) {
6375 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.
6378 } else if (v.runBackwards && dur !== 0) {
6379 //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)
6380 if (this._startAt) {
6381 this._startAt.render(-1, true);
6382 this._startAt.kill();
6383 this._startAt = null;
6386 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.
6387 if (!_reservedProps[p] || p === "autoCSS") {
6392 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.
6393 pt.lazy = (immediate && v.lazy !== false);
6394 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)
6395 this._startAt = TweenLite.to(this.target, 0, pt);
6397 this._startAt._init(); //ensures that the initial values are recorded
6398 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.
6399 } else if (this._time === 0) {
6405 this._ease = TweenLite.defaultEase;
6406 } else if (ease instanceof Ease) {
6407 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
6409 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
6411 this._easeType = this._ease._type;
6412 this._easePower = this._ease._power;
6413 this._firstPT = null;
6415 if (this._targets) {
6416 i = this._targets.length;
6418 if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
6423 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
6427 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
6429 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.
6430 this._enabled(false, false);
6432 if (v.runBackwards) {
6440 this._onUpdate = v.onUpdate;
6441 this._initted = true;
6444 p._initProps = function(target, propLookup, siblings, overwrittenProps) {
6445 var p, i, initPlugins, plugin, pt, v;
6446 if (target == null) {
6450 if (_lazyLookup[target._gsTweenID]) {
6451 _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)
6454 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.
6455 _autoCSS(this.vars, target);
6457 for (p in this.vars) {
6459 if (_reservedProps[p]) {
6460 if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
6461 this.vars[p] = v = this._swapSelfInParams(v, this);
6464 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
6466 //t - target [object]
6467 //p - property [string]
6468 //s - start [number]
6469 //c - change [number]
6470 //f - isFunction [boolean]
6472 //pg - isPlugin [boolean]
6473 //pr - priority [number]
6474 this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
6475 i = plugin._overwriteProps.length;
6477 propLookup[plugin._overwriteProps[i]] = this._firstPT;
6479 if (plugin._priority || plugin._onInitAllProps) {
6482 if (plugin._onDisable || plugin._onEnable) {
6483 this._notifyPluginsOfEnabled = true;
6487 this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
6488 pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
6489 pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
6491 if (pt) if (pt._next) {
6492 pt._next._prev = pt;
6496 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)
6497 return this._initProps(target, propLookup, siblings, overwrittenProps);
6499 if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
6500 this._kill(propLookup, target);
6501 return this._initProps(target, propLookup, siblings, overwrittenProps);
6503 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.
6504 _lazyLookup[target._gsTweenID] = true;
6509 p.render = function(time, suppressEvents, force) {
6510 var prevTime = this._time,
6511 duration = this._duration,
6512 prevRawPrevTime = this._rawPrevTime,
6513 isComplete, callback, pt, rawPrevTime;
6514 if (time >= duration) {
6515 this._totalTime = this._time = duration;
6516 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
6517 if (!this._reversed ) {
6519 callback = "onComplete";
6521 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.
6522 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.
6525 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
6527 if (prevRawPrevTime > _tinyNum) {
6528 callback = "onReverseComplete";
6531 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.
6534 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
6535 this._totalTime = this._time = 0;
6536 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
6537 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
6538 callback = "onReverseComplete";
6539 isComplete = this._reversed;
6542 this._active = false;
6543 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.
6544 if (prevRawPrevTime >= 0) {
6547 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.
6549 } 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.
6553 this._totalTime = this._time = time;
6555 if (this._easeType) {
6556 var r = time / duration, type = this._easeType, pow = this._easePower;
6557 if (type === 1 || (type === 3 && r >= 0.5)) {
6565 } else if (pow === 2) {
6567 } else if (pow === 3) {
6569 } else if (pow === 4) {
6575 } else if (type === 2) {
6577 } else if (time / duration < 0.5) {
6580 this.ratio = 1 - (r / 2);
6584 this.ratio = this._ease.getRatio(time / duration);
6588 if (this._time === prevTime && !force) {
6590 } else if (!this._initted) {
6592 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.
6594 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
6595 this._time = this._totalTime = prevTime;
6596 this._rawPrevTime = prevRawPrevTime;
6597 _lazyTweens.push(this);
6601 //_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.
6602 if (this._time && !isComplete) {
6603 this.ratio = this._ease.getRatio(this._time / duration);
6604 } else if (isComplete && this._ease._calcEnd) {
6605 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
6608 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.
6611 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
6612 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.
6614 if (prevTime === 0) {
6615 if (this._startAt) {
6617 this._startAt.render(time, suppressEvents, force);
6618 } else if (!callback) {
6619 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.
6622 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
6623 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
6630 pt.t[pt.p](pt.c * this.ratio + pt.s);
6632 pt.t[pt.p] = pt.c * this.ratio + pt.s;
6637 if (this._onUpdate) {
6638 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.
6639 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.
6641 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
6642 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
6646 if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
6647 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.
6648 this._startAt.render(time, suppressEvents, force);
6651 if (this._timeline.autoRemoveChildren) {
6652 this._enabled(false, false);
6654 this._active = false;
6656 if (!suppressEvents && this.vars[callback]) {
6657 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
6659 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.
6660 this._rawPrevTime = 0;
6666 p._kill = function(vars, target) {
6667 if (vars === "all") {
6670 if (vars == null) if (target == null || target === this.target) {
6672 return this._enabled(false, false);
6674 target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
6675 var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
6676 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
6679 if (this._kill(vars, target[i])) {
6684 if (this._targets) {
6685 i = this._targets.length;
6687 if (target === this._targets[i]) {
6688 propLookup = this._propLookup[i] || {};
6689 this._overwrittenProps = this._overwrittenProps || [];
6690 overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
6694 } else if (target !== this.target) {
6697 propLookup = this._propLookup;
6698 overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
6702 killProps = vars || propLookup;
6703 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)
6704 for (p in killProps) {
6705 if ((pt = propLookup[p])) {
6706 if (pt.pg && pt.t._kill(killProps)) {
6707 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
6709 if (!pt.pg || pt.t._overwriteProps.length === 0) {
6711 pt._prev._next = pt._next;
6712 } else if (pt === this._firstPT) {
6713 this._firstPT = pt._next;
6716 pt._next._prev = pt._prev;
6718 pt._next = pt._prev = null;
6720 delete propLookup[p];
6723 overwrittenProps[p] = 1;
6726 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.
6727 this._enabled(false, false);
6734 p.invalidate = function() {
6735 if (this._notifyPluginsOfEnabled) {
6736 TweenLite._onPluginEvent("_onDisable", this);
6738 this._firstPT = null;
6739 this._overwrittenProps = null;
6740 this._onUpdate = null;
6741 this._startAt = null;
6742 this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
6743 this._propLookup = (this._targets) ? {} : [];
6747 p._enabled = function(enabled, ignoreTimeline) {
6748 if (!_tickerActive) {
6751 if (enabled && this._gc) {
6752 var targets = this._targets,
6757 this._siblings[i] = _register(targets[i], this, true);
6760 this._siblings = _register(this.target, this, true);
6763 Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
6764 if (this._notifyPluginsOfEnabled) if (this._firstPT) {
6765 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
6771 //----TweenLite static methods -----------------------------------------------------
6773 TweenLite.to = function(target, duration, vars) {
6774 return new TweenLite(target, duration, vars);
6777 TweenLite.from = function(target, duration, vars) {
6778 vars.runBackwards = true;
6779 vars.immediateRender = (vars.immediateRender != false);
6780 return new TweenLite(target, duration, vars);
6783 TweenLite.fromTo = function(target, duration, fromVars, toVars) {
6784 toVars.startAt = fromVars;
6785 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
6786 return new TweenLite(target, duration, toVars);
6789 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
6790 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});
6793 TweenLite.set = function(target, vars) {
6794 return new TweenLite(target, 0, vars);
6797 TweenLite.getTweensOf = function(target, onlyActive) {
6798 if (target == null) { return []; }
6799 target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
6801 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
6805 a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
6808 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
6819 a = _register(target).concat();
6822 if (a[i]._gc || (onlyActive && !a[i].isActive())) {
6830 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
6831 if (typeof(onlyActive) === "object") {
6832 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
6835 var a = TweenLite.getTweensOf(target, onlyActive),
6838 a[i]._kill(vars, target);
6845 * ----------------------------------------------------------------
6846 * 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)
6847 * ----------------------------------------------------------------
6849 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
6850 this._overwriteProps = (props || "").split(",");
6851 this._propName = this._overwriteProps[0];
6852 this._priority = priority || 0;
6853 this._super = TweenPlugin.prototype;
6856 p = TweenPlugin.prototype;
6857 TweenPlugin.version = "1.10.1";
6858 TweenPlugin.API = 2;
6861 p._addTween = function(target, prop, start, end, overwriteProp, round) {
6863 if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
6864 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
6866 pt._next._prev = pt;
6872 p.setRatio = function(v) {
6873 var pt = this._firstPT,
6877 val = pt.c * v + pt.s;
6879 val = Math.round(val);
6880 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
6892 p._kill = function(lookup) {
6893 var a = this._overwriteProps,
6896 if (lookup[this._propName] != null) {
6897 this._overwriteProps = [];
6901 if (lookup[a[i]] != null) {
6907 if (lookup[pt.n] != null) {
6909 pt._next._prev = pt._prev;
6912 pt._prev._next = pt._next;
6914 } else if (this._firstPT === pt) {
6915 this._firstPT = pt._next;
6923 p._roundProps = function(lookup, value) {
6924 var pt = this._firstPT;
6926 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.
6933 TweenLite._onPluginEvent = function(type, tween) {
6934 var pt = tween._firstPT,
6935 changed, pt2, first, last, next;
6936 if (type === "_onInitAllProps") {
6937 //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.
6941 while (pt2 && pt2.pr > pt.pr) {
6944 if ((pt._prev = pt2 ? pt2._prev : last)) {
6945 pt._prev._next = pt;
6949 if ((pt._next = pt2)) {
6956 pt = tween._firstPT = first;
6959 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
6967 TweenPlugin.activate = function(plugins) {
6968 var i = plugins.length;
6970 if (plugins[i].API === TweenPlugin.API) {
6971 _plugins[(new plugins[i]())._propName] = plugins[i];
6977 //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.
6978 _gsDefine.plugin = function(config) {
6979 if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
6980 var propName = config.propName,
6981 priority = config.priority || 0,
6982 overwriteProps = config.overwriteProps,
6983 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
6984 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
6986 TweenPlugin.call(this, propName, priority);
6987 this._overwriteProps = overwriteProps || [];
6988 }, (config.global === true)),
6989 p = Plugin.prototype = new TweenPlugin(propName),
6991 p.constructor = Plugin;
6992 Plugin.API = config.API;
6994 if (typeof(config[prop]) === "function") {
6995 p[map[prop]] = config[prop];
6998 Plugin.version = config.version;
6999 TweenPlugin.activate([Plugin]);
7004 //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.
7005 a = window._gsQueue;
7007 for (i = 0; i < a.length; i++) {
7010 for (p in _defLookup) {
7011 if (!_defLookup[p].func) {
7012 //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
7017 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
7021 angular.module('att.abs.transition', [])
7023 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
7025 var $transition = function(element, trigger, options) {
7026 options = options || {};
7027 var deferred = $q.defer();
7028 var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
7030 var transitionEndHandler = function(event) {
7031 $rootScope.$apply(function() {
7032 element.unbind(endEventName, transitionEndHandler);
7033 deferred.resolve(element);
7038 element.bind(endEventName, transitionEndHandler);
7041 // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
7042 $timeout(function() {
7043 if ( angular.isString(trigger) ) {
7044 element.addClass(trigger);
7045 } else if ( angular.isFunction(trigger) ) {
7047 } else if ( angular.isObject(trigger) ) {
7048 element.css(trigger);
7050 //If browser does not support transitions, instantly resolve
7051 if ( !endEventName ) {
7052 deferred.resolve(element);
7056 // Add our custom cancel function to the promise that is returned
7057 // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
7058 // i.e. it will therefore never raise a transitionEnd event for that transition
7059 deferred.promise.cancel = function() {
7060 if ( endEventName ) {
7061 element.unbind(endEventName, transitionEndHandler);
7063 deferred.reject('Transition cancelled');
7066 return deferred.promise;
7069 // Work out the name of the transitionEnd event
7070 var transElement = document.createElement('trans');
7071 var transitionEndEventNames = {
7072 'WebkitTransition': 'webkitTransitionEnd',
7073 'MozTransition': 'transitionend',
7074 'OTransition': 'oTransitionEnd',
7075 'transition': 'transitionend'
7077 var animationEndEventNames = {
7078 'WebkitTransition': 'webkitAnimationEnd',
7079 'MozTransition': 'animationend',
7080 'OTransition': 'oAnimationEnd',
7081 'transition': 'animationend'
7083 function findEndEventName(endEventNames) {
7084 for (var name in endEventNames){
7085 if (transElement.style[name] !== undefined) {
7086 return endEventNames[name];
7090 $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
7091 $transition.animationEndEventName = findEndEventName(animationEndEventNames);
7095 .factory('$scrollTo', ['$window', function($window) {
7096 var $scrollTo = function(offsetLeft, offsetTop, duration) {
7097 TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
7101 .factory('animation', function(){
7104 .factory('$progressBar', function(){
7106 //Provides a function to pass in code for closure purposes
7107 var loadingAnimationCreator = function(onUpdateCallback){
7109 //Use closure to setup some resuable code
7110 var loadingAnimation = function(callback, duration){
7111 TweenMax.to({}, duration, {
7112 onUpdateParams: ["{self}"],
7113 onUpdate: onUpdateCallback,
7114 onComplete: callback
7117 //Returns a function that takes a callback function and a duration for the animation
7119 return loadingAnimation;
7124 return loadingAnimationCreator;
7126 .factory('$height', function(){
7127 var heightAnimation = function(element,duration,height,alpha){
7128 TweenMax.to(element,
7130 {height:height, autoAlpha:alpha},
7133 return heightAnimation;
7136 angular.module('att.abs.accordion', ['att.abs.position','att.abs.transition'])
7137 .constant('accordionConfig', {
7141 .controller('AccordionController',['$scope', '$attrs', 'accordionConfig', '$log',
7142 function($scope, $attrs, accordionConfig, $log) {
7143 // This array keeps track of the accordion groups
7147 // Keep reference to user's scope to properly assign `is-open`
7148 this.scope = $scope;
7149 $scope.forceExpand=false;
7150 // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
7151 this.closeOthers = function(openGroup) {
7152 var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
7153 if(closeOthers && !$scope.forceExpand) {
7154 angular.forEach(this.groups, function(group) {
7155 if (group !== openGroup) {
7160 if(this.groups.indexOf(openGroup)===(this.groups.length-1) && $scope.forceExpand){
7161 $scope.forceExpand=false;
7165 this.expandAll = function() {
7166 $scope.forceExpand=true;
7167 angular.forEach(this.groups, function(group) {
7168 group.isOpen = true;
7172 this.collapseAll = function() {
7173 angular.forEach(this.groups, function(group) {
7174 group.isOpen = false;
7182 this.focus = function(focusGroup) {
7184 $log.log("entering focus");
7185 angular.forEach(this.groups, function(group, index) {
7186 if (group !== focusGroup) {
7187 group.focused = false;
7190 group.focused = true;
7198 this.blur = function(blurGroup) {
7199 blurGroup.focused = false;
7201 $log.log("accordion.blur()", blurGroup);
7205 * @param group - the group in current focus
7206 * @param down - cycling down
7208 this.cycle = function(group, down, noRecycle) {
7210 if (this.index <= 0 && !noRecycle) {
7211 this.index = this.groups.length - 1;
7217 /*if (this.index === (this.groups.length - 1) && !noRecycle) {
7219 } else if (this.index === (this.groups.length - 1) && noRecycle) {
7225 if (this.index === (this.groups.length - 1))
7229 group.focused = false;
7243 group.focused = false;
7244 this.groups[this.index].focused = true;
7245 $log.log("accordion.cycle()", group, down);
7246 $log.log("group unfocused", group);
7247 $log.log("group focused", this.groups[this.index]);
7251 // This is called from the accordion-group directive to add itself to the accordion
7252 this.addGroup = function(groupScope) {
7254 groupScope.index = this.groups.length;
7255 groupScope.focused = false;
7256 this.groups.push(groupScope);
7258 groupScope.$on('$destroy', function(event) {
7259 that.removeGroup(groupScope);
7263 // This is called from the accordion-group directive when to remove itself
7264 this.removeGroup = function(group) {
7265 var index = this.groups.indexOf(group);
7267 this.groups.splice(this.groups.indexOf(group), 1);
7273 // The accordion directive simply sets up the directive controller
7274 // and adds an accordion CSS class to itself element.
7275 .directive('accordion', function() {
7278 controller: 'AccordionController',
7286 template: '<div class="{{cClass}}" ng-transclude></div>',
7287 link:function(scope,elem,attribute,ctrl) {
7289 scope.$watch("expandAll", function(value) {
7292 scope.expandAll=false;
7295 scope.$watch("collapseAll", function(value) {
7298 scope.collapseAll = false;
7305 // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
7306 .directive('accordionGroup', ['$parse', '$transition', '$scrollTo', '$timeout', '$log', '$position', '$window', function($parse, $transition, $scrollTo, $timeout, $log, $position, $window) {
7308 require: ['^accordion', 'accordionGroup'], // We need this directive to be inside an accordion
7310 transclude: true, // It transcludes the contents of the directive into the template
7311 replace: true, // The element containing the directive will be replaced with the template
7312 templateUrl:'app/scripts/ng_js_att_tpls/accordion/accordion.html',
7313 //templateUrl:'app/scripts/ng_js_att_tpls/accordion/accordion_alt.html',
7318 }, // Create an isolated scope and interpolate the heading attribute onto this scope
7319 controller:['$scope', function($scope)
7321 $scope.showico = true;
7322 this.setHeading = function(element)
7324 this.heading = element;
7325 $scope.showico = false;
7327 this.isIsOpen = function()
7329 return $scope.isOpen;
7332 link: function(scope, element, attrs, ctrl) {
7333 var accordionCtrl = ctrl[0];
7334 var accordionGroupCtrl = ctrl[1];
7335 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};
7338 var tab = element.children().eq(0);
7339 var panel = element.children().eq(1);
7341 var handleKeydown = function(ev) {
7342 $log.log("Enter handleKeydown on: ", ev);
7343 var boolFlag = true;
7347 ev.preventDefault();
7354 ev.preventDefault();
7355 $log.log("cycle up");
7356 accordionCtrl.cycle(scope, false);
7361 ev.preventDefault();
7362 $log.log("cycle down");
7363 accordionCtrl.cycle(scope, true);
7367 // if(ev.shiftKey === true)
7369 // $log.log("shift with Tab");
7370 // accordionCtrl.cycle(scope, false);
7374 // accordionCtrl.cycle(scope, true, true);
7382 ev.stopPropagation();
7386 var swallowKeypress = function(e) {
7387 $log.log("keypress", e);
7392 var boolFlag = true;
7403 e.stopPropagation();
7409 // The tab keypress handler must consume pageup and pagedown
7410 // keypresses to prevent Firefox from switching tabs
7411 // on ctrl+pageup and ctrl+pagedown
7418 e.stopPropagation();
7429 if(angular.isUndefined(scope.isOpen)) {
7430 scope.isOpen = false;
7433 panel.bind("keypress", swallowKeypress);
7434 tab.bind("keydown", handleKeydown);
7436 tab.bind("focus", function(ev) {
7437 tab.attr("tabindex", "0");
7440 tab.bind("blur", function(ev) {
7441 if (scope.index !== 0) {
7442 tab.attr("tabindex", "-1");
7446 accordionCtrl.addGroup(scope);
7448 if (scope.index === 0) {
7449 tab.attr("tabindex", "0");
7452 accordionGroupCtrl.toggle = scope.toggle = function() {
7453 scope.isOpen = !scope.isOpen;
7454 accordionCtrl.focus(scope);
7455 if (scope.isOpen === true) {
7456 if (navigator.userAgent.match(/MSIE 8/) === null) {
7457 // $scrollTo(0, $position.offset(element).top, 0.5);
7460 return scope.isOpen;
7463 scope.$watch('isOpen', function(value) {
7465 accordionCtrl.closeOthers(scope);
7469 scope.$watch("focused", function(value) {
7471 $timeout(function() {
7472 tab.attr("tabindex", "0");
7480 // Use accordion-heading below an accordion-group to provide a heading containing HTML
7481 // <accordion-group>
7482 // <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
7483 // </accordion-group>
7485 .directive('accordionToggle',function(){
7488 require: '^accordionGroup',
7493 link: function(scope, element, attr, accordionCtrl)
7496 var setIcon = function(isOpen){
7497 if(scope.expandIcon && scope.collapseIcon)
7500 element.removeClass(scope.expandIcon);
7501 element.addClass(scope.collapseIcon);
7504 element.removeClass(scope.collapseIcon);
7505 element.addClass(scope.expandIcon);
7510 element.bind('click', function()
7512 accordionCtrl.toggle();
7516 scope.$watch(function(){
7517 return accordionCtrl.isIsOpen();
7525 .directive('accordionHeading', function() {
7528 transclude: true, // Grab the contents to be used as the heading
7529 template: '', // In effect remove this element!
7531 require: '^accordionGroup',
7532 compile: function(element, attr, transclude) {
7533 return function link(scope, element, attr, accordionGroupCtrl) {
7534 // Pass the heading to the accordion-group controller
7535 // so that it can be transcluded into the right place in the template
7536 // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
7537 transclude(scope, function(clone) {
7538 element.append(clone);
7539 accordionGroupCtrl.setHeading(element);
7544 // compile: function(element, attr, transclude) {
7545 // return function link(scope, element, attr, accordionGroupCtrl) {
7546 // // Pass the heading to the accordion-group controller
7547 // // so that it can be transcluded into the right place in the template
7548 // // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
7549 // accordionGroupCtrl.setHeading(transclude(scope, function() {
7556 // Use in the accordion-group template to indicate where you want the heading to be transcluded
7557 // You must provide the property on the accordion-group controller that will hold the transcluded element
7558 // <div class="accordion-group">
7559 // <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
7562 .directive('accordionTransclude', function() {
7564 require: '^accordionGroup',
7565 link: function(scope, element, attr, controller) {
7566 scope.$watch(function() {
7567 return controller[attr.accordionTransclude];
7568 }, function(heading) {
7570 element.find("span").eq(0).prepend(heading);
7577 .directive('attGoTop',['$scrollTo', function($scrollTo){
7581 link: function (scope, elem, attrs)
7583 elem.bind('click', function()
7585 $scrollTo(0,attrs["attGoTop"]);
7591 .directive('attGoTo',['$anchorScroll','$location', function($anchorScroll, $location){
7595 link: function (scope, elem, attrs)
7597 elem.bind('click', function()
7599 var newHash = attrs["attGoTo"];
7600 if ($location.hash() !== newHash)
7602 $location.hash(attrs["attGoTo"]);
7613 .directive('freeStanding',function(){
7619 template: "<div><span class='att-accordion__freestanding' ng-show='showAccordion'></span>\n" +
7620 "<div class='section-toggle'>\n" +
7621 "<button class='section-toggle__button' ng-click='fsToggle()'>\n" +
7622 " {{btnText}}<i style='font-size:0.875rem' ng-class='{\"icon-chevron-up\": showAccordion,\"icon-chevron-down\": !showAccordion, }'></i> \n" +
7625 compile: function(element, attr, transclude)
7627 return function link(scope, elem, attrs)
7630 transclude(scope, function(clone)
7632 elem.find("span").append(clone);
7634 scope.showAccordion = false;
7635 scope.btnText = scope.showAccordion? attrs.hideMsg:attrs.showMsg;
7636 scope.fsToggle = function()
7638 scope.showAccordion = !scope.showAccordion;
7639 scope.btnText = scope.showAccordion? attrs.hideMsg:attrs.showMsg;
7646 .directive('expanders',function(){
7651 template:"<div ng-transclude></div>",
7652 controller: ['$scope',function($scope){
7653 var bodyScope = null;
7654 this.setScope = function(scope){
7657 this.toggle = function(){
7658 bodyScope.isOpen = !bodyScope.isOpen;
7659 return bodyScope.isOpen;
7663 link: function(scope, element, attrs, accordionCtrl)
7665 scope.isOpen = false;
7666 element.bind('click', function()
7668 scope.isOpen = !scope.isOpen;
7674 .directive('expanderHeading',function(){
7677 require:"^expanders",
7682 template: "<div style='padding:10px !important' ng-transclude></div>"
7687 .directive('expanderBody',function(){
7691 require:"^expanders",
7695 template: "<div collapse='!isOpen'><div ng-transclude></div></div>",
7696 link:function(scope, elem, attr, myCtrl){
7697 scope.isOpen = false;
7698 myCtrl.setScope(scope);
7703 .directive('expanderToggle',function(){
7707 require:"^expanders",
7712 link: function(scope, element, attr, myCtrl)
7715 var setIcon = function(){
7716 if(scope.expandIcon && scope.collapseIcon)
7719 element.removeClass(scope.expandIcon);
7720 element.addClass(scope.collapseIcon);
7723 element.removeClass(scope.collapseIcon);
7724 element.addClass(scope.expandIcon);
7729 element.bind("keydown", function(e){
7730 if(e.keyCode === 13)
7736 element.bind('click', function()
7741 scope.toggleit = function()
7743 isOpen = myCtrl.toggle();
7752 .directive('collapse', ['$transition', function($transition) {
7753 // CSS transitions don't work with height: auto, so we have to manually change the height to a
7754 // specific value and then once the animation completes, we can reset the height to auto.
7755 // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
7756 // "collapse") then you trigger a change to height 0 in between.
7757 // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
7764 paddingBottom: null,
7776 var fixUpHeight = function(scope, element, height) {
7777 // We remove the collapse CSS class to prevent a transition when we change to height: auto
7778 element.removeClass('collapse');
7779 element.css({ height: height });
7780 //adjusting for any margin or padding
7782 element.css(props.closed);
7784 element.css(props.open);
7786 // It appears that reading offsetWidth makes the browser realise that we have changed the
7787 // height already :-/
7788 var x = element[0].offsetWidth;
7789 element.addClass('collapse');
7793 link: function(scope, element, attrs) {
7795 // alert(element.css("marginTop"));
7797 var initialAnimSkip = true;
7798 scope.$watch(function (){ return element[0].scrollHeight; }, function (value) {
7799 //The listener is called when scrollHeight changes
7800 //It actually does on 2 scenarios:
7801 // 1. Parent is set to display none
7802 // 2. angular bindings inside are resolved
7803 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
7804 if (element[0].scrollHeight !== 0) {
7806 if (initialAnimSkip) {
7807 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
7809 fixUpHeight(scope, element, 'auto');
7815 scope.$watch(attrs.collapse, function(value) {
7824 var currentTransition;
7825 var doTransition = function(change) {
7826 if ( currentTransition ) {
7827 currentTransition.cancel();
7829 currentTransition = $transition(element,change);
7830 currentTransition.then(
7831 function() { currentTransition = undefined; },
7832 function() { currentTransition = undefined; }
7834 return currentTransition;
7837 var expand = function() {
7839 scope.postTransition = true;
7840 if (initialAnimSkip) {
7841 initialAnimSkip = false;
7842 if ( !isCollapsed ) {
7843 fixUpHeight(scope, element, 'auto');
7846 //doTransition({ height : element[0].scrollHeight + 'px' })
7847 doTransition(angular.extend({ height : element[0].scrollHeight + 'px' }, props.open))
7849 // This check ensures that we don't accidentally update the height if the user has closed
7850 // the group while the animation was still running
7853 fixUpHeight(scope, element, 'auto');
7857 isCollapsed = false;
7860 var collapse = function() {
7862 if (initialAnimSkip) {
7863 initialAnimSkip = false;
7864 fixUpHeight(scope, element, 0);
7866 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
7867 //doTransition({'height':'0'}).then(function() {
7868 doTransition(angular.extend({height:0}, props.closed)).then(function() {
7870 scope.postTransition = false;
7877 .directive('attAccord', function(){
7883 controller: 'AttAccordCtrl',
7884 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html',
7885 link: function(scope,element,attr,ctrls){
7889 .controller('AttAccordCtrl', ['$scope', function($scope){
7891 this.type='attAccord';
7896 this.toggleBody = function(){
7900 this.collapseBody();
7905 this.expandBody = function(){
7906 this.bodyCtrl.expand();
7909 this.collapseBody = function(){
7910 this.bodyCtrl.collapse();
7914 .controller('AttAccordHeaderCtrl',['$scope', function($scope){
7917 .directive('attAccordHeader', function(){
7922 require:['^attAccord','attAccordHeader'],
7923 controller: 'AttAccordHeaderCtrl',
7924 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html',
7925 link: function(scope,element,attr, ctrls){
7926 var attAccordCtrl = ctrls[0];
7927 var attAccordHeaderCtrl = ctrls[1];
7928 attAccordCtrl.headerCtrl = attAccordHeaderCtrl;
7930 scope.clickFunc = function(){
7931 attAccordCtrl.toggleBody();
7937 .controller('AttAccordBodyCtrl', ['$scope', function($scope){
7940 this.expand = function(){
7944 this.collapse = function(){
7949 .directive('attAccordBody', ['$timeout', '$height',function($timeout,$height){
7954 require: ['^attAccord','attAccordBody'],
7955 controller: 'AttAccordBodyCtrl',
7956 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordBody.html',
7957 link: function(scope,element,attr,ctrls){
7959 var attAccordCtrl = ctrls[0];
7960 var attAccordBodyCtrl = ctrls[1];
7961 attAccordCtrl.bodyCtrl = attAccordBodyCtrl;
7964 $timeout(function(){
7965 originalHeight = element[0].offsetHeight;
7966 $height(element,0,0,0);
7969 scope.expand = function(){
7970 $height(element,0.05,originalHeight,1);
7973 scope.collapse = function(){
7974 $height(element,0.25,0,0);
7980 angular.module('att.abs.alert', [])
7981 .directive('attAlert', [function()
7988 alertType : "@type",
7989 showTop : "@topPos",
7992 templateUrl : 'app/scripts/ng_js_att_tpls/alert/alert.html',
7993 link: function(scope, elem, attr, ctrl)
7995 if(scope.showTop === 'true'){
7996 scope.cssStyle = {'top':'50px'};
7999 scope.cssStyle = {'top':'0px'};
8001 scope.close = function(){
8002 scope.showAlert = false;
8008 angular.module('att.abs.breadCrumbs', [])
8009 .constant("classConstant",{
8010 "defaultClass" : "breadcrumbs__link",
8011 "activeClass": "breadcrumbs__link--active"
8013 .directive('attCrumb', ['classConstant', function(classConstant)
8020 link: function(scope, elem, attr, ctrl)
8022 elem.addClass(classConstant.defaultClass);
8023 if(attr.attCrumb === 'active'){
8024 elem.addClass(classConstant.activeClass);
8026 if(!elem.hasClass('last')){
8027 elem.append('<i class="breadcrumbs__item"></i>');
8034 angular.module('att.abs.utilities', [])
8036 .filter('highlight', function () {
8037 function escapeRegexp(queryToEscape) {
8038 return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
8040 return function (matchItem, query, className) {
8041 return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
8045 .filter('attLimitTo', function() {
8046 return function(actualArray, _limit, _begin) {
8047 var finalArray = [];
8053 if(actualArray && !isNaN(limit)) {
8054 // finalArray = actualArray.slice(begin, begin+limit);
8055 //slice is not a function. need to find out why 06/17/2015
8056 finalArray = actualArray;
8058 finalArray = actualArray;
8064 .directive('attInputDeny', [function() {
8068 link: function (scope, elem, attr, ctrl) {
8069 var regexExpression = null;
8070 attr.$observe('attInputDeny', function (value) {
8072 regexExpression = new RegExp(value, 'g');
8075 elem.bind('input', function () {
8076 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
8077 if (inputString !== ctrl.$viewValue) {
8078 ctrl.$setViewValue(inputString);
8087 .directive('attAccessibilityClick', [function() {
8090 link: function (scope, elem, attr, ctrl) {
8092 attr.$observe('attAccessibilityClick', function (value) {
8094 keyCode = value.split(',');
8097 elem.bind('keydown', function (ev) {
8098 if(keyCode.length > 0 && ((ev.charCode && keyCode.indexOf(ev.charCode.toString()) > -1) || (ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1) || (ev.which && keyCode.indexOf(ev.which.toString()) > -1))) {
8100 ev.preventDefault();
8107 .directive('attElementFocus', [function() {
8110 link: function(scope, elem, attr, ctrl) {
8111 scope.$watch(attr.attElementFocus, function (value) {
8112 if (value === true) {
8119 .factory('events', function(){
8120 var s = function(e){
8121 if(e.stopPropagation) {
8122 e.stopPropagation();
8124 e.returnValue = false;
8132 .factory('$documentBind', ['$document', '$timeout', function($document, $timeout) {
8133 var _click = function (flag, callbackFunc, scope) {
8134 scope.$watch(flag, function (val) {
8135 $timeout(function () {
8137 $document.bind('click', callbackFunc);
8139 $document.unbind('click', callbackFunc);
8151 String.prototype.toSnakeCase = function () {
8152 return this.replace(/([A-Z])/g, function ($1) {
8153 return "-" + $1.toLowerCase();
8157 var concat = function (character, times) {
8158 character = character || '';
8159 times = (!isNaN(times) && times) || 0;
8161 for (var i = 0; i < times; i++) {
8162 finalChar += character;
8168 var pad = function (actualString, width, character, direction) { // direction: true for left and false for right
8169 actualString = actualString || '';
8170 width = (!isNaN(width) && width) || 0;
8171 character = character || '';
8172 direction = (direction !== undefined && direction) || true;
8174 if (width > actualString.length) {
8176 return concat(character, (width - actualString.length)) + actualString;
8178 return actualString + concat(character, (width - actualString.length));
8181 return actualString;
8184 String.prototype.lPad = function (width, character) {
8185 return pad(this, width, character, true);
8188 String.prototype.rPad = function (width, character) {
8189 return pad(this, width, character, false);
8192 if (!Array.prototype.indexOf) {
8193 Array.prototype.indexOf = function (val) {
8194 for (var index = 0; index < this.length; index++) {
8195 if (this[index] === val) {
8204 angular.module('att.abs.buttons', ['att.abs.position', 'att.abs.utilities'])
8205 .constant('btnConfig', {
8207 btnPrimaryClass: 'button--primary',
8208 btnSecondaryClass: 'button--secondary',
8209 btnDisabledClass: 'button--inactive',
8210 btnSmallClass: 'button--small'
8212 .directive('attButton', ['btnConfig', function(btnConfig) {
8215 link: function (scope, element, attrs, ctrl) {
8216 element.addClass(btnConfig.btnClass);
8217 if (attrs.size === 'small') {
8218 element.addClass(btnConfig.btnSmallClass);
8220 attrs.$observe('btnType', function(value) {
8221 if (value === 'primary') {
8222 element.addClass(btnConfig.btnPrimaryClass);
8223 element.removeClass(btnConfig.btnSecondaryClass);
8224 element.removeClass(btnConfig.btnDisabledClass);
8225 element.removeAttr('disabled');
8226 } else if (value === 'secondary') {
8227 element.addClass(btnConfig.btnSecondaryClass);
8228 element.removeClass(btnConfig.btnPrimaryClass);
8229 element.removeClass(btnConfig.btnDisabledClass);
8230 element.removeAttr('disabled');
8231 } else if (value === 'disabled') {
8232 element.addClass(btnConfig.btnDisabledClass);
8233 element.removeClass(btnConfig.btnPrimaryClass);
8234 element.removeClass(btnConfig.btnSecondaryClass);
8235 element.attr('disabled', 'disabled');
8241 .directive('attButtonLoader', [function () {
8248 template: '<div ng-class="{\'button--loading\': size === \'large\',\'button--loading__small\': size === \'small\'}"><i></i><i></i><i></i></div>',
8249 link: function (scope, element, attrs, ctrl) {
8250 element.addClass('button button--inactive');
8253 }]).directive('attButtonHero', [function () {
8261 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>',
8262 link: function (scope, element, attrs, ctrl) {
8263 element.addClass('button button--hero');
8264 element.attr("tabindex", "0");
8267 }]).directive('attBtnDropdown',['$document', '$isElement', '$documentBind', function($document, $isElement, $documentBind){
8272 type: "@dropdowntype"
8275 template: '<div class="att-btn-dropdown"> <div class="buttons-dropdown--small btn-group" ng-class="{\'open\': isOpen}" ng-click="toggleDropdown($event)"> <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($event)"></div> <div class="circle" ng-click="toggleDropdownCircle($event)"></div> <div class="circle" ng-click="toggleDropdownCircle($event)"></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"> <div ng-transclude> </div> </ul> </div></div>',
8276 link: function(scope,element,attrs){
8278 scope.isOpen = false;
8280 var toggle = scope.toggle = function (show) {
8281 if(show === true || show === false) {
8282 scope.isOpen = show;
8284 scope.isOpen = !scope.isOpen;
8288 scope.toggleDropdownCircle = function($event){
8292 scope.toggleDropdown = function($event){
8296 var outsideClick = function (e) {
8297 var isElement = $isElement(angular.element(e.target), element, $document);
8304 $documentBind.click('isOpen', outsideClick, scope);
8309 angular.module('att.abs.checkbox', [])
8310 .constant("attCheckboxConfig", {
8311 activeClass : "att-checkbox--on",
8312 disabledClass : "att-checkbox--disabled"
8314 .directive('checkboxLimit', ['$compile', "attCheckboxConfig", function ($compile, attCheckboxConfig) {
8322 require:'checkboxLimit',
8323 controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs)
8326 this.getMaxLimits=function(){
8327 return $scope.limit;
8329 this.setMaxLimits=function(value){
8332 this.maxCheckboxSelected=function(){
8333 $scope.maxSelected();
8336 link: function (scope, element, attribute, ctrl) {
8337 scope.$watch('checkboxLimit', function()
8340 for (var keys in scope.checkboxLimit) {
8341 if (scope.checkboxLimit.hasOwnProperty(keys)) {
8342 if (scope.checkboxLimit[keys] === true) {
8343 countTrue = countTrue + 1;
8347 if(countTrue>=parseInt(scope.selectLimit)){
8348 ctrl.setMaxLimits(false);
8351 ctrl.setMaxLimits(true);
8357 .directive('attCheckbox', ['$compile', "attCheckboxConfig", function ($compile, attCheckboxConfig) {
8361 require: ['ngModel','^?checkboxLimit'],
8362 link: function (scope, element, attribute, ctrl) {
8363 var ngCtrl = ctrl[0];
8364 var checkboxLimitCtrl = ctrl[1];
8365 var parentDiv = $compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope);
8366 element.css({display:'none'});
8367 element.wrap(parentDiv);
8368 element.parent().append('<div class="att-checkbox__indicator"></div>');
8369 element.parent().attr("title", attribute.title);
8370 element.parent().attr("id", attribute.id);
8371 element.removeAttr("id");
8373 ngCtrl.$render = function () {
8374 var selected = ngCtrl.$modelValue ? true : false;
8375 element.parent().toggleClass(attCheckboxConfig.activeClass, selected);
8376 element.parent().attr("aria-checked", selected);
8380 scope.updateModel = function (evt) {
8381 if (!scope.disabled) {
8382 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? false : true);
8383 if(checkboxLimitCtrl && !(checkboxLimitCtrl.getMaxLimits())){
8384 if(ngCtrl.$modelValue===false){
8388 checkboxLimitCtrl.maxCheckboxSelected();
8389 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? true : false);
8396 evt.preventDefault();
8399 attribute.$observe('disabled', function(val) {
8400 scope.disabled = (val === true || val === "disabled" || val === "true");
8401 element.parent().toggleClass(attCheckboxConfig.disabledClass, scope.disabled);
8402 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
8407 .directive('checkboxGroup', ['$compile',function($compile) {
8412 checkboxGroupValue: "=?"
8415 link: function(scope, element, attribute, ctrl)
8417 scope.checkboxState = 'none';
8418 scope.checkboxGroupValue="indeterminate";
8419 element.css({display:'none'});
8420 element.wrap($compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope));
8421 element.parent().append('<div class="att-checkbox__indicator"></div>');
8422 element.parent().attr("title", attribute.title);
8423 scope.$watch('checkboxState', function(val) {
8424 if (val === 'all') {
8425 element.parent().addClass('att-checkbox--on');
8426 element.parent().removeClass('att-checkbox--indeterminate');
8427 element.parent().attr("aria-checked", true);
8429 else if (val === 'none') {
8430 element.parent().removeClass('att-checkbox--on');
8431 element.parent().removeClass('att-checkbox--indeterminate');
8432 element.parent().attr("aria-checked", false);
8434 else if (val === 'indeterminate') {
8435 element.parent().removeClass('att-checkbox--on');
8436 element.parent().addClass('att-checkbox--indeterminate');
8437 element.parent().attr("aria-checked", true);
8441 scope.updateModel = function(evt)
8443 if (element.parent().hasClass('att-checkbox--on')) {
8444 element.parent().removeClass('att-checkbox--on');
8445 for (var keys in scope.checkboxGroup) {
8446 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8447 scope.checkboxGroup[keys] = false;
8452 element.parent().addClass('att-checkbox--on');
8453 for (var keys in scope.checkboxGroup) {
8454 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8455 scope.checkboxGroup[keys] = true;
8459 evt.preventDefault();
8461 scope.$watch('checkboxGroupValue', function (value) {
8462 if (value === false) {
8463 element.parent().removeClass('att-checkbox--on');
8464 for (var keys in scope.checkboxGroup) {
8465 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8466 scope.checkboxGroup[keys] = false;
8470 else if (value === true){
8471 element.parent().addClass('att-checkbox--on');
8472 for (var keys in scope.checkboxGroup) {
8473 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8474 scope.checkboxGroup[keys] = true;
8479 scope.$watch('checkboxGroup', function()
8484 for (var keys in scope.checkboxGroup) {
8485 if (scope.checkboxGroup.hasOwnProperty(keys)) {
8487 if (scope.checkboxGroup[keys] === true) {
8488 countTrue = countTrue + 1;
8490 else if (scope.checkboxGroup[keys] === false) {
8491 countFalse = countFalse + 1;
8495 if (count === countTrue) {
8496 scope.checkboxState = "all";
8497 scope.checkboxGroupValue=true;
8499 else if (count === countFalse) {
8500 scope.checkboxState = "none";
8501 scope.checkboxGroupValue=false;
8504 scope.checkboxState = "indeterminate";
8505 scope.checkboxGroupValue="indeterminate";
8512 angular.module('att.abs.colorselector', [])
8513 .directive('colorSelectorWrapper', [function() {
8521 templateUrl: 'app/scripts/ng_js_att_tpls/colorselector/colorselector.html',
8522 link: function(scope, element, attr) {
8523 scope.applycolor = {'background-color': scope.iconColor};
8524 scope.selectedcolor = function(iconColor) {
8525 scope.selected = iconColor;
8530 .directive('colorSelector', ['$compile', function($compile) {
8537 link: function(scope, element, attr) {
8538 element.removeAttr('color-selector');
8539 var wrapcont = angular.element('<color-selector-wrapper selected="ngModel" icon-color="{{colorSelector}}">' + element.prop('outerHTML') + '</color-selector-wrapper>');
8540 var newWrapcont = $compile(wrapcont)(scope);
8541 element.replaceWith(newWrapcont);
8545 angular.module('att.abs.datepicker', ['att.abs.position', 'att.abs.utilities'])
8547 .constant('datepickerConfig', {
8548 dateFormat: 'MM/dd/yyyy',
8550 monthFormat: 'MMMM',
8552 dayHeaderFormat: 'EEEE',
8553 dayTitleFormat: 'MMMM yyyy',
8554 disableWeekend: false,
8555 disableSunday: false,
8561 defaultText: 'Select from list'
8563 datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'mode'],
8564 datepickerWatchAttributes: ['min', 'max']
8567 .factory('datepickerService', ['datepickerConfig', 'dateFilter', function (datepickerConfig, dateFilter) {
8568 var setAttributes = function (attr, elem) {
8569 if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
8570 var attributes = datepickerConfig.datepickerEvalAttributes.concat(datepickerConfig.datepickerWatchAttributes);
8571 for (var key in attr) {
8572 var val = attr[key];
8573 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8574 elem.attr(key.toSnakeCase(), key);
8580 var bindScope = function (attr, scope) {
8581 if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
8582 var evalFunction = function (key, val) {
8583 scope[key] = scope.$parent.$eval(val);
8586 var watchFunction = function (key, val) {
8587 scope.$parent.$watch(val, function (value) {
8590 scope.$watch(key, function (value) {
8591 scope.$parent[val] = value;
8595 var evalAttributes = datepickerConfig.datepickerEvalAttributes;
8596 var watchAttributes = datepickerConfig.datepickerWatchAttributes;
8597 for (var key in attr) {
8598 var val = attr[key];
8599 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8600 evalFunction(key, val);
8601 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
8602 watchFunction(key, val);
8608 var validateDateString = function (dateString, dateFormat) {
8609 if (dateString && dateFormat) {
8611 if (dateFormat.indexOf('/') !== -1) {
8613 } else if (dateFormat.indexOf('-') !== -1) {
8615 } else if (dateFormat.indexOf('.') !== -1) {
8619 var dateStringArray = dateString.split(delimiter);
8620 var dateFormatArray = dateFormat.split(delimiter);
8621 if (dateStringArray.length !== dateFormatArray.length) {
8625 for (var i = 0; i < dateStringArray.length; i++) {
8626 dateStringArray[i] = dateStringArray[i].lPad(dateFormatArray[i].length, '0');
8628 var intermediateDateString = dateStringArray.join(delimiter);
8630 var actualDateString = dateFilter(new Date(intermediateDateString), dateFormat);
8631 if (intermediateDateString === actualDateString) {
8640 setAttributes: setAttributes,
8641 bindScope: bindScope,
8642 validateDateString: validateDateString
8646 .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
8648 date: getValue($attrs.dateFormat, dtConfig.dateFormat),
8649 day: getValue($attrs.dayFormat, dtConfig.dayFormat),
8650 month: getValue($attrs.monthFormat, dtConfig.monthFormat),
8651 year: getValue($attrs.yearFormat, dtConfig.yearFormat),
8652 dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
8653 dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
8654 disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
8655 disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
8657 startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
8658 $scope.mode = getValue($attrs.mode, dtConfig.mode);
8660 $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
8661 $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
8663 function getValue(value, defaultValue) {
8664 return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
8667 function getDaysInMonth(year, month) {
8668 return new Date(year, month, 0).getDate();
8671 function getDates(startDate, n) {
8672 var dates = new Array(n);
8673 var current = startDate, i = 0;
8675 dates[i++] = new Date(current);
8676 current.setDate(current.getDate() + 1);
8681 function isSelected(dt) {
8682 if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
8688 function isFromDate(dt) {
8689 if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
8695 function isToDate(dt) {
8696 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
8702 function isDateRange(dt) {
8703 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
8709 function isWeekend(date) {
8710 if (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday") {
8716 function isToday(date) {
8717 if (compare(date, $scope.resetTime(new Date())) === 0) {
8722 function isFocused(date) {
8723 if (date && angular.isDate($scope.focusedDate) && compare(date, $scope.focusedDate) === 0) {
8729 var isDisabled = this.isDisabled = function(date) {
8730 if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
8733 if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
8736 return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0));
8739 var compare = this.compare = function(date1, date2) {
8740 return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
8744 function isMinDateAvailable(startDate, endDate) {
8745 if(($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime())) {
8753 function isMaxDateAvailable(startDate, endDate) {
8754 if(($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime())) {
8762 function getLabel(label) {
8766 pre: label.substr(0, 3),
8774 function makeDate(date, dayFormat, dayHeaderFormat, isFocused, isSelected, isFromDate, isToDate, isDateRange, isOld, isNew, isDisabled, isToday, isWeekend) {
8775 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};
8781 getVisibleDates: function(date, calendar) {
8782 var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1), lastDayOfMonth = new Date(year, month+1, 0);
8783 var difference = startingDay - firstDayOfMonth.getDay(),
8784 numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
8785 firstDate = new Date(firstDayOfMonth), numDates = 0;
8787 if (numDisplayedFromPreviousMonth > 0) {
8788 firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
8789 numDates += numDisplayedFromPreviousMonth; // Previous
8791 numDates += getDaysInMonth(year, month + 1); // Current
8792 numDates += (7 - numDates % 7) % 7; // Next
8794 var days = getDates(firstDate, numDates), labels = new Array(7);
8795 for (var i = 0; i < numDates; i++) {
8796 var dt = new Date(days[i]);
8797 days[i] = makeDate(dt,
8805 (new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() < new Date(year, month, 1, 0, 0, 0).getTime()),
8806 (new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() > new Date(year, month, 1, 0, 0, 0).getTime()),
8811 for (var j = 0; j < 7; j++) {
8812 labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
8814 if (calendar === 'top') {
8815 $scope.disablePrevTop = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8816 $scope.disableNextTop = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8817 } else if (calendar === 'bottom') {
8818 $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8819 $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8821 $scope.disablePrevTop = $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
8822 $scope.disableNextTop = $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
8824 $scope.disablePrev = $scope.disablePrevTop || $scope.disablePrevBottom;
8825 $scope.disableNext = $scope.disableNextTop || $scope.disableNextBottom;
8826 return {objects: days, title: dateFilter(date, format.dayTitle), labels: labels};
8833 getVisibleDates: function(date, calendar) {
8834 var months = new Array(12), labels = [], year = date.getFullYear(), month = date.getMonth();
8835 for (var i = 0; i < 12; i++) {
8836 var dt = new Date(year,i,1);
8837 months[i] = makeDate(dt,
8852 return {objects: months, title: dateFilter(date, format.year), labels: labels};
8861 .directive('datepicker', ['$timeout', function ($timeout) {
8866 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepicker.html',
8868 currentDate: "=?current",
8871 require: 'datepicker',
8872 controller: 'DatepickerController',
8873 link: function(scope, element, attrs, ctrl) {
8874 var datepickerCtrl = ctrl;
8875 var selected, calendarSelected = false;
8878 scope.resetTime = function(date) {
8880 if (!isNaN(new Date(date))) {
8881 dt = new Date(date);
8882 if(scope.mode === 1){
8883 dt = new Date(dt.getFullYear(), dt.getMonth());
8885 dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
8894 scope.$parent.$watch(attrs.min, function(value) {
8895 scope.minDate = value ? scope.resetTime(value) : null;
8900 scope.$parent.$watch(attrs.max, function(value) {
8901 scope.maxDate = value ? scope.resetTime(value) : null;
8906 // Split array into smaller arrays
8907 function split(arr, size) {
8909 while (arr.length > 0) {
8910 arrays.push(arr.splice(0, size));
8915 function refill(date) {
8916 if (angular.isDate(date) && !isNaN(date)) {
8917 selected = new Date(date);
8920 selected = new Date();
8925 var selectedCalendar;
8926 if(scope.mode === 1){
8927 selected = new Date();
8928 selectedCalendar = moveMonth(angular.copy(selected), -1);
8930 selectedCalendar = angular.copy(selected);
8933 var currentMode = datepickerCtrl.modes[scope.mode];
8934 var currentData = currentMode.getVisibleDates(selectedCalendar, 'top');
8935 scope.currentRows = split(currentData.objects, currentMode.split);
8936 scope.currentTitle = currentData.title;
8937 scope.labels = currentData.labels || [];
8939 var nextData = currentMode.getVisibleDates(moveMonth(angular.copy(selectedCalendar), 1), 'bottom');
8940 scope.nextRows = split(nextData.objects, currentMode.split);
8941 scope.nextTitle = nextData.title;
8945 scope.select = function(date) {
8946 calendarSelected = true;
8948 if(!(angular.isDate(scope.fromDate) && angular.isDate(scope.currentDate))) {
8949 if(angular.isDate(scope.fromDate)) {
8950 selectCurrentDate(date);
8951 } else if(!angular.isDate(scope.fromDate)) {
8952 selectFromDate(date);
8956 selectCurrentDate(date);
8958 scope.focusedDate = date;
8961 var selectCurrentDate = function(date) {
8962 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
8963 scope.currentDate = dt;
8966 var selectFromDate = function(date) {
8967 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
8968 scope.fromDate = dt;
8971 var swapDate = function(fromDate, currentDate) {
8972 selectFromDate(currentDate);
8973 $timeout(function () {
8974 calendarSelected = true;
8975 scope.focusedDate = currentDate;
8976 selectCurrentDate(fromDate);
8979 var moveMonth = function(selectedDate, direction) {
8980 var step = datepickerCtrl.modes[scope.mode].step;
8981 selectedDate.setDate(1);
8982 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
8983 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
8985 return selectedDate;
8988 scope.move = function(direction) {
8989 selected = moveMonth(angular.copy(selected), direction);
8993 scope.$watch('currentDate', function (value) {
8994 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
8995 scope.currentDate = null;
8999 if (!isNaN(value) && !isNaN(scope.fromDate) && datepickerCtrl.compare(value, scope.fromDate) < 0) {
9000 swapDate(scope.fromDate, value);
9004 if (calendarSelected) {
9006 calendarSelected = false;
9008 if (angular.isDefined(value) && value !== null) {
9014 scope.focusedDate = undefined;
9017 scope.$watch('fromDate', function (value) {
9018 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
9019 scope.fromDate = null;
9023 if (!isNaN(scope.currentDate) && !isNaN(value) && datepickerCtrl.compare(scope.currentDate, value) < 0) {
9024 swapDate(value, scope.currentDate);
9027 if (calendarSelected) {
9029 calendarSelected = false;
9031 if (angular.isDefined(value) && value !== null) {
9038 scope.focusedDate = undefined;
9043 .directive('datepickerPopup', ['$document', 'datepickerService', '$isElement', '$documentBind', function($document, datepickerService, $isElement, $documentBind) {
9044 var link = function (scope, elem, attr, ctrl) {
9045 datepickerService.bindScope(attr, scope);
9047 scope.isOpen = false;
9049 var toggle = scope.toggle = function (show) {
9050 if(show === true || show === false) {
9051 scope.isOpen = show;
9053 scope.isOpen = !scope.isOpen;
9057 scope.$watch('current', function () {
9061 var outsideClick = function (e) {
9062 var isElement = $isElement(angular.element(e.target), elem, $document);
9069 $documentBind.click('isOpen', outsideClick, scope);
9076 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html',
9080 compile: function (elem, attr) {
9081 var wrapperElement = elem.find('span').eq(1);
9082 wrapperElement.attr('current', 'current');
9083 datepickerService.setAttributes(attr, wrapperElement);
9090 .directive('attDatepicker', ['$log', function($log) {
9095 controller: ['$scope', '$element', '$attrs', '$compile', 'datepickerConfig', 'datepickerService', function($scope, $element, $attrs, $compile, datepickerConfig, datepickerService) {
9096 var dateFormatString = angular.isDefined($attrs.dateFormat) ? $scope.$parent.$eval($attrs.dateFormat) : datepickerConfig.dateFormat;
9097 var selectedDateMessage = '<div class="sr-focus hidden-spoken" tabindex="-1">the date you selected is {{$parent.current | date : \'' + dateFormatString + '\'}}</div>';
9099 $element.removeAttr('att-datepicker');
9100 $element.removeAttr('ng-model');
9101 $element.attr('ng-model', '$parent.current');
9102 $element.attr('aria-describedby', 'datepicker');
9103 $element.attr('format-date', dateFormatString);
9104 $element.attr('att-input-deny', '[^0-9\/-]');
9105 $element.attr('maxlength', 10);
9107 var wrapperElement = angular.element('<div></div>');
9108 wrapperElement.attr('datepicker-popup', '');
9109 wrapperElement.attr('current', 'current');
9111 datepickerService.setAttributes($attrs, wrapperElement);
9112 datepickerService.bindScope($attrs, $scope);
9114 wrapperElement.html('');
9115 wrapperElement.append($element.prop('outerHTML'));
9116 if (navigator.userAgent.match(/MSIE 8/) === null) {
9117 wrapperElement.append(selectedDateMessage);
9119 var elm = wrapperElement.prop('outerHTML');
9120 elm = $compile(elm)($scope);
9121 $element.replaceWith(elm);
9123 link: function(scope, elem, attr, ctrl) {
9125 $log.error("ng-model is required.");
9126 return; // do nothing if no ng-model
9129 scope.$watch('current', function(value) {
9130 ctrl.$setViewValue(value);
9132 ctrl.$render = function() {
9133 scope.current = ctrl.$viewValue;
9139 .directive('formatDate', ['dateFilter', 'datepickerService', function(dateFilter, datepickerService) {
9143 link: function(scope, elem, attr, ctrl) {
9144 var formatDate = "";
9145 attr.$observe('formatDate', function (value) {
9148 var dateToString = function(value) {
9150 ctrl.$setValidity('invalidDate', true);
9151 return dateFilter(value, formatDate);
9153 ctrl.$setValidity('invalidDate', false);
9157 var stringToDate = function(value) {
9158 if(datepickerService.validateDateString(value, formatDate)) {
9159 ctrl.$setValidity('invalidDate', true);
9160 return new Date(value);
9162 ctrl.$setValidity('invalidDate', false);
9166 ctrl.$formatters.unshift(dateToString);
9167 ctrl.$parsers.unshift(stringToDate);
9172 .directive('attDateFilter', ['$document', 'dateFilter', 'datepickerConfig', 'datepickerService', '$isElement', '$documentBind', function($document, dateFilter, datepickerConfig, datepickerService, $isElement, $documentBind) {
9174 var link = function (scope, elem, attr, ctrl) {
9175 datepickerService.bindScope(attr, scope);
9177 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9178 scope.showDropdownList = false;
9179 scope.showCalendar = false;
9180 scope.applyButtonType = "disabled";
9182 scope.currentSelection = "";
9183 var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : datepickerConfig.dateFormat;
9184 var inputChange = false;
9188 var showDropdown = scope.showDropdown = function (show) {
9189 if(show === true || show === false) {
9190 scope.showDropdownList = show;
9192 scope.showDropdownList = !scope.showDropdownList;
9195 if (!scope.showDropdownList) {
9198 if (scope.currentSelection === 'Custom Single Date' || scope.currentSelection === 'Custom Range') {
9204 var resetTime = scope.resetTime = function(date) {
9206 if (!isNaN(new Date(date))) {
9207 dt = new Date(date);
9211 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9214 var addDays = scope.addDays = function (date, days) {
9216 if (!isNaN(new Date(date)) && !isNaN(days)) {
9217 dt = new Date(date);
9218 dt.setDate(dt.getDate() + days);
9224 var addMonth = scope.addMonth = function (date, months) {
9226 if (!isNaN(new Date(date)) && !isNaN(months)) {
9227 dt = new Date(date);
9228 dt.setMonth(dt.getMonth() + months);
9235 var showCalendar = function() {
9236 scope.showCalendar = true;
9239 var hideCalendar = function() {
9240 scope.showCalendar = false;
9241 if(scope.currentSelection !== 'Custom Single Date' && scope.currentSelection !== 'Custom Range') {
9246 var setDropdownText = function(value) {
9251 var fromDateText = dateFormatString.toUpperCase();
9252 var currentDateText = dateFormatString.toUpperCase();
9254 if(!isNaN(new Date(scope.fromDate))) {
9255 fromDateText = dateFilter(scope.fromDate, dateFormatString);
9257 if(!isNaN(new Date(scope.currentDate))) {
9258 currentDateText = dateFilter(scope.currentDate, dateFormatString);
9261 if(value === 'Custom Single Date') {
9262 ctrl.$setValidity('invalidDate', true);
9263 scope.maxLength = 10;
9264 scope.selectedOption = currentDateText;
9265 } else if(value === 'Custom Range') {
9266 ctrl.$setValidity('invalidDate', true);
9267 ctrl.$setValidity('invalidDateRange', true);
9268 scope.maxLength = 21;
9269 scope.selectedOption = fromDateText + '-' + currentDateText;
9273 scope.getDropdownText = function () {
9275 var dropdownText = scope.selectedOption;
9277 if (scope.currentSelection === 'Custom Single Date') {
9278 if (!isNaN(new Date(dropdownText)) && datepickerService.validateDateString(dropdownText, dateFormatString)) {
9279 ctrl.$setValidity('invalidDate', true);
9280 scope.fromDate = undefined;
9281 scope.currentDate = new Date(dropdownText);
9283 ctrl.$setValidity('invalidDate', false);
9286 } else if (scope.currentSelection === 'Custom Range') {
9287 if (dropdownText.indexOf('-') !== -1 && (dropdownText.split('-').length === 2 || dropdownText.split('-').length === 6)) {
9288 ctrl.$setValidity('invalidDateRange', true);
9289 var resultDropdownText = dropdownText.split('-');
9290 if (resultDropdownText.length === 2) {
9291 resultDropdownText[0] = resultDropdownText[0].trim();
9292 resultDropdownText[1] = resultDropdownText[1].trim();
9293 } else if (resultDropdownText.length === 6) {
9294 var firstDateString = resultDropdownText[0].trim() + '-' + resultDropdownText[1].trim() + '-' + resultDropdownText[2].trim();
9295 var secondDateString = resultDropdownText[3].trim() + '-' + resultDropdownText[4].trim() + '-' + resultDropdownText[5].trim();
9296 resultDropdownText[0] = firstDateString;
9297 resultDropdownText[1] = secondDateString;
9300 if (!isNaN(new Date(resultDropdownText[0])) && !isNaN(new Date(resultDropdownText[1])) && datepickerService.validateDateString(resultDropdownText[0], dateFormatString) && datepickerService.validateDateString(resultDropdownText[1], dateFormatString)) {
9301 ctrl.$setValidity('invalidDate', true);
9302 var fromDate = new Date(resultDropdownText[0]);
9303 var currentDate = new Date(resultDropdownText[1]);
9304 if(fromDate.getTime() < currentDate.getTime()) {
9305 ctrl.$setValidity('invalidDateRange', true);
9306 scope.fromDate = fromDate;
9307 scope.currentDate = currentDate;
9309 ctrl.$setValidity('invalidDateRange', false);
9313 ctrl.$setValidity('invalidDate', false);
9317 ctrl.$setValidity('invalidDateRange', false);
9323 scope.untrackInputChange = function(ev) {
9324 inputChange = false;
9327 scope.selectAdvancedOption = function (value) {
9328 scope.currentSelection = value;
9331 scope.$watch('currentDate', function(val) {
9332 if(!isNaN(new Date(val))) {
9333 scope.applyButtonType = "primary";
9334 setDropdownText(value);
9336 scope.focusApplyButton = true;
9340 scope.$watch('fromDate', function(val) {
9341 if(!isNaN(new Date(val))) {
9342 setDropdownText(value);
9345 if (value === 'Custom Single Date') {
9346 scope.focusSingleDateCalendar = true;
9347 } else if (value === 'Custom Range') {
9348 scope.focusRangeCalendar = true;
9352 scope.resetFocus = function (ev) {
9353 scope.focusSingleDateCalendar = false;
9354 scope.focusRangeCalendar = false;
9355 scope.focusApplyButton = false;
9358 scope.apply = function() {
9359 scope.dateRange.selection = scope.selectedOption;
9360 if(!isNaN(new Date(scope.fromDate))) {
9361 scope.from = scope.fromDate;
9362 scope.dateRange.from = scope.fromDate;
9364 scope.from = undefined;
9365 scope.dateRange.from = undefined;
9367 if(!isNaN(new Date(scope.currentDate))) {
9368 scope.current = scope.currentDate;
9369 scope.dateRange.current = scope.currentDate;
9371 scope.current = undefined;
9372 scope.dateRange.current = undefined;
9378 scope.$watchCollection(function() {
9379 return scope.dateRange;
9380 }, function(value) {
9382 var finalDateRange = angular.copy(value);
9383 ctrl.$setViewValue(finalDateRange);
9387 ctrl.$render = function() {
9388 if (ctrl.$viewValue) {
9389 var inputRange = ctrl.$viewValue;
9390 scope.selectedOption = inputRange.selection;
9391 scope.fromDate = inputRange.from;
9392 scope.currentDate = inputRange.current;
9396 scope.cancel = function() {
9397 scope.currentSelection = "";
9398 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9402 var clear = scope.clear = function(partial) {
9403 scope.fromDate = undefined;
9404 scope.currentDate = undefined;
9405 scope.applyButtonType = "disabled";
9407 ctrl.$setValidity('invalidDate', true);
9408 ctrl.$setValidity('invalidDateRange', true);
9409 setDropdownText(scope.currentSelection);
9413 var outsideClick = function (e) {
9414 var isElement = $isElement(angular.element(e.target), elem, $document);
9416 showDropdown(false);
9421 $documentBind.click('showDropdownList', outsideClick, scope);
9428 current: "=?current"
9431 require: '?ngModel',
9433 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/dateFilter.html',
9434 controller:['$scope', '$element', '$attrs',function($scope, $element, $attrs){
9435 $scope.dateRange = {
9436 selection: undefined,
9440 this.selectOption = function (fromDate,toDate,caption) {
9441 $scope.selectedOption = caption;
9442 $scope.currentSelection =caption;
9443 $scope.dateRange.selection = caption;
9444 $scope.dateRange.current = $scope.resetTime(toDate);
9445 $scope.dateRange.from = $scope.resetTime(fromDate);
9446 $scope.showDropdown();
9448 $scope.checkCurrentSelection=this.checkCurrentSelection = function(value) {
9449 if(value === $scope.currentSelection) {
9455 compile: function(elem, attr) {
9456 var singleDateCalendar = elem.find('span').eq(4);
9457 var rangeCalendar = elem.find('span').eq(5);
9458 rangeCalendar.attr('from', 'fromDate');
9459 singleDateCalendar.attr('current', 'currentDate');
9460 rangeCalendar.attr('current', 'currentDate');
9462 datepickerService.setAttributes(attr, singleDateCalendar);
9463 datepickerService.setAttributes(attr, rangeCalendar);
9469 .directive('attDateFilterList',function(){
9473 fromDate:'=fromDate',
9476 disabled:'=disabled'
9478 require:'^attDateFilter',
9481 templateUrl:'app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html',
9482 link:function(scope,elem,attr,ctrl){
9483 scope.selectOption=function(fromDate,toDate,caption){
9484 ctrl.selectOption(fromDate,toDate,caption);
9486 scope.checkCurrentSelection=ctrl.checkCurrentSelection;
9492 angular.module('att.abs.devNotes', [])
9494 .directive('attDevNotes', function() {
9500 controller: function($scope, $element){
9501 var panes = $scope.panes = [];
9502 $scope.select = function(pane)
9504 angular.forEach(panes, function(pane)
9506 pane.selected = false;
9508 pane.selected = true;
9511 this.addPane = function(pane) {
9512 if (panes.length === 0) $scope.select(pane);
9517 '<ul class="tabs">' +
9518 '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
9519 '<a href="javascript:void(0)" ng-click="select(pane)">{{pane.title}}</a>' +
9522 '<div ng-transclude></div>'+
9528 .directive('pane', function() {
9530 require: '^attDevNotes',
9536 link: function(scope, element, attrs, tabsCtrl) {
9537 tabsCtrl.addPane(scope);
9540 '<div class="tab-pane" ng-class="{active: selected}">' +
9541 '<pre ng-class="{\'language-markup\':title==\'HTML\',\'language-javascript\':title==\'JavaScript\'}" class=" line-numbers">' +
9542 '<code ng-transclude></code>' +
9549 angular.module('att.abs.dividerLines', [])
9550 .directive('attDividerLines', [function()
9554 attDividerLines: '@'
9558 templateUrl: 'app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html',
9559 link: function(scope, element, attribute, ctrl)
9561 scope.lightContainer = attribute.attDividerLines;
9566 angular.module('att.abs.dragdrop', [])
9567 .directive('attFileDrop', ['$parse', function($parse) {
9575 controller: ['$scope', '$attrs', function($scope, $attrs){
9576 if($attrs.attFileDrop!==""){
9577 $scope.onDrop=$scope.attFileDrop;
9580 this.onDrop = $scope.onDrop;
9582 link: function(scope, element, attr, ctrl) {
9584 element.addClass('dragdrop');
9590 if(e.originalEvent){
9591 e.dataTransfer = e.originalEvent.dataTransfer;
9594 e.dataTransfer.dropEffect = 'move';
9595 // allows us to drop
9596 if (e.preventDefault) e.preventDefault();
9597 element.addClass('dragdrop-over');
9605 // allows us to drop
9606 if (e.preventDefault) e.preventDefault();
9607 element.addClass('dragdrop-over');
9615 element.removeClass('dragdrop-over');
9623 // Stops some browsers from redirecting.
9624 if(e.preventDefault) { e.preventDefault(); } ;
9625 if (e.stopPropagation) { e.stopPropagation(); };
9627 if(e.originalEvent){
9628 e.dataTransfer = e.originalEvent.dataTransfer;
9631 element.removeClass('dragdrop-over');
9633 if(e.dataTransfer.files && e.dataTransfer.files.length > 0){
9634 scope.fileModel = e.dataTransfer.files[0];
9637 if(typeof scope.onDrop === "function"){
9638 scope.onDrop = $parse(scope.onDrop);
9648 .directive('attFileLink', [ function() {
9651 require: '^?attFileDrop',
9654 templateUrl: 'app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html',
9660 controller: ['$scope', '$parse', function($scope, $parse){
9662 this.setFileModel= function(fileModel){
9663 if($scope.takeFileModelFromParent){
9664 $scope.$parent.fileModel = fileModel;
9665 $scope.$parent.$apply();
9668 $scope.fileModel = fileModel;
9673 this.callbackFunction= function(){
9674 if(typeof $scope.onFileSelect === "function"){
9675 $scope.onFileSelect = $parse($scope.onFileSelect);
9676 $scope.onFileSelect();
9681 link: function(scope, element, attr, attFileDropCtrl) {
9683 scope.takeFileModelFromParent = false;
9685 if(!(attr.fileModel)){
9686 if(attFileDropCtrl){
9687 scope.takeFileModelFromParent = true;
9691 if(attr.attFileLink!==""){
9692 scope.onFileSelect=scope.attFileLink;
9694 else if(!(attr.onFileSelect)){
9695 if(attFileDropCtrl){
9696 scope.onFileSelect = attFileDropCtrl.onDrop;
9703 .directive('attFileChange', ['$parse', function($parse) {
9706 require: '^attFileLink',
9707 link: function(scope, element, attr, attFileLinkCtrl) {
9711 if(e.target.files && e.target.files.length > 0){
9712 attFileLinkCtrl.setFileModel(e.target.files[0]);
9713 attFileLinkCtrl.callbackFunction();
9716 var strFileName = e.target.value;
9717 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
9719 attFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
9720 attFileLinkCtrl.callbackFunction();
9727 angular.module("att.abs.drawer", [])
9728 .directive('attDrawer', ['$document', '$timeout', function ($document, $timeout) {
9735 drawerAutoClose: "=?"
9737 template: '<div><div class="att-drawer" ng-transclude></div><div ng-class="{\'drawer-backdrop\':drawerOpen}"></div></div>',
9738 link: function ($scope, element, attrs) {
9741 // Override default parameters
9742 param.side = attrs.drawerSlide || 'top';
9743 param.speed = attrs.drawerSpeed || '0.25';
9744 param.size = attrs.drawerSize || '300px';
9745 param.zindex = attrs.drawerZindex || 1000;
9746 param.className = attrs.drawerClass || 'att-drawer';
9748 var slider = element.eq(0).children()[0];
9749 var content = angular.element(slider).children()[0];
9751 slider.className = param.className;
9754 slider.style.transitionDuration = param.speed + 's';
9755 slider.style.webkitTransitionDuration = param.speed + 's';
9756 slider.style.zIndex = param.zindex;
9757 slider.style.position = 'fixed';
9758 slider.style.width = 0;
9759 slider.style.height = 0;
9760 slider.style.transitionProperty = 'width, height';
9762 switch (param.side) {
9764 slider.style.height = attrs.drawerCustomHeight || '100%';
9765 slider.style.top = attrs.drawerCustomTop || '0px';
9766 slider.style.bottom = attrs.drawerCustomBottom || '0px';
9767 slider.style.right = attrs.drawerCustomRight || '0px';
9770 slider.style.height = attrs.drawerCustomHeight || '100%';
9771 slider.style.top = attrs.drawerCustomTop || '0px';
9772 slider.style.bottom = attrs.drawerCustomBottom || '0px';
9773 slider.style.left = attrs.drawerCustomLeft || '0px';
9776 slider.style.width = attrs.drawerCustomWidth || '100%';
9777 slider.style.left = attrs.drawerCustomLeft || '0px';
9778 slider.style.top = attrs.drawerCustomTop || '0px';
9779 slider.style.right = attrs.drawerCustomRight || '0px';
9782 slider.style.width = attrs.drawerCustomWidth || '100%';
9783 slider.style.bottom = attrs.drawerCustomBottom || '0px';
9784 slider.style.left = attrs.drawerCustomLeft || '0px';
9785 slider.style.right = attrs.drawerCustomRight || '0px';
9792 function drawerClose(slider, param) {
9793 if (slider && slider.style.width !== 0 && slider.style.width !== 0){
9794 content.style.display = 'none';
9795 switch (param.side){
9797 slider.style.width = '0px';
9800 slider.style.width = '0px';
9803 slider.style.height = '0px';
9806 slider.style.height = '0px';
9810 $scope.drawerOpen = false;
9814 function drawerOpen(slider, param) {
9815 if (slider.style.width !== 0 && slider.style.width !== 0){
9816 switch (param.side){
9818 slider.style.width = param.size;
9821 slider.style.width = param.size;
9824 slider.style.height = param.size;
9827 slider.style.height = param.size;
9830 $timeout(function() {
9831 content.style.display = 'block';
9832 },(param.speed * 1000));
9837 function isFunction(functionToCheck) {
9839 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
9846 if(attrs.drawerSize) {
9847 $scope.$watch(function() {
9849 return attrs.drawerSize;
9850 }, function(newVal,oldVal) {
9851 param.size = newVal;
9853 if($scope.drawerOpen) {
9854 drawerOpen(slider,param);
9859 $scope.$watch("drawerOpen", function (value){
9862 drawerOpen(slider,param);
9865 drawerClose(slider,param);
9869 // close panel on location change
9870 if($scope.drawerAutoClose) {
9871 $scope.$on("$locationChangeStart", function(){
9872 drawerClose(slider, param);
9873 if(isFunction($scope.drawerAutoClose)) {
9874 $scope.drawerAutoClose();
9877 $scope.$on("$stateChangeStart", function(){
9878 drawerClose(slider, param);
9879 if(isFunction($scope.drawerAutoClose)) {
9880 $scope.drawerAutoClose();
9888 angular.module('att.abs.message', [])
9890 .directive('attMessages', [function() {
9894 controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
9896 $scope.$watchCollection($attrs['for'], function(errors) {
9897 for (var key in errors) {
9898 if (errors[key] === true) {
9902 $scope.error = null;
9905 if ($scope.error === null) {
9906 $scope.messageType = null;
9907 $element.removeAttr('message-type');
9910 this.setMessageType = function(messageType) {
9911 $scope.messageType = messageType;
9913 $scope.$watch('messageType', function(value) {
9914 if (angular.isDefined(value) && value !== null) {
9915 $element.attr('message-type', value);
9922 .directive('attMessage', [function() {
9926 require: '^attMessages',
9927 link: function(scope, elem, attr, ctrl) {
9928 scope.when = attr.when || attr.attMessage;
9929 scope.type = attr.type;
9930 elem.css({display: 'none'});
9931 scope.$parent.$watch('error', function(value) {
9932 if (value === scope.when) {
9933 elem.css({display: 'block'});
9934 ctrl.setMessageType(scope.type);
9936 elem.css({display: 'none'});
9943 angular.module('att.abs.formField', ['att.abs.message'])
9945 .directive('attFormField', [function() {
9949 controller: ['$scope', function($scope) {
9951 link: function(scope, elem, attr, ctrl) {
9952 elem.wrap('<div class="form-field"></div>');
9953 elem.parent().append('<label class="form-field__label">' + attr.placeholder || attr.attFormField + '</label>');
9954 elem.wrap('<div class="form-field-input-container"></div>');
9956 elem.bind('keyup', function() {
9957 if (this.value !== '') {
9958 elem.parent().parent().find('label').addClass('form-field__label--show').removeClass('form-field__label--hide');
9960 elem.parent().parent().find('label').addClass('form-field__label--hide').removeClass('form-field__label--show');
9964 elem.bind('blur', function() {
9965 if (this.value === '') {
9966 elem.parent().parent().find('label').removeClass('form-field__label--hide');
9973 .directive('attFormFieldValidation', ['$compile', '$log', function($compile, $log) {
9978 require: ['?ngModel', '?attFormField'],
9979 link: function(scope, elem, attr, ctrl) {
9980 var ngCtrl = ctrl[0];
9981 var attFormFieldCtrl = ctrl[1];
9985 $log.error("att-form-field-validation :: ng-model directive is required.");
9988 if (!attFormFieldCtrl) {
9989 $log.error("att-form-field-validation :: att-form-field directive is required.");
9993 elem.parent().append($compile(angular.element('<i class="icon-info-alert error" ng-show="valid===false"> </i>'))(scope));
9994 elem.parent().append($compile(angular.element('<i class="icon-info-success success" ng-show="valid===true"> </i>'))(scope));
9996 scope.$watch('valid', function(value) {
9997 if (value === true) {
9998 elem.parent().parent().addClass('success');
9999 } else if (value === false) {
10000 elem.parent().parent().addClass('error');
10002 elem.parent().parent().removeClass('success').removeClass('error');
10006 elem.bind('keyup', function() {
10007 if (ngCtrl.$valid === true) {
10008 scope.valid = true;
10009 } else if (ngCtrl.$invalid === true) {
10010 scope.valid = false;
10020 .directive('attFormFieldValidationAlert', ['$timeout', function($timeout) {
10026 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html',
10027 link: function(scope, elem, attr, ctrl) {
10028 scope.showLabel = false;
10029 scope.hideLabel = false;
10030 scope.errorMessage = false;
10031 scope.warningMessage = false;
10033 var checkMessageType = function() {
10034 if (elem.find('att-messages').attr('message-type') === 'error') {
10035 scope.errorMessage = true;
10036 scope.warningMessage = false;
10037 } else if (elem.find('att-messages').attr('message-type') === 'warning') {
10038 scope.errorMessage = false;
10039 scope.warningMessage = true;
10041 scope.errorMessage = false;
10042 scope.warningMessage = false;
10046 elem.find('label').text(elem.find('input').attr('placeholder'));
10047 elem.find('input').bind('keyup', function() {
10048 if (this.value !== '') {
10049 scope.showLabel = true;
10050 scope.hideLabel = false;
10052 scope.showLabel = false;
10053 scope.hideLabel = true;
10055 checkMessageType();
10059 elem.find('input').bind('blur', function() {
10060 if (this.value === '') {
10061 scope.showLabel = false;
10062 scope.hideLabel = false;
10067 $timeout(function() {
10068 checkMessageType();
10075 angular.module('att.abs.hourpicker', ['att.abs.utilities'])
10076 .constant('hourpickerConfig', {
10077 days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
10078 customOption: 'Custom'
10081 .controller('hourPickerController', ['$scope', function($scope) {
10083 $scope.options = [];
10085 function(value, fromtime, totime, preselect, uncheckedFromTime,uncheckedToTime) {
10087 $scope.options.push(value);
10088 if (preselect !== undefined) {
10089 $scope.preselect = preselect;
10092 if (fromtime !== undefined) {
10093 $scope.fromtime = fromtime;
10094 for (var daycount in $scope.days) {
10095 $scope.FrtimeList[$scope.days[daycount]] = {};
10097 if(uncheckedFromTime !== undefined){
10098 $scope.FrtimeList[$scope.days[daycount]].value = uncheckedFromTime;
10099 $scope.selectedFromOption[$scope.days[daycount]] = uncheckedFromTime;
10101 $scope.FrtimeList[$scope.days[daycount]].value = fromtime[0].value;
10102 $scope.selectedFromOption[$scope.days[daycount]] = fromtime[0].value;
10106 if (totime !== undefined) {
10107 $scope.totime = totime;
10108 for (var daycount in $scope.days) {
10109 $scope.TotimeList[$scope.days[daycount]] = {};
10111 if(uncheckedToTime !== undefined){
10112 $scope.TotimeList[$scope.days[daycount]].value = uncheckedToTime;
10113 $scope.selectedToOption[$scope.days[daycount]] = uncheckedToTime;
10115 $scope.TotimeList[$scope.days[daycount]].value = totime[0].value;
10116 $scope.selectedToOption[$scope.days[daycount]] = totime[0].value;
10122 if(uncheckedFromTime !== undefined)
10123 $scope.uncheckedFromTime = uncheckedFromTime;
10125 if(uncheckedToTime !== undefined)
10126 $scope.uncheckedToTime = uncheckedToTime;
10130 .directive('attHourpickerOption', [function() {
10133 require: '^attHourpicker',
10136 fromtime: "=fromtime",
10138 preselect: "=preselect",
10139 uncheckedFromTime: "=",
10140 uncheckedToTime: "="
10142 link: function(scope, element, attr, ctrl) {
10143 ctrl.setOptions(scope.option,
10147 scope.uncheckedFromTime,
10148 scope.uncheckedToTime);
10153 .directive('attHourpicker', ["hourpickerConfig", "$document", "$log", "$documentBind", "$timeout", function(hourpickerConfig, $document, $log, $documentBind, $timeout) {
10155 require: 'ngModel',
10157 controller: 'hourPickerController',
10163 templateUrl: 'app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html',
10164 link: function(scope, element, attr, ctrl) {
10166 scope.isFromDropDownOpen = false;
10167 scope.isToDropDownOpen = false;
10168 var dropDownOpenValue = "";
10170 scope.days = hourpickerConfig.days;
10171 scope.daysList = {};
10172 scope.FrtimeList = {};
10173 scope.FrtimeListDay = {};
10174 scope.TotimeListDay = {};
10175 scope.selectedFromOption = {};
10176 scope.selectedToOption = {};
10177 scope.TotimeList = {};
10178 scope.selectedIndex = 0;
10179 scope.selectedOption = "Select from list";
10180 scope.customTime = [];
10182 scope.resetFlag = false;
10184 scope.$watch('resetFlag', function(newVal, oldVal){
10185 if(newVal !== oldVal){
10186 if( newVal === true && scope.selectedOption === hourpickerConfig.customOption ){
10187 //disable and reset all days checkbox
10188 for (day in scope.daysList) {
10189 scope.daysList[day] = false;
10190 scope.addSelectedValue(day);
10192 scope.preselectUpdateFxn(scope.preselect);
10194 scope.resetFlag = false;
10198 scope.$watch('selCategory', function(value) {
10200 ctrl.$setViewValue(value);
10203 scope.$watch('model', function(value,oldValue) {
10204 if (value && oldValue && angular.toJson(value) !== angular.toJson(oldValue)) {
10205 scope.updateData(value)
10208 scope.updateData = function(value)
10210 if (value.constructor === Array) {
10211 scope.showDaysSelector = true;
10212 scope.selectedOption = hourpickerConfig.customOption;
10213 for (var arry in value) {
10214 var day = value[arry].day;
10215 scope.daysList[day] = true;
10217 for (var fromcount in scope.fromtime) {
10218 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
10219 scope.FrtimeList[day].value = scope.fromtime[fromcount].value;
10220 scope.selectedFromOption[day] = scope.FrtimeList[day].value;
10223 for (var tocount in scope.totime) {
10224 if (scope.totime[tocount].value === value[arry].ToTime) {
10225 scope.TotimeList[day].value = scope.totime[tocount].value;
10226 scope.selectedToOption[day] = scope.TotimeList[day].value;
10229 scope.addSelectedValue(day, value[arry].FromTime, value[arry].ToTime);
10231 if (parseInt(arry) + 1 === value.length) {
10237 scope.selectOption(value.day);
10241 scope.$watch('preselect', function(value) {
10242 scope.preselectUpdateFxn(value);
10245 scope.preselectUpdateFxn = function(value){
10246 if (value !== undefined) {
10249 value = scope.validatePreselectData(value);
10251 if (value === "") {
10254 scope.updateData(value);
10258 scope.validatePreselectData = function(value)
10260 if (value.constructor === Array) {
10261 for (var arry in value) {
10262 var day = value[arry].day;
10263 var isDayFound = false;
10264 var isFrmFound = false;
10265 var isToFound = false;
10266 for (var daycount in scope.days) {
10267 if (scope.days[daycount] === day) {
10273 value.splice(arry, 1);
10276 for (var fromcount in scope.fromtime) {
10277 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
10283 value[arry].FromTime = scope.fromtime[0].value;
10285 for (var tocount in scope.totime) {
10286 if (scope.totime[tocount].value === value[arry].ToTime) {
10292 value[arry].ToTime = scope.totime[0].value;
10295 if (parseInt(arry) + 1 === value.length) {
10301 var isOptionFound = false;
10302 for (var optcount in scope.options) {
10303 if (scope.options[optcount] === value.day) {
10304 isOptionFound = true;
10308 if (!isOptionFound) {
10315 scope.selectPrevNextValue = function($event, arrayValues, currValue) {
10319 if ($event.keyCode === 38) {
10321 } else if ($event.keyCode === 40) {
10327 if (arrayValues.indexOf(currValue) !== -1) {
10328 index = arrayValues.indexOf(currValue) + value;
10330 for (var count in arrayValues) {
10331 if (arrayValues[count].value === currValue) {
10332 index = parseInt(count) + value;
10338 if (index === arrayValues.length) {
10340 } else if (index === -1) {
10344 $event.preventDefault();
10345 if (arrayValues[index].value)
10346 return arrayValues[index].value;
10348 return arrayValues[index];
10351 scope.showDropdown = function()
10353 scope.showlist = !scope.showlist;
10357 scope.showfromDayDropdown = function(value)
10359 //close dropdown if any other From drop down is opened
10360 for (count in scope.FrtimeListDay) {
10361 if (count !== value && scope.FrtimeListDay[count] === true) {
10362 scope.FrtimeListDay[count] = false;
10365 for (count in scope.TotimeListDay) {
10366 if (scope.TotimeListDay[count] === true) {
10367 scope.TotimeListDay[count] = false;
10370 scope.FrtimeListDay[value] = !scope.FrtimeListDay[value];
10372 scope.showlist = false;
10374 //save model value so we can close current dropdown on click of other part of the document
10375 if (scope.FrtimeListDay[value]) {
10376 scope.isFromDropDownOpen = true;
10377 dropDownOpenValue = value;
10380 scope.isFromDropDownOpen = false;
10383 $timeout(function () {
10384 if(scope.FrtimeListDay[value]){
10385 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
10386 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
10387 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
10388 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
10394 scope.showtoDayDropdown = function(value)
10396 //close dropdown if any other To drop down is opened
10397 for (count in scope.TotimeListDay) {
10398 if (count !== value && scope.TotimeListDay[count] === true) {
10399 scope.TotimeListDay[count] = false;
10402 for (count in scope.FrtimeListDay) {
10403 if (scope.FrtimeListDay[count] === true) {
10404 scope.FrtimeListDay[count] = false;
10407 scope.TotimeListDay[value] = !scope.TotimeListDay[value];
10409 scope.showlist = false;
10411 //save model value so we can close current dropdown on click of other part of the document
10412 if (scope.TotimeListDay[value]) {
10413 scope.isToDropDownOpen = true;
10414 dropDownOpenValue = value;
10417 scope.isToDropDownOpen = false;
10420 $timeout(function () {
10421 if(scope.FrtimeListDay[value]){
10422 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
10423 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
10424 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
10425 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
10431 scope.selectFromDayOption = function(day, value)
10433 scope.selectedFromOption[day] = value;
10434 scope.FrtimeList[day].value = value;
10435 scope.FrtimeListDay[day] = false;
10436 scope.isFromDropDownOpen = false;
10439 scope.selectToDayOption = function(day, value)
10441 scope.selectedToOption[day] = value;
10442 scope.TotimeList[day].value = value;
10443 scope.TotimeListDay[day] = false;
10444 scope.isToDropDownOpen = false;
10447 scope.addSelectedValue = function(value, fromtime, totime)
10449 if (scope.daysList[value] !== undefined && !scope.daysList[value]) {
10451 for (var count = 0, len = scope.customTime.length; count < len; count++) {
10452 if (scope.customTime[count].day === value) {
10454 if(scope.uncheckedFromTime)
10455 scope.selectedFromOption[scope.customTime[count].day] = scope.uncheckedFromTime;
10457 scope.selectedFromOption[scope.customTime[count].day] = scope.FrtimeList[scope.customTime[count].day].value;
10459 if(scope.uncheckedToTime)
10460 scope.selectedToOption[scope.customTime[count].day] = scope.uncheckedToTime;
10462 scope.selectedToOption[scope.customTime[count].day] = scope.TotimeList[scope.customTime[count].day].value;
10464 scope.customTime.splice(count, 1);
10472 if(scope.selectedFromOption[value] == scope.uncheckedFromTime){
10473 scope.selectedFromOption[value] = scope.fromtime[0].value;
10474 fromtime = scope.fromtime[0].value;
10475 scope.FrtimeList[value].value = scope.fromtime[0].value;
10478 if(scope.selectedToOption[value] == scope.uncheckedToTime){
10479 scope.selectedToOption[value]= scope.totime[0].value;
10480 totime = scope.totime[0].value;
10481 scope.TotimeList[value].value = scope.totime[0].value;
10484 custTime["day"] = value;
10485 custTime["FromTime"] = scope.FrtimeList[value].value;
10486 custTime["ToTime"] = scope.TotimeList[value].value;
10488 var count = 0, len = scope.customTime.length;
10489 for (; count < len; count++) {
10490 if (scope.customTime[count].day === value) {
10491 scope.customTime[count].FromTime = custTime["FromTime"];
10492 scope.customTime[count].ToTime = custTime["ToTime"];
10496 if (count === len) {
10497 var x = angular.copy(custTime);
10498 scope.customTime.push(x);
10501 scope.selCategory = scope.customTime;
10505 var outsideClick = function(e) {
10506 if (scope.showlist) {
10507 scope.$apply(function() {
10508 scope.showlist = false;
10513 $documentBind.click('showlist', outsideClick, scope);
10515 var outsideClickFromDropdown = function(e) {
10516 scope.$apply(function() {
10517 if (scope.isFromDropDownOpen) {
10518 scope.FrtimeListDay[dropDownOpenValue] = false;
10519 scope.isFromDropDownOpen = false;
10524 $documentBind.click('isFromDropDownOpen', outsideClickFromDropdown, scope);
10526 var outsideClickToDropdown = function(e) {
10527 scope.$apply(function() {
10528 if (scope.isToDropDownOpen) {
10529 scope.TotimeListDay[dropDownOpenValue] = false;
10530 scope.isToDropDownOpen = false;
10535 $documentBind.click('isToDropDownOpen', outsideClickToDropdown, scope);
10537 scope.selectOption = function(sItem)
10540 if (sItem === hourpickerConfig.customOption) {
10541 scope.showDaysSelector = true;
10542 scope.selCategory = scope.customTime;
10544 scope.showDaysSelector = false;
10545 var fromTime = /[0-9]\s?am/i.exec(sItem);
10546 var toTime = /[0-9]\s?pm/i.exec(sItem);
10547 scope.selCategory = {day: sItem, FromTime: fromTime === null ? 'NA' : fromTime[0], ToTime: toTime === null ? 'NA' : toTime[0]};
10550 scope.showlist = false;
10552 scope.selectedOption = sItem;
10558 angular.module('att.abs.iconButtons', [])
10560 .constant('buttonConfig', {
10561 activeClass: 'active--button',
10562 toggleEvent: 'click'
10565 .directive('attIconBtnRadio', ['buttonConfig', function(buttonConfig) {
10566 var activeClass = buttonConfig.activeClass || 'active--button';
10567 var toggleEvent = buttonConfig.toggleEvent || 'click';
10570 require: 'ngModel',
10571 link: function(scope, element, attrs, ngModelCtrl) {
10573 element.attr("role","button");
10574 element.attr("tabindex","0");
10575 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnRadio+"</span>");
10578 ngModelCtrl.$render = function() {
10579 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, attrs.attIconBtnRadio));
10580 /*if(ngModelCtrl.$modelValue!==undefined){
10581 if (angular.equals(ngModelCtrl.$modelValue, attrs.attIconBtnRadio)) {
10582 element.attr("aria-selected", true);
10585 element.attr("aria-selected", false);
10591 element.parent().bind(toggleEvent, function() {
10592 if (!element.parent().hasClass(activeClass)) {
10593 scope.$apply(function() {
10594 ngModelCtrl.$setViewValue(attrs.attIconBtnRadio);
10595 ngModelCtrl.$render();
10604 .directive('attIconBtnCheckbox', ['buttonConfig', function(buttonConfig) {
10605 var activeClass = buttonConfig.activeClass || 'active--button';
10606 var toggleEvent = buttonConfig.toggleEvent || 'click';
10609 require: 'ngModel',
10610 link: function(scope, element, attrs, ngModelCtrl) {
10612 element.attr("role","button");
10613 element.attr("tabindex","0");
10614 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnCheckbox+"</span>");
10616 function getTrueValue() {
10617 var trueValue = scope.$eval(attrs.btnCheckboxTrue);
10618 return angular.isDefined(trueValue) ? trueValue : true;
10621 function getFalseValue() {
10622 var falseValue = scope.$eval(attrs.btnCheckboxFalse);
10623 return angular.isDefined(falseValue) ? falseValue : false;
10627 ngModelCtrl.$render = function() {
10628 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
10629 /*if(ngModelCtrl.$modelValue!==undefined){
10630 if ((angular.equals(ngModelCtrl.$modelValue, getTrueValue()))) {
10631 element.attr("aria-selected", true);
10634 element.attr("aria-selected", false);
10640 element.parent().bind(toggleEvent, function() {
10641 scope.$apply(function() {
10642 ngModelCtrl.$setViewValue(element.parent().hasClass(activeClass) ? getFalseValue() : getTrueValue());
10643 ngModelCtrl.$render();
10650 angular.module('att.abs.links', [])
10651 .directive('attLink', ['$compile',function($compile) {
10654 link: function(scope, elem, attr) {
10655 elem.addClass('link');
10656 if(!(elem.attr('href'))){
10657 elem.attr("tabindex", "0");
10662 .directive('attLinkVisited', ['$compile',function($compile) {
10665 link: function(scope, elem, attr) {
10666 elem.addClass('link--visited');
10667 if(!(elem.attr('href'))){
10668 elem.attr("tabindex", "0");
10673 .directive('attReadmore', ['$timeout',function($timeout) {
10677 lines:"@noOfLines",
10679 isOpen: "=" //attribute to use readmore inside accordion
10681 templateUrl: 'app/scripts/ng_js_att_tpls/links/readMore.html',
10682 link: function(scope, elem, attr, ctrl) {
10684 scope.$watch('textModel', function(val){
10686 scope.textToDisplay = '';
10687 scope.readMoreLink = false;
10688 scope.readLessLink = false;
10689 scope.readFlag = false;
10692 if (typeof String.prototype.trim !== 'function') {
10693 String.prototype.trim = function() {
10694 return this.replace(/^\s+|\s+$/g, '');
10697 scope.textToDisplay = val.trim();
10698 scope.readFlag = true;
10699 $timeout(function() {
10700 var readElem = elem[0].children[0].children[0];
10702 if(window.getComputedStyle){
10703 height = parseInt(scope.lines) * parseFloat(window.getComputedStyle(readElem,null).getPropertyValue("height"));
10706 height = parseInt(scope.lines) * parseFloat(readElem.currentStyle.height);
10708 scope.elemHeight = height;
10709 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
10712 scope.readMoreLink = true;
10713 scope.readLessLink = false;
10717 // Code to use readmore inside accordion
10718 var parentElem = elem.parent();
10719 if (parentElem.hasClass('att-accordion__body')) {
10720 scope.$watch('isOpen', function(val) {
10727 scope.readMore = function() {
10728 scope.readMoreLink = false;
10729 scope.readLessLink = true;
10730 scope.readLinkStyle = {'height': 'auto'};
10731 scope.readFlag = false;
10734 scope.readLess = function() {
10735 scope.readMoreLink = true;
10736 scope.readLessLink = false;
10737 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
10738 scope.readFlag = true;
10743 .directive('attLinksList', [function() {
10746 controller: function() {
10748 link: function(scope, elem, attr) {
10749 elem.addClass('links-list');
10753 .directive('attLinksListItem', ['$compile',function($compile) {
10756 require: '^attLinksList',
10757 link: function(scope, elem, attr, attLinksListCtrl) {
10758 elem.addClass('links-list__item');
10759 if(!(elem.attr('href'))){
10760 elem.attr("tabindex", "0");
10766 angular.module('att.abs.loading', [])
10767 .directive('attLoading', [
10773 icon: '@attLoading',
10774 progressStatus: '=?',
10777 templateUrl: 'app/scripts/ng_js_att_tpls/loading/loading.html',
10778 link: function(scope, element, attr) {
10779 var progressvalue = scope.progressStatus;
10780 scope.progressStatus = Math.min(100, Math.max(0, progressvalue));
10781 if(navigator.userAgent.indexOf("MSIE 8.")!=-1){
10783 shiftY = scope.progressStatus * 36;
10785 if (element.hasClass('att-loading--blue')) {
10788 else if (element.hasClass('att-loading--white')) {
10791 //element.eq(1).children().find('att-loading-inset__percentage').html(scope.progressStatus);
10793 'background-position-x' : shiftX,
10794 'background-position-y' : -shiftY
10804 angular.module('att.abs.modal', [])
10806 * A helper, internal data structure that acts as a map but also allows getting / removing
10807 * elements in the LIFO order
10809 .factory('$$stackedMap', function () {
10811 createNew: function () {
10815 add: function (key, value) {
10821 get: function (key) {
10822 for (var i = 0; i < stack.length; i++) {
10823 if (key == stack[i].key) {
10830 for (var i = 0; i < stack.length; i++) {
10831 keys.push(stack[i].key);
10836 return stack[stack.length - 1];
10838 remove: function (key) {
10840 for (var i = 0; i < stack.length; i++) {
10841 if (key == stack[i].key) {
10846 return stack.splice(idx, 1)[0];
10848 removeTop: function () {
10849 return stack.splice(stack.length - 1, 1)[0];
10851 length: function () {
10852 return stack.length;
10860 * A helper directive for the $modal service. It creates a backdrop element.
10862 .directive('modalBackdrop', ['$timeout', function ($timeout) {
10866 templateUrl: 'app/scripts/ng_js_att_tpls/modal/backdrop.html',
10867 link: function (scope) {
10868 scope.animate = false;
10869 //trigger CSS transitions
10870 $timeout(function () {
10871 scope.animate = true;
10877 .directive('modalWindow', ['$modalStack','$timeout','$document', function ($modalStack,$timeout,$document) {
10885 templateUrl: 'app/scripts/ng_js_att_tpls/modal/window.html',
10886 link: function (scope, element, attrs) {
10887 scope.windowClass = attrs.windowClass || '';
10890 $timeout(function () {
10891 // trigger CSS transitions
10892 scope.focusModalFlag=true;
10893 scope.animate = true;
10896 $document.on('focus keydown', function(e) {
10897 if (e.which ===9) {
10898 String.prototype.contains = function(it) { return this.indexOf(it) != -1; };
10899 if (element[0] !== e.target && !element[0].contains( e.target )) {
10900 element[0].focus();
10904 scope.close = function (evt) {
10905 var modal = $modalStack.getTop();
10906 if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
10907 // Check if preventDefault exists due to lack of support for IE8
10908 if (evt.preventDefault) {
10909 evt.preventDefault();
10910 evt.stopPropagation();
10912 evt.returnValue = false;
10915 $modalStack.dismiss(modal.key, 'backdrop click');
10922 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap',
10923 function ($document, $compile, $rootScope, $$stackedMap) {
10925 var OPENED_MODAL_CLASS = 'modal-open';
10927 var backdropjqLiteEl, backdropDomEl;
10928 var backdropScope = $rootScope.$new(true);
10929 var openedWindows = $$stackedMap.createNew();
10930 var $modalStack = {};
10932 function backdropIndex() {
10933 var topBackdropIndex = -1;
10934 var opened = openedWindows.keys();
10935 for (var i = 0; i < opened.length; i++) {
10936 if (openedWindows.get(opened[i]).value.backdrop) {
10937 topBackdropIndex = i;
10940 return topBackdropIndex;
10943 $rootScope.$watch(backdropIndex, function(newBackdropIndex){
10944 backdropScope.index = newBackdropIndex;
10947 function removeModalWindow(modalInstance) {
10949 var body = $document.find('body').eq(0);
10950 var modalWindow = openedWindows.get(modalInstance).value;
10952 //clean up the stack
10953 openedWindows.remove(modalInstance);
10955 //remove window DOM element
10956 modalWindow.modalDomEl.remove();
10957 body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
10959 //remove backdrop if no longer needed
10960 if (backdropDomEl && backdropIndex() == -1) {
10961 backdropDomEl.remove();
10962 backdropDomEl = undefined;
10966 modalWindow.modalScope.$destroy();
10969 $document.bind('keydown', function (evt) {
10972 if (evt.which === 27) {
10973 modal = openedWindows.top();
10974 if (modal && modal.value.keyboard) {
10975 $rootScope.$apply(function () {
10976 $modalStack.dismiss(modal.key);
10982 $modalStack.open = function (modalInstance, modal) {
10984 openedWindows.add(modalInstance, {
10985 deferred: modal.deferred,
10986 modalScope: modal.scope,
10987 backdrop: modal.backdrop,
10988 keyboard: modal.keyboard
10991 var body = $document.find('body').eq(0);
10993 if (backdropIndex() >= 0 && !backdropDomEl) {
10994 backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
10995 backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
10996 body.append(backdropDomEl);
10999 var angularDomEl = angular.element('<div modal-window></div>');
11000 angularDomEl.attr('window-class', modal.windowClass);
11001 angularDomEl.attr('index', openedWindows.length() - 1);
11002 angularDomEl.html(modal.content);
11004 var modalDomEl = $compile(angularDomEl)(modal.scope);
11005 openedWindows.top().value.modalDomEl = modalDomEl;
11006 body.append(modalDomEl);
11007 body.addClass(OPENED_MODAL_CLASS);
11010 $modalStack.close = function (modalInstance, result) {
11011 var modal = openedWindows.get(modalInstance);
11013 modal.value.deferred.resolve(result);
11014 removeModalWindow(modalInstance);
11018 $modalStack.dismiss = function (modalInstance, reason) {
11019 var modalWindow = openedWindows.get(modalInstance).value;
11021 modalWindow.deferred.reject(reason);
11022 removeModalWindow(modalInstance);
11026 $modalStack.getTop = function () {
11027 return openedWindows.top();
11030 return $modalStack;
11033 .provider('$modal', function () {
11035 var $modalProvider = {
11037 backdrop: true, //can be also false or 'static'
11040 $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
11041 function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
11045 function getTemplatePromise(options) {
11046 return options.template ? $q.when(options.template) :
11047 $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
11048 return result.data;
11052 function getResolvePromises(resolves) {
11053 var promisesArr = [];
11054 angular.forEach(resolves, function (value, key) {
11055 if (angular.isFunction(value) || angular.isArray(value)) {
11056 promisesArr.push($q.when($injector.invoke(value)));
11059 return promisesArr;
11062 $modal.open = function (modalOptions) {
11064 var modalResultDeferred = $q.defer();
11065 var modalOpenedDeferred = $q.defer();
11067 //prepare an instance of a modal to be injected into controllers and returned to a caller
11068 var modalInstance = {
11069 result: modalResultDeferred.promise,
11070 opened: modalOpenedDeferred.promise,
11071 close: function (result) {
11072 $modalStack.close(modalInstance, result);
11074 dismiss: function (reason) {
11075 $modalStack.dismiss(modalInstance, reason);
11079 //merge and clean up options
11080 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
11081 modalOptions.resolve = modalOptions.resolve || {};
11084 if (!modalOptions.template && !modalOptions.templateUrl) {
11085 throw new Error('One of template or templateUrl options is required.');
11088 var templateAndResolvePromise =
11089 $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
11092 templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
11094 var modalScope = (modalOptions.scope || $rootScope).$new();
11095 modalScope.$close = modalInstance.close;
11096 modalScope.$dismiss = modalInstance.dismiss;
11098 var ctrlInstance, ctrlLocals = {};
11099 var resolveIter = 1;
11102 if (modalOptions.controller) {
11103 ctrlLocals.$scope = modalScope;
11104 ctrlLocals.$modalInstance = modalInstance;
11105 angular.forEach(modalOptions.resolve, function (value, key) {
11106 ctrlLocals[key] = tplAndVars[resolveIter++];
11109 ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
11112 $modalStack.open(modalInstance, {
11114 deferred: modalResultDeferred,
11115 content: tplAndVars[0],
11116 backdrop: modalOptions.backdrop,
11117 keyboard: modalOptions.keyboard,
11118 windowClass: modalOptions.windowClass
11121 }, function resolveError(reason) {
11122 modalResultDeferred.reject(reason);
11125 templateAndResolvePromise.then(function () {
11126 modalOpenedDeferred.resolve(true);
11128 modalOpenedDeferred.reject(false);
11131 return modalInstance;
11138 return $modalProvider;
11141 .directive("simpleModal", ["$modal", "$log", '$scrollTo', function($modal, $log, $scrollTo) {
11153 link: function(scope, elm, attr) {
11154 elm.bind('click', function(ev) {
11155 var currentPosition = ev.pageY - ev.clientY;
11156 ev.preventDefault();
11157 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
11158 scope.simpleModal = elm.attr("href");
11160 scope.backdrop === "false" ? scope.backdropclick='static':scope.backdropclick=true;
11161 scope.keyboard === "false" ? scope.keyboardev=false:scope.keyboardev=true;
11163 templateUrl: scope.simpleModal,
11164 backdrop:scope.backdropclick,
11165 keyboard:scope.keyboardev,
11166 windowClass:scope.windowClass,
11167 controller: scope.controller
11168 }).result.then(scope.modalOk, scope.modalCancel);
11174 angular.module('att.abs.pagination', ['att.abs.utilities'])
11175 .directive('attPagination', ['$timeout', function($timeout) {
11185 templateUrl: 'app/scripts/ng_js_att_tpls/pagination/pagination.html',
11186 link: function(scope, elem, attr, ctrl) {
11189 scope.$watch('totalPages', function(value) {
11190 if(angular.isDefined(value) && value !== null){
11193 scope.totalPages = 1;
11198 for (var i = 1; i <= value; i++) {
11199 scope.pages.push(i);
11201 } else if (value > 7) {
11202 var midVal = Math.ceil(value / 2);
11203 scope.pages = [midVal - 1, midVal, midVal + 1];
11206 currentPageChanged(1);
11210 scope.$watch('currentPage', function(value) {
11211 currentPageChanged(value);
11214 function currentPageChanged(value) {
11215 if (angular.isDefined(value) && value !== null) {
11218 } else if (!angular.isNumber(value)) {
11219 value = parseInt(value, 10);
11222 if (value > scope.totalPages) {
11223 value = scope.totalPages;
11224 } else if (value < 1) {
11228 if(scope.currentPage !== value) {
11229 scope.currentPage = value;
11230 callbackHandler(scope.currentPage);
11233 if (scope.totalPages > 7) {
11234 if (value < scope.pages[0] && value > 3) {
11235 scope.pages = [value, value + 1, value + 2];
11236 } else if (value > scope.pages[2] && value < scope.totalPages - 2) {
11237 scope.pages = [value - 2, value - 1, value];
11238 } else if (value <= 3) {
11239 scope.pages = [1, 2, 3];
11240 } else if (value >= scope.totalPages - 2) {
11241 scope.pages = [scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
11247 scope.next = function(event) {
11248 event.preventDefault();
11249 if (scope.currentPage < scope.totalPages) {
11250 scope.currentPage += 1;
11251 callbackHandler(scope.currentPage);
11255 scope.prev = function(event) {
11256 event.preventDefault();
11257 if (scope.currentPage > 1) {
11258 scope.currentPage -= 1;
11259 callbackHandler(scope.currentPage);
11263 scope.selectPage = function(value, event) {
11264 event.preventDefault();
11265 scope.currentPage = value;
11266 scope.focusedPage = value;
11267 callbackHandler(scope.currentPage);
11270 var callbackHandler = function(num) {
11271 if (angular.isFunction(scope.clickHandler))
11273 scope.clickHandler(num);
11277 scope.checkSelectedPage = function(value) {
11278 if(scope.currentPage === value) {
11284 scope.isFocused = function(page) {
11285 if(scope.focusedPage === page) {
11295 angular.module('att.abs.paneSelector',[])
11296 .constant('paneGroupConstants',{
11297 SIDE_WIDTH_DEFAULT: '33%',
11298 INNER_PANE_DEFAULT: '67%',
11299 SIDE_PANE_ID: 'sidePane',
11300 NO_DRILL_DOWN: 'none'
11302 .factory('animation', function(){
11305 .directive('sideRow', ['$parse',function($parse){
11309 require: ['^sidePane','^paneGroup'],
11310 link: function(scope,element,attr,ctrls){
11311 var sidePaneCtrl = ctrls[0];
11312 var paneGroupCtrl = ctrls[1];
11315 Reset the sidePaneId array if a new
11316 set of ngRepeat data appeared
11318 sidePaneCtrl.sidePaneIds = [];
11321 var paneId =attr['paneId'];
11322 var drillDownTo = attr['drillDownTo'];
11324 sidePaneCtrl.sidePaneRows.push({'paneId':paneId, 'drillDownTo':drillDownTo});
11325 element.on('click', function(evnt){
11326 sidePaneCtrl.currentSelectedRowPaneId = paneId;
11327 paneGroupCtrl.slideOutPane(paneId,true);
11332 .controller('SidePaneCtrl',['$scope', '$element','animation', 'paneGroupConstants',
11333 function($scope,$element,animation, paneGroupConstants){
11335 this.sidePaneTracker = {};
11336 this.currentWidth = paneGroupConstants.SIDE_WIDTH_DEFAULT;
11337 this.paneId = paneGroupConstants.SIDE_PANE_ID;
11338 this.currentSelectedRowPaneId;
11340 this.drillDownToMapper = {};
11342 this.sidePaneRows = [];
11344 this.init = function(){
11346 var sidePaneRows = this.sidePaneRows;
11349 for(var index in sidePaneRows){
11350 var paneId = sidePaneRows[index].paneId;
11351 var drillDownTo = sidePaneRows[index].drillDownTo;
11353 this.drillDownToMapper[paneId] = drillDownTo;
11356 this.currentSelectedRowPaneId = paneId;
11357 this.sidePaneTracker[paneId] = [];
11365 this.getSidePanesList = function(){
11366 return this.sidePaneTracker[this.currentSelectedRowPaneId];
11369 this.addToSidePanesList = function(newPaneId){
11370 if(this.sidePaneTracker[this.currentSelectedRowPaneId] == undefined)
11371 this.sidePaneTracker[this.currentSelectedRowPaneId] = [];
11374 this.sidePaneTracker[this.currentSelectedRowPaneId].push(newPaneId);
11378 this.setWidth = function(val){
11380 this.currentWidth = val;
11381 animation.set($element,{width:this.currentWidth});
11384 this.resizeWidth = function(val){
11386 this.currentWidth = val;
11387 animation.to($element,.5,{width:val});
11391 .directive('sidePane', ['paneGroupConstants', function(paneGroupConstants){
11396 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/sidePane.html',
11397 require: ['^paneGroup', 'sidePane'],
11398 controller: 'SidePaneCtrl',
11400 link: function(scope,element,attr, ctrls){
11401 var paneGroupCtrl = ctrls[0];
11402 var sidePaneCtrl = ctrls[1];
11403 paneGroupCtrl.addPaneCtrl(paneGroupConstants.SIDE_PANE_ID, sidePaneCtrl);
11407 .directive('drillDownRow', ['$parse', 'paneGroupConstants',function($parse,paneGroupConstants){
11411 require: ['^innerPane','^paneGroup'],
11412 link: function(scope,element,attr,ctrls){
11413 var innerPaneCtrl = ctrls[0];
11414 var paneGroupCtrl = ctrls[1];
11415 var sidePaneCtrl = ctrls[2];
11417 element.on('click', function(evnt){
11418 var drillDownTo = innerPaneCtrl.drillDownTo;
11420 if(innerPaneCtrl.drillDownTo != paneGroupConstants.NO_DRILL_DOWN)
11421 paneGroupCtrl.slideOutPane(drillDownTo);
11426 .controller('InnerPaneCtrl', ['$scope', '$element','animation', 'paneGroupConstants',
11427 function($scope,$element,animation,paneGroupConstants){
11429 this.paneId = $scope.paneId;
11431 this.currentWidth = paneGroupConstants.INNER_PANE_DEFAULT;
11433 this.setWidth = function(val){
11435 this.currentWidth = val;
11436 animation.set($element,{width:this.currentWidth});
11439 this.resizeWidth = function(val,callback){
11440 animation.to($element,.25,{width:val,onComplete: callback});
11443 this.displayNone = function(){
11444 animation.set($element, {display:'none'});
11447 this.displayBlock = function(){
11448 animation.set($element,{display:'block'});
11450 this.hideRightBorder();
11453 this.floatLeft = function(){
11454 animation.set($element,{float:'left'});
11457 this.hideLeftBorder = function(){
11458 animation.set($element, {borderLeftWidth: '0px'});
11461 this.showLeftBorder = function(){
11462 animation.set($element,{borderLeftWidth: '1px'});
11465 this.hideRightBorder = function(){
11466 animation.set($element,{borderRightWidth: '0px'});
11469 this.showRightBorder = function(){
11470 animation.set($element, {borderRightWidth: '1px'});
11473 this.slideFromRight = function(){
11474 animation.set($element, {float:'right'});
11475 animation.set($element, {width: this.currentWidth});
11478 this.startOpen = function(){
11479 return $scope.startOpen;
11483 .directive('innerPane', function(){
11488 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/innerPane.html',
11489 require: ['^paneGroup', 'innerPane'],
11490 controller: 'InnerPaneCtrl',
11494 link: function(scope,element,attr,ctrls){
11496 if(attr.startOpen == ""){
11497 scope.startOpen = true;
11500 var paneGroupCtrl = ctrls[0];
11501 var innerPaneCtrl = ctrls[1];
11502 paneGroupCtrl.addPaneCtrl(scope.paneId,innerPaneCtrl);
11506 .controller('PaneGroupCtrl', ['$scope', '$element', 'paneGroupConstants', '$timeout',function($scope,$element,paneGroupConstants,$timeout){
11509 this.accountLevelPaneModel = [];
11511 this.title = $scope.title;
11513 this.init = function(){
11514 var sidePane = this.panes[paneGroupConstants.SIDE_PANE_ID];
11520 //Show the other panes that may be set to startOpen
11521 //numOpen starts at 1 because of the side pane
11523 for(var key in this.panes){
11524 if(this.panes[key].startOpen && this.panes[key].startOpen())
11529 width = ((100/numOpen)) + '%';
11533 if(this.panes[sidePane.currentSelectedRowPaneId])
11536 sidePane.setWidth(width);
11537 this.panes[sidePane.currentSelectedRowPaneId].setWidth(width);
11540 sidePane.setWidth();
11541 this.panes[sidePane.currentSelectedRowPaneId].setWidth();
11544 this.panes[sidePane.currentSelectedRowPaneId].displayBlock();
11546 for(var key in this.panes){
11547 if(key != paneGroupConstants.SIDE_PANE_ID && key != sidePane.currentSelectedRowPaneId)
11548 this.panes[key].displayNone();
11550 this.panes[key].drillDownTo = sidePane.drillDownToMapper[key];
11554 openOtherPanesOnStart(sidePane, this.panes);
11558 function openOtherPanesOnStart(sidePane, panes){
11559 //Build an array of the panes that need to be out
11560 var otherPanesStartOpened = [];
11561 for(var index in sidePane.sidePaneRows){
11562 var pane = sidePane.sidePaneRows[index];
11564 //Skip the first pane row since we handled it in the begining
11565 if(index > 0 && panes[pane.paneId].startOpen && panes[pane.paneId].startOpen()){
11566 otherPanesStartOpened.push(pane);
11567 //Remember the panes that are opened for the first pane row Index
11568 sidePane.addToSidePanesList(pane.paneId);
11574 for(var index in otherPanesStartOpened){
11575 var paneId = otherPanesStartOpened[index].paneId;
11576 var paneCtrl = panes[paneId];
11578 if(paneCtrl && paneCtrl.setWidth && paneCtrl.displayBlock){
11579 paneCtrl.setWidth(width);
11580 paneCtrl.displayBlock();
11590 Resets all the panels to their original positions at the end of a sidebar click
11591 By setting the sideBar to its default width
11592 Setting all panes to float left and displaynone
11593 Setting the pane that was clicked to default width and slide right
11596 this.resetPanes = function(){
11597 for(var key in this.panes){
11598 var pane = this.panes[key];
11599 if(pane && (pane.paneId != paneGroupConstants.SIDE_PANE_ID)){
11601 pane.displayNone();
11605 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11606 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
11609 this.addPaneCtrl = function(paneId,paneCtrl){
11610 this.panes[paneId] = paneCtrl;
11613 this._slideOutPane = function(paneId,isFromSidePane){
11616 //Check current side pane stack to see how many panes are already open for that side pane choice
11617 //then add the new pane that needs to be there
11618 if(isFromSidePane){
11620 //Check if the side pane id has already been clicked
11624 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11625 panesList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11629 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID] && this.panes[paneId]){
11630 this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId = paneId;
11631 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList();
11633 this.panes[paneId].slideFromRight();
11634 this.panes[paneId].displayBlock();
11636 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
11640 //Restore the panes based on the panelist
11641 if(panesList.length == 0){
11642 //Only one pane is out
11644 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID] && this.panes[paneId]){
11645 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
11646 this.panes[paneId].displayBlock();
11647 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
11652 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID]){
11653 //Multiple panes out
11654 var numPanes = panesList.length + 2;
11655 var width = ((100/numPanes)) + '%';
11656 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(width);
11658 //Set the sidePanes pane
11659 //set the panes children list
11660 if(this.panes && this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11661 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
11662 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].setWidth(width);
11665 for(var i in panesList){
11666 if(this.panes[panesList[i]]){
11667 this.panes[panesList[i]].displayBlock();
11668 this.panes[panesList[i]].setWidth(width);
11679 //Have to check the paneId that was given and where it is drilling down to
11680 var isPaneInStack = false;
11684 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11685 stackPaneList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11687 for(var i in stackPaneList){
11688 var pId = stackPaneList[i];
11690 isPaneInStack = true;
11695 if(!isPaneInStack){
11696 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11697 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList(paneId);
11700 var sidePanesListLength;
11702 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11703 sidePanesListLength = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList().length;
11705 var numPanes = sidePanesListLength + 2;
11706 var width = ((100/numPanes)) + '%';
11708 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11709 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(width);
11713 if(this.panes[paneGroupConstants.SIDE_PANE_ID])
11714 slideInPaneId = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList()[sidePanesListLength - 1];
11720 if(that.panes[paneGroupConstants.SIDE_PANE_ID])
11721 panesList = that.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
11723 for(var p in panesList){
11724 var paneId = panesList[p];
11725 var pane = this.panes[paneId];
11726 if(paneId != slideInPaneId && pane){
11727 pane.setWidth(width);
11728 pane.displayBlock();
11733 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11734 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
11735 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].showRightBorder();
11737 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].resizeWidth(width,function(){
11739 if(that.panes[slideInPaneId] && that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
11740 that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].hideRightBorder();
11741 that.panes[slideInPaneId].setWidth(width);
11742 that.panes[slideInPaneId].slideFromRight();
11743 that.panes[slideInPaneId].displayBlock();
11744 that.panes[slideInPaneId].floatLeft();
11754 this.slideOutPane = function(paneId,isFromSidePane){
11755 this._slideOutPane(paneId,isFromSidePane);
11759 .directive('paneGroup', ['$timeout',function($timeout){
11764 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html',
11767 controller: 'PaneGroupCtrl',
11768 link: function(scope,element,attr,ctrl){
11770 $timeout(initialize,100);
11772 function initialize(){
11779 angular.module('att.abs.profileCard', [])
11781 .constant('profileStatus',{
11783 ACTIVE:{status:"Active",color:"green"},
11784 DEACTIVATED:{status:"Deactivated",color:"red"},
11785 LOCKED:{status:"Locked",color:"red"},
11786 IDLE:{status:"Idle",color:"yellow"},
11787 PENDING:{status:"Pending",color:"blue"}
11789 role:"COMPANY ADMINISTRATOR"
11792 .directive('profileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
11796 templateUrl:function(element, attrs) {
11797 if(!attrs.addUser){
11798 return 'app/scripts/ng_js_att_tpls/profileCard/profileCard.html';
11801 return 'app/scripts/ng_js_att_tpls/profileCard/addUser.html';
11807 link: function(scope, elem, attr){
11810 function isImage(src) {
11812 var deferred = $q.defer();
11814 var image = new Image();
11815 image.onerror = function() {
11816 deferred.reject(false);
11818 image.onload = function() {
11819 deferred.resolve(true);
11822 if(src!==undefined && src.length>0 ){
11825 deferred.reject(false);
11828 return deferred.promise;
11832 isImage(scope.profile.img).then(function(img) {
11836 var splitName=(scope.profile.name).split(' ');
11838 for(var i=0;i<splitName.length;i++){
11839 scope.initials += splitName[i][0];
11841 if(scope.profile.role.toUpperCase()===profileStatus.role){
11844 var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
11846 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
11847 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
11848 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase())
11849 if(scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
11850 scope.profile.lastLogin=scope.profile.state;
11853 scope.profile.lastLogin=scope.profile.state;
11856 var today=new Date().getTime();
11857 var lastlogin=new Date(scope.profile.lastLogin).getTime();
11858 var diff=(today-lastlogin)/(1000*60*60*24);
11860 scope.profile.lastLogin="Today";
11863 scope.profile.lastLogin="Yesterday";
11869 angular.module('att.abs.progressBars', [])
11871 .directive('attProgressBar', [ function() {
11875 templateUrl : 'app/scripts/ng_js_att_tpls/progressBars/progressBars.html'
11878 angular.module('att.abs.radio', [])
11879 .constant('attRadioConfig', {
11880 activeClass : "att-radio--on",
11881 disabledClass : "att-radio--disabled"
11883 .directive('attRadio', ['$compile','attRadioConfig', function ($compile, attRadioConfig) {
11887 require: 'ngModel',
11888 link: function (scope, element, attr, ctrl) {
11890 var parentDiv = $compile('<div tabindex="0" role="radio" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-radio"></div>')(scope);
11892 element.wrap(parentDiv);
11893 element.parent().append('<div class="att-radio__indicator"></div>');
11894 element.parent().attr("title", attr.title);
11895 element.attr("tabindex","-1");
11897 ngCtrl.$render = function () {
11898 var selected = angular.equals(ngCtrl.$modelValue, attr.attRadio);
11899 element.parent().toggleClass(attRadioConfig.activeClass, selected);
11900 element.parent().attr("aria-checked", selected)
11903 scope.updateModel = function (evt) {
11904 var isActive = element.parent().hasClass(attRadioConfig.activeClass);
11906 if (!isActive && !scope.disabled) {
11907 ngCtrl.$setViewValue(isActive ? null : attr.attRadio);
11910 evt.preventDefault();
11913 attr.$observe('disabled', function (val) {
11914 scope.disabled = (val === true || val === "disabled" || val === "true");
11915 element.parent().toggleClass(attRadioConfig.disabledClass, scope.disabled);
11916 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
11922 angular.module('att.abs.scrollbar', [])
11923 .directive('attScrollbar', ['$window', '$timeout', '$parse', '$animate', function ($window, $timeout, $parse, $animate) {
11927 templateUrl: 'app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html',
11928 controller: ['$scope','$element','$attrs', function($scope, $element, $attrs) {
11930 axis: 'y', // Vertical or horizontal scrollbar? ( x || y ).
11931 wheel: true, // Enable or disable the mousewheel;
11932 wheelSpeed: 40, // How many pixels must the mouswheel scroll at a time.
11933 wheelLock: true, // Lock default scrolling window when there is no more content.
11934 scrollInvert: false, // Enable invert style scrolling
11935 trackSize: false, // Set the size of the scrollbar to auto or a fixed number.
11936 thumbSize: false, // Set the size of the thumb to auto or a fixed number.
11937 alwaysVisible: true // Set to false to hide the scrollbar if not being used
11939 var options = $attrs.scrollbar;
11941 options = $parse(options)($scope);
11945 this.options = angular.extend({}, defaults, options);
11946 this._defaults = defaults;
11949 $body = angular.element(document.querySelectorAll('body')[0]),
11950 $document = angular.element(document),
11951 $viewport = angular.element($element[0].querySelectorAll('.scroll-viewport')[0]),
11952 $overview = angular.element($element[0].querySelectorAll('.scroll-overview')[0]),
11953 $scrollbar = angular.element($element[0].querySelectorAll('.scroll-bar')[0]),
11954 $thumb = angular.element($element[0].querySelectorAll('.scroll-thumb')[0]),
11956 isHorizontal = this.options.axis === 'x',
11957 hasTouchEvents=false,
11958 wheelEvent = ("onwheel" in document ? "wheel" : // Modern browsers support "wheel"
11959 document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
11960 "DOMMouseScroll"), // let's assume that remaining browsers are older Firefox
11961 sizeLabel = isHorizontal ? 'width' : 'height',
11962 sizeLabelCap = sizeLabel.charAt(0).toUpperCase() + sizeLabel.slice(1).toLowerCase(),
11963 posiLabel = isHorizontal ? 'left' : 'top',
11964 // moveEvent = document.createEvent('HTMLEvents'),
11965 restoreVisibilityAfterWheel,
11966 thumbscrolltouch=false,documnetscrolltouch=false;
11967 if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
11968 hasTouchEvents = true;
11971 //moveEvent.initEvent('move', true, true);
11972 this.contentPosition = 0;
11973 this.viewportSize = 0;
11974 this.contentSize = 0;
11975 this.contentRatio = 0;
11976 this.trackSize = 0;
11977 this.trackRatio = 0;
11978 this.thumbSize = 0;
11979 this.thumbPosition = 0;
11981 this.initialize = function() {
11982 if (!this.options.alwaysVisible) {
11983 $scrollbar.css('opacity', 0);
11990 this.update = function(scrollTo) {
11991 this.viewportSize = $viewport.prop('offset' + sizeLabelCap) || 1;
11992 this.contentSize = $overview.prop('scroll' + sizeLabelCap) || 1;
11993 this.contentRatio = this.viewportSize / this.contentSize;
11994 this.trackSize = this.options.trackSize || this.viewportSize;
11995 this.thumbSize = Math.min(this.trackSize, Math.max(0, (this.options.thumbSize || (this.trackSize * this.contentRatio))));
11996 this.trackRatio = this.options.thumbSize ? (this.contentSize - this.viewportSize) / (this.trackSize - this.thumbSize) : (this.contentSize / this.trackSize);
11997 mousePosition = $scrollbar.prop('offsetTop');
11999 $scrollbar.toggleClass('disable', this.contentRatio >= 1 || isNaN(this.contentRatio));
12001 if (!this.options.alwaysVisible && this.contentRatio < 1 && this.viewportSize > 0) {
12002 //flash the scrollbar when update happens
12003 $animate.addClass($scrollbar, 'visible').then(function() {
12004 $animate.removeClass($scrollbar, 'visible');
12009 if (scrollTo !== null) {
12010 switch (scrollTo) {
12012 this.contentPosition = this.contentSize - this.viewportSize;
12015 this.contentPosition = parseInt(scrollTo, 10) || 0;
12019 ensureContentPosition();
12020 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
12021 $scrollbar.css(sizeLabel, self.trackSize + 'px');
12022 $thumb.css(sizeLabel, self.thumbSize + 'px');
12023 $overview.css(posiLabel, -self.contentPosition + 'px');
12027 fireEvent = function(obj, evt) {
12028 var fireOnThis = obj;
12029 if (document.createEvent) {
12031 var evtObj = document.createEvent('HTMLEvents');
12032 evtObj.initEvent(evt, true, false);
12033 fireOnThis.dispatchEvent(evtObj);
12035 else if (document.createEventObject) {
12037 var evtObj = document.createEventObject();
12038 fireOnThis.fireEvent('on' + evt, evtObj);
12041 function ensureContentPosition() {
12042 // if scrollbar is on, ensure the bottom of the content does not go above the bottom of the viewport
12043 if (self.contentRatio <= 1 && self.contentPosition > self.contentSize - self.viewportSize) {
12044 self.contentPosition = self.contentSize - self.viewportSize;
12046 // if scrollbar is off, ensure the top of the content does not go below the top of the viewport
12047 else if (self.contentRatio > 1 && self.contentPosition > 0) {
12048 self.contentPosition = 0;
12052 function setEvents() {
12054 if (hasTouchEvents) {
12055 $viewport.on('touchstart', touchstart);
12056 $thumb.on('touchstart', touchstart);
12059 $thumb.on('mousedown', start);
12060 $scrollbar.on('mousedown', drag);
12063 angular.element($window).on('resize', resize);
12065 if (self.options.wheel) {
12066 $element.on(wheelEvent, wheel);
12070 function resize() {
12074 function touchstart(event) {
12075 if (1 === event.touches.length) {
12076 event.stopPropagation();
12077 start(event.touches[0]);
12081 function start(event) {
12082 $body.addClass('scroll-no-select');
12083 $element.addClass('scroll-no-select');
12085 if (!self.options.alwaysVisible) {
12086 $scrollbar.addClass('visible');
12088 mousePosition = isHorizontal ? event.clientX : event.clientY;
12089 self.thumbPosition = parseInt($thumb.css(posiLabel), 10) || 0;
12091 if (hasTouchEvents) {
12092 documnetscrolltouch=false;
12093 thumbscrolltouch=false;
12094 $viewport.on('touchmove', touchdrag);
12095 $viewport.on('touchend', end);
12096 $thumb.on('touchmove',touchdragthumb);
12097 $thumb.on('touchend', end);
12099 $document.on('mousemove', drag);
12100 $document.on('mouseup', end);
12101 $thumb.on('mouseup', end);
12105 function wheel(event) {
12107 if (self.contentRatio >= 1) {
12111 if (!self.options.alwaysVisible) {
12112 //cancel removing visibility if wheel event is triggered before the timeout
12113 if (restoreVisibilityAfterWheel) {
12114 $timeout.cancel(restoreVisibilityAfterWheel);
12116 $scrollbar.addClass('visible');
12118 restoreVisibilityAfterWheel = $timeout(function() {
12119 $scrollbar.removeClass('visible');
12124 var evntObj = (event && event.originalEvent) || event || $window.event,
12125 deltaDir = self.options.axis.toUpperCase(),
12130 wheelSpeed = evntObj.deltaMode === 0 ? self.options.wheelSpeed : 1;
12132 if (self.options.scrollInvert) {
12136 if (wheelEvent === 'mousewheel') {
12137 delta.Y = -1 * evntObj.wheelDelta / 40;
12138 evntObj.wheelDeltaX && (delta.X = -1 * evntObj.wheelDeltaX / 40);
12140 delta.X *= -1 / wheelSpeed;
12141 delta.Y *= -1 / wheelSpeed;
12143 var wheelSpeedDelta = delta[deltaDir];
12145 self.contentPosition -= wheelSpeedDelta * self.options.wheelSpeed;
12146 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
12149 //$element[0].dispatchEvent(moveEvent);
12150 fireEvent($element[0], 'move');
12152 ensureContentPosition();
12153 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
12154 $overview.css(posiLabel, -self.contentPosition + 'px');
12156 if (self.options.wheelLock || (self.contentPosition !== (self.contentSize - self.viewportSize) && self.contentPosition !== 0)) {
12157 evntObj.preventDefault();
12161 function touchdrag(event) {
12162 event.preventDefault();
12163 documnetscrolltouch=true;
12164 drag(event.touches[0]);
12166 function touchdragthumb(event){
12167 event.preventDefault();
12168 thumbscrolltouch=true;
12169 drag(event.touches[0]);
12172 function drag(event) {
12174 if (self.contentRatio >= 1) {
12177 var mousePositionNew = isHorizontal ? event.clientX : event.clientY,
12178 thumbPositionDelta = mousePositionNew - mousePosition;
12180 if ((self.options.scrollInvert && !hasTouchEvents) ||
12181 (hasTouchEvents && !self.options.scrollInvert))
12183 thumbPositionDelta = mousePosition - mousePositionNew;
12185 if(documnetscrolltouch && hasTouchEvents){
12186 thumbPositionDelta = mousePosition - mousePositionNew;
12188 if(thumbscrolltouch && hasTouchEvents){
12189 thumbPositionDelta = mousePositionNew - mousePosition;
12191 var thumbPositionNew = Math.min((self.trackSize - self.thumbSize), Math.max(0, self.thumbPosition + thumbPositionDelta));
12192 self.contentPosition = thumbPositionNew * self.trackRatio;
12195 // $element[0].dispatchEvent(moveEvent);
12196 fireEvent($element[0], 'move');
12198 ensureContentPosition();
12199 $thumb.css(posiLabel, thumbPositionNew + 'px');
12200 $overview.css(posiLabel, -self.contentPosition + 'px');
12205 $body.removeClass('scroll-no-select');
12206 $element.removeClass('scroll-no-select');
12207 if (!self.options.alwaysVisible) {
12208 $scrollbar.removeClass('visible');
12210 $document.off('mousemove', drag);
12211 $document.off('mouseup', end);
12212 $thumb.off('mouseup', end);
12213 $document.off('touchmove', touchdrag);
12214 $document.off('ontouchend', end);
12215 $thumb.off('touchmove',touchdragthumb);
12216 $thumb.off('touchend', end);
12218 this.cleanup = function() {
12219 $viewport.off('touchstart', touchstart);
12220 $thumb.off('mousedown', start);
12221 $scrollbar.off('mousedown', drag);
12222 $thumb.off('touchmove',touchdragthumb);
12223 $thumb.off('touchend', end);
12224 angular.element($window).off('resize', resize);
12225 $element.off(wheelEvent, wheel);
12226 //ensure scrollbar isn't activated
12227 self.options.alwaysVisible = true;
12232 link: function(scope, iElement, iAttrs, controller) {
12233 var position = iElement.css('position');
12234 if (position !== 'relative' && position !== 'absolute') {
12235 iElement.css('position', 'relative');
12237 scope.$watch(function() {
12238 $timeout(function() {
12239 var $overview = angular.element(iElement[0].querySelectorAll('.scroll-overview')[0]);
12240 var newValue = $overview.prop('scrollHeight');
12241 var oldValue = scope.oldValue;
12242 if (newValue !== oldValue) {
12243 scope.oldValue = newValue;
12244 controller.update();
12248 controller.initialize();
12249 iElement.on('$destroy', function() {
12250 controller.cleanup();
12276 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 : "'"
12279 isControl: function (e) {
12289 if (e.metaKey) return true;
12293 isFunctionKey: function (k) {
12294 k = k.keyCode ? k.keyCode : k;
12295 return k >= 112 && k <= 123;
12297 isVerticalMovement: function (k){
12298 return ~[KEY.UP, KEY.DOWN].indexOf(k);
12300 isHorizontalMovement: function (k){
12301 return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
12305 angular.module('att.abs.search', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
12307 .directive('attSearch', ["$document", "$filter", "$isElement", '$documentBind', "$timeout", function($document,$filter,$isElement,$documentBind,$timeout){
12310 scope:{cName: '=attSearch'},
12314 templateUrl: 'app/scripts/ng_js_att_tpls/search/search.html',
12315 link: function(scope, element, attr, ctrl) {
12317 scope.selectedIndex = -1;
12318 scope.selectedOption = attr.placeholder;
12319 scope.isDisabled = false;
12320 scope.className = "select2-match";
12321 scope.showSearch = false;
12322 scope.showlist = false;
12324 if(attr.placeholderAsOption === "false")
12326 scope.selectMsg = "";
12330 scope.selectMsg = attr.placeholder;
12333 if(attr.showInputFilter === "true"){scope.showSearch = true;}
12335 scope.showDropdown = function(){
12336 if(!(attr.disabled)){
12337 scope.showlist = !scope.showlist;
12338 scope.setSelectTop();
12342 element.bind("keydown", function(e){
12343 if (e.keyCode === KEY.BACKSPACE || e.keyCode === KEY.SPACE || e.keyCode === KEY.ESC || e.keyCode === KEY.ENTER || KEY.isControl(e) || KEY.isVerticalMovement(e.keyCode) || KEY.isHorizontalMovement(e.keyCode) || KEY.isFunctionKey(e.keyCode))
12345 e.preventDefault();
12346 e.stopPropagation();
12348 switch (e.keyCode) {
12350 scope.selectNext();
12353 scope.selectPrev();
12356 scope.selectCurrent();
12358 case KEY.BACKSPACE:
12363 scope.title += " ";
12367 if(scope.title === "")
12369 scope.showlist = false;
12382 if(scope.showSearch === false && e.keyCode !== 9)
12384 scope.showlist = true;
12385 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode):String.fromCharCode(e.keyCode);
12388 else if(e.keyCode === 9)
12390 scope.showlist = false;
12397 scope.selectOption = function(sTitle,sIndex,keepOpen)
12399 if(sIndex === -1 || sIndex === "-1"){
12400 scope.selCategory = "";
12401 scope.selectedIndex = -1;
12402 ctrl.$setViewValue("");
12403 scope.selectedOption = scope.selectMsg;
12407 scope.selCategory = scope.cName[sIndex];
12408 scope.selectedIndex = sIndex;
12409 ctrl.$setViewValue(scope.selCategory);
12410 scope.selectedOption = scope.selCategory.title;
12415 scope.showlist = false;
12421 scope.isDisabled = true;
12424 scope.selectCurrent = function()
12426 if(scope.showlist === true)
12428 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12433 scope.showlist = true;
12434 scope.setSelectTop();
12439 scope.hoverIn = function(cItem)
12441 scope.selectedIndex = cItem;
12444 scope.setSelectTop = function()
12446 $timeout(function ()
12448 if(scope.showlist ===true)
12450 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12451 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
12452 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12458 scope.setCurrentTop = function()
12460 $timeout(function ()
12462 if(scope.showlist ===true)
12464 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12465 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
12466 //angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12467 if(selectedElemTopPos < (angular.element(containerUL)[0].scrollTop) )
12469 angular.element(containerUL)[0].scrollTop -= 30;
12471 else if((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight))
12473 angular.element(containerUL)[0].scrollTop += 30;
12480 scope.selectNext = function()
12482 if((scope.selectedIndex + 1) <= (scope.cName.length-1))
12484 scope.selectedIndex += 1;
12485 if(scope.showlist === false)
12487 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12491 scope.setCurrentTop();
12494 scope.selectPrev = function()
12496 if((scope.selectedIndex - 1) >= 0)
12498 scope.selectedIndex -= 1;
12499 if(scope.showlist === false)
12501 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12505 else if(scope.selectedIndex -1 < 0)
12507 scope.selectedIndex = -1;
12508 if(scope.showlist === false)
12510 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12514 scope.setCurrentTop();
12518 scope.updateSelection = function(sItem)
12520 scope.selectedOption = sItem.title;
12521 //scope.selectedIndex = -1;
12525 scope.$watch('selCategory',function(value)
12528 scope.updateSelection(value);
12532 ctrl.$viewChangeListeners.push(function(){
12533 scope.$eval(attr.ngChange);
12536 ctrl.$render = function(){
12537 scope.selCategory = ctrl.$viewValue;
12540 var outsideClick = function(e){
12541 var isElement = $isElement(angular.element(e.target), element, $document);
12543 scope.showlist = false;
12548 $documentBind.click('showlist', outsideClick, scope);
12575 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 : "'"
12578 isControl: function (e) {
12588 if (e.metaKey) return true;
12592 isFunctionKey: function (k) {
12593 k = k.keyCode ? k.keyCode : k;
12594 return k >= 112 && k <= 123;
12596 isVerticalMovement: function (k){
12597 return ~[KEY.UP, KEY.DOWN].indexOf(k);
12599 isHorizontalMovement: function (k){
12600 return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
12604 angular.module('att.abs.select', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
12606 .filter('startsWith', function() {
12607 if (typeof String.prototype.startsWith != 'function') {
12608 // see below for better implementation!
12609 String.prototype.startsWith = function (str){
12610 return this.indexOf(str) === 0;
12614 return function(items, searchString) {
12615 if (searchString === undefined || searchString === "") return items;
12618 angular.forEach(items, function(item) {
12619 if (item.title.toLowerCase().startsWith(searchString.toLowerCase())) {
12620 filtered.push(item);
12627 .directive('attSelect', ["$document", "$filter", "$isElement", '$documentBind', "$timeout", function($document,$filter,$isElement,$documentBind,$timeout){
12630 scope:{cName: '=attSelect'},
12634 templateUrl: 'app/scripts/ng_js_att_tpls/select/select.html',
12635 link: function(scope, element, attr, ctrl) {
12637 scope.selectedIndex = -1;
12638 scope.selectedOption = attr.placeholder;
12639 scope.isDisabled = false;
12640 scope.className = "select2-match";
12641 scope.showSearch = false;
12642 scope.showlist = false;
12644 if(attr.placeholderAsOption === "false")
12646 scope.selectMsg = "";
12650 scope.selectMsg = attr.placeholder;
12653 if (attr.startsWithFilter === "true" || attr.startsWithFilter === true) {
12654 scope.startsWithFilter = true;
12657 if(attr.showInputFilter === "true"){scope.showSearch = true;}
12659 scope.showDropdown = function(){
12660 if(!(attr.disabled)){
12661 scope.showlist = !scope.showlist;
12662 scope.setSelectTop();
12666 element.bind("keydown", function(e){
12667 if (e.keyCode === KEY.BACKSPACE || e.keyCode === KEY.SPACE || e.keyCode === KEY.ESC || e.keyCode === KEY.ENTER || KEY.isControl(e) || KEY.isVerticalMovement(e.keyCode) || KEY.isHorizontalMovement(e.keyCode) || KEY.isFunctionKey(e.keyCode))
12669 e.preventDefault();
12670 e.stopPropagation();
12672 switch (e.keyCode) {
12674 scope.selectNext();
12677 scope.selectPrev();
12680 scope.selectCurrent();
12682 case KEY.BACKSPACE:
12687 scope.title += " ";
12691 if(scope.title === "")
12693 scope.showlist = false;
12706 if(scope.showSearch === false && e.keyCode !== 9)
12708 scope.showlist = true;
12709 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode):String.fromCharCode(e.keyCode);
12712 else if(e.keyCode === 9)
12714 scope.showlist = false;
12721 scope.selectOption = function(sTitle,sIndex,keepOpen)
12723 if(sIndex === -1 || sIndex === '-1'){
12724 scope.selCategory = "";
12725 scope.selectedIndex = -1;
12726 ctrl.$setViewValue("");
12727 scope.selectedOption = scope.selectMsg;
12731 scope.selCategory = scope.cName[sIndex];
12732 scope.selectedIndex = sIndex;
12733 ctrl.$setViewValue(scope.selCategory);
12734 scope.selectedOption = scope.selCategory.title;
12739 scope.showlist = false;
12745 scope.isDisabled = true;
12748 scope.selectCurrent = function()
12750 if(scope.showlist === true)
12752 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12757 scope.showlist = true;
12758 scope.setSelectTop();
12763 scope.hoverIn = function(cItem)
12765 scope.selectedIndex = cItem;
12768 scope.setSelectTop = function()
12770 $timeout(function ()
12772 if(scope.showlist ===true)
12774 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12775 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
12776 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12782 scope.setCurrentTop = function()
12784 $timeout(function ()
12786 if(scope.showlist ===true)
12788 var containerUL = angular.element(element)[0].querySelector(".select2-results");
12789 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
12790 //angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
12791 if(selectedElemTopPos < (angular.element(containerUL)[0].scrollTop) )
12793 angular.element(containerUL)[0].scrollTop -= 30;
12795 else if((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight))
12797 angular.element(containerUL)[0].scrollTop += 30;
12804 scope.selectNext = function()
12806 if((scope.selectedIndex + 1) <= (scope.cName.length-1))
12808 scope.selectedIndex += 1;
12809 if(scope.showlist === false)
12811 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12815 scope.setCurrentTop();
12818 scope.selectPrev = function()
12820 if((scope.selectedIndex - 1) >= 0)
12822 scope.selectedIndex -= 1;
12823 if(scope.showlist === false)
12825 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12829 else if(scope.selectedIndex -1 < 0)
12831 scope.selectedIndex = -1;
12832 if(scope.showlist === false)
12834 scope.selectOption(scope.selectMsg,scope.selectedIndex ,false);
12838 scope.setCurrentTop();
12842 scope.updateSelection = function(sItem)
12844 scope.selectedOption = sItem.title;
12845 //scope.selectedIndex = -1;
12849 scope.$watch('selCategory',function(value)
12852 scope.updateSelection(value);
12856 ctrl.$viewChangeListeners.push(function(){
12857 scope.$eval(attr.ngChange);
12860 ctrl.$render = function(){
12861 scope.selCategory = ctrl.$viewValue;
12864 var outsideClick = function(e){
12865 var isElement = $isElement(angular.element(e.target), element, $document);
12867 scope.showlist = false;
12872 $documentBind.click('showlist', outsideClick, scope);
12877 .directive('textDropdown', ['$document', '$isElement', '$documentBind', function($document,$isElement,$documentBind) {
12882 actions: '=actions',
12883 defaultAction: '=defaultAction',
12884 onActionClicked: '=?'
12886 templateUrl : 'app/scripts/ng_js_att_tpls/select/textDropdown.html',
12888 link: function(scope, element, attr, ctrl) {
12889 scope.selectedIndex = 0;
12890 scope.selectedOption = attr.placeholder;
12891 scope.isDisabled = false;
12892 scope.isActionsShown = false;
12894 if(scope.defaultAction == undefined)
12896 scope.currentAction = scope.actions[0];
12897 scope.selectedIndex = 0;
12898 } else if (scope.defaultAction != undefined || scope.defaultAction != '') {
12899 for (var act in scope.actions)
12901 if (scope.actions[act] === scope.defaultAction)
12903 scope.currentAction = scope.actions[act];
12904 scope.selectedIndex = scope.actions.indexOf(act);
12905 scope.isActionsShown = false;
12912 scope.currentAction = scope.actions[0];
12915 scope.toggle = function() {
12916 scope.isActionsShown = !scope.isActionsShown;
12919 scope.chooseAction = function($event, action){
12921 if ($event != null) {
12922 scope.currentAction = action;
12923 scope.selectedIndex = scope.actions.indexOf(action);
12928 scope.currentAction = scope.actions[scope.selectedIndex];
12931 if (angular.isFunction(scope.onActionClicked))
12933 scope.onActionClicked(scope.currentAction);
12939 scope.isCurrentAction = function(action) {
12940 return (action === scope.currentAction);
12944 element.bind("keydown", function(e){
12945 if (e.which === KEY.ENTER || KEY.isVerticalMovement(e.which) || KEY.isHorizontalMovement(e.which))
12947 e.preventDefault();
12948 e.stopPropagation();
12949 switch (e.keyCode) {
12951 scope.selectNext();
12954 scope.selectPrev();
12957 scope.selectCurrent();
12960 scope.isActionsShown = false;
12970 scope.isDisabled = true;
12974 scope.selectCurrent = function()
12976 if (scope.selectedIndex < 0)
12978 scope.selectedIndex = 0;
12982 if(!scope.isActionsShown) {
12986 scope.chooseAction(null, scope.currentAction);
12990 scope.selectNext = function()
12992 if(scope.isActionsShown)
12994 if((scope.selectedIndex + 1) < scope.actions.length)
12996 scope.selectedIndex += 1;
13001 scope.selectedIndex = (scope.actions.length - 1);
13008 scope.selectPrev = function()
13010 if(scope.isActionsShown)
13012 if((scope.selectedIndex - 1) >= 0)
13014 scope.selectedIndex -= 1;
13017 else if(scope.selectedIndex - 1 < 0)
13019 scope.selectedIndex = 0;
13025 scope.hoverIn = function(cItem)
13027 scope.selectedIndex = cItem;
13033 var outsideClick = function(e) {
13034 var isElement = $isElement(angular.element(e.target), element, $document);
13043 $documentBind.click('isActionsShown', outsideClick, scope);
13051 angular.module('att.abs.slider', ['att.abs.position'])
13052 .constant('sliderDefaultOptions', {
13056 disabledWidth: 116,
13058 .directive('attSlider', ['sliderDefaultOptions','$position', function(sliderDefaultOptions,$position)
13065 floor: "=", // the minimum possible value
13066 ceiling: "=", // the maximum possible value
13067 step: "@", // how wide is each step
13068 precision: "@", // how many decimal places do we care about
13069 width: "@", //how wide the bar would be
13070 textDisplay: "=", // Labels of max and min values to be displayed at front End
13071 value: "=", // Value of Current Position model
13072 ngModelSingle: '=?',
13075 ngModelDisabled: '=?'
13077 templateUrl: 'app/scripts/ng_js_att_tpls/slider/slider.html',
13078 link: function(scope, elem, attr, ctrl)
13080 var minOffset, maxOffset, newOffset, offsetRange, valueRange, start_x = 0, disabledRange, disabled, evFlag = false, minValue, maxValue, range, refLow, refHigh, maxPtr, minPtr, singlePtr, getHandles;
13081 scope.minPtrOffset = 0;
13082 scope.maxPtrOffset = 0;
13083 var disableWidth = sliderDefaultOptions.disabledWidth;
13086 var obj = elem.children();
13087 disabledRange = obj[0].children;
13088 disabledRange = angular.element(disabledRange[0]);
13089 getHandles = obj[1].children;
13090 singlePtr = angular.element(getHandles[0]);
13091 minPtr = angular.element(getHandles[1]);
13092 maxPtr = angular.element(getHandles[2]);
13093 disabled = ((attr.ngModelSingle == null) && (attr.ngModelLow == null) && (attr.ngModelHigh == null)) && (attr.ngModelDisabled != null);
13094 range = (attr.ngModelSingle == null) && ((attr.ngModelLow != null) && (attr.ngModelHigh != null));
13095 refLow = 'ngModelLow';
13096 refHigh = 'ngModelHigh';
13102 singlePtr.remove();
13105 disabledRange.remove();
13108 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
13109 scope.handleStyle = {left: disableWidth + 'px'};
13111 minValue = parseFloat(scope.floor);
13112 maxValue = parseFloat(scope.ceiling);
13113 valueRange = maxValue - minValue;
13115 if (attr.width !== undefined) {
13116 maxOffset = attr.width;
13119 if (elem[0].clientWidth !== 0) {
13120 maxOffset = elem[0].clientWidth;
13123 maxOffset = sliderDefaultOptions.width;
13126 offsetRange = maxOffset - minOffset;
13129 scope.keyDown = function(ev){
13130 if(ev.keyCode == 39){
13131 var elemLeft = $position.position(elem).left;
13133 newOffset = sliderDefaultOptions.step + newOffset;
13135 else{newOffset = sliderDefaultOptions.step + elemLeft;}
13137 else if(ev.keyCode == 37){
13138 var ptrLeft = $position.position(singlePtr).left;
13139 var elemLeft = $position.position(elem).left;
13142 newOffset = newOffset - sliderDefaultOptions.step ;
13146 newOffset = ptrLeft - sliderDefaultOptions.step ;}
13151 scope.ptrOffset(newOffset);
13157 scope.mouseDown = function(e, ref) {
13163 start_x = e.clientX - newOffset;
13167 start_x = e.clientX;
13170 if (scope.ref == refLow) {
13171 start_x = e.clientX - scope.minPtrOffset;
13175 start_x = e.clientX - scope.maxPtrOffset;
13179 scope.ref= 'ngModelDisabled';
13180 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
13184 // Mouse Move Event
13185 scope.moveElem = function(ev) {
13187 var eventX, newPercent, newValue;
13188 eventX = ev.clientX;
13189 newOffset = eventX - start_x;
13190 scope.ptrOffset(newOffset);
13195 scope.mouseUp = function(ev) {
13197 minPtr.removeClass('dragging');
13198 maxPtr.removeClass('dragging');
13199 singlePtr.removeClass('dragging');
13200 $(document).off('mousemove');
13203 //Function to calculate the current PositionValue
13204 scope.calStep = function(value, precision, step, floor) {
13205 var decimals, remainder, roundedValue, steppedValue;
13206 if (floor === null) {
13209 if (step === null) {
13210 step = 1 / Math.pow(10, precision);
13212 remainder = (value - floor) % step;
13213 steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
13214 decimals = Math.pow(10, precision);
13215 roundedValue = steppedValue * decimals / decimals;
13216 return roundedValue.toFixed(precision);
13219 //Function to calculate Offset Percent
13220 scope.percentOffset = function(offset) {
13221 return ((offset - minOffset) / offsetRange) * 100;
13224 //Function to calculate Offset position
13225 scope.ptrOffset = function(newOffset){
13226 var newPercent, newValue;
13227 newOffset = Math.max(Math.min(newOffset, maxOffset), minOffset);
13228 newPercent = scope.percentOffset(newOffset);
13229 newValue = minValue + (valueRange * newPercent / 100.0);
13231 var rangeSliderWidth;
13232 if (scope.ref == refLow) {
13233 scope.minHandleStyle = {left: newOffset + "px"};
13234 scope.minNewVal = newValue;
13235 scope.minPtrOffset = newOffset;
13236 minPtr.addClass('dragging');
13237 if (newValue > scope.maxNewVal) {
13238 scope.ref = refHigh;
13239 scope.maxNewVal = newValue;
13240 scope.maxPtrOffset = newOffset;
13241 maxPtr.addClass('dragging');
13242 minPtr.removeClass('dragging');
13243 scope.maxHandleStyle = {left: newOffset + "px"};
13247 scope.maxHandleStyle = {left: newOffset + "px"};
13248 scope.maxNewVal = newValue;
13249 scope.maxPtrOffset = newOffset;
13250 maxPtr.addClass('dragging');
13251 if (newValue < scope.minNewVal) {
13252 scope.ref = refLow;
13253 scope.minVal = newValue;
13254 scope.minPtrOffset = newOffset;
13255 minPtr.addClass('dragging');
13256 maxPtr.removeClass('dragging');
13257 scope.minHandleStyle = {left: newOffset + "px"};
13260 rangeSliderWidth = parseInt(scope.maxPtrOffset) - parseInt(scope.minPtrOffset);
13261 scope.rangeStyle = {width: rangeSliderWidth + "px", left: scope.minPtrOffset + "px"};
13264 if (disabled && newOffset > disableWidth) {
13265 scope.rangeStyle = {width: newOffset + "px", zIndex: 0};
13268 singlePtr.addClass('dragging');
13269 scope.rangeStyle = {width: newOffset + "px"};
13271 scope.handleStyle = {left: newOffset + "px"};
13273 if ((scope.precision == undefined) || (scope.step == undefined)) {
13274 scope.precision = sliderDefaultOptions.precision;
13275 scope.step = sliderDefaultOptions.step;
13277 newValue = scope.calStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
13278 scope[scope.ref] = newValue;
13283 ]).directive('attSliderMin',[function()
13286 require: '^attSlider',
13290 templateUrl: 'app/scripts/ng_js_att_tpls/slider/minContent.html'
13293 ]).directive('attSliderMax',[function()
13296 require: '^attSlider',
13300 templateUrl: 'app/scripts/ng_js_att_tpls/slider/maxContent.html'
13304 .constant('sliderConstants', {
13306 The MIT License (MIT)
13307 Copyright (c) 2013 Julien Valéry
13320 className: "jslider",
13321 selector: ".jslider-"
13327 BLUE_HIGHLIGHT: 'blue',
13328 MAGENTA: 'magenta',
13331 DARK_BLUE: 'dark-blue',
13332 REGULAR: 'regular',
13336 .factory('utils', function() {
13338 The MIT License (MIT)
13339 Copyright (c) 2013 Julien Valéry
13342 offset: function(elm) {
13343 var rawDom = elm[0];
13346 var body = document.documentElement || document.body;
13347 var scrollX = window.pageXOffset || body.scrollLeft;
13348 var scrollY = window.pageYOffset || body.scrollTop;
13349 _x = rawDom.getBoundingClientRect().left + scrollX;
13350 _y = rawDom.getBoundingClientRect().top + scrollY;
13351 return { left: _x, top:_y };
13354 roundUpToScale: function(mousePrc, scale, cutOffWidth, cutOffIndex){
13360 for(var index = 1;index < scale.length; index++){
13361 lowerVal = scale[index-1];
13362 higherVal = scale[index];
13364 middle = ((higherVal - lowerVal)*.5)+lowerVal;
13367 Handles a situation where the user clicks close to the start point of
13368 the slider but the pointer doesn't move
13372 if(lowerVal == 0 && mousePrc <= middle){
13373 newMousePrc = lowerVal;
13376 else if(checkEquality(lowerVal,mousePrc)){
13377 newMousePrc = lowerVal;
13380 else if(lowerVal < mousePrc && (mousePrc < higherVal ||
13381 checkEquality(mousePrc,higherVal)))
13383 newMousePrc = higherVal;
13389 //Check if the newMousePrc is <= the cuttOffPoint
13390 if(cutOffWidth && newMousePrc < cutOffWidth){
13391 return scale[cutOffIndex];
13394 return newMousePrc;
13398 Checks to see if 2 points are so close that they are
13402 function checkEquality(point1, point2){
13403 var precision = 0.1;
13404 if( Math.abs(point2 - point1) <= precision)
13410 valueForDifferentScale: function(from,to,prc,prcToValueMapper){
13411 var decimalPrc = prc/100;
13412 if(decimalPrc == 0)
13415 return prcToValueMapper[prc];
13418 getConversionFactorValue: function(value, conversion,firstDimension){
13420 Loop through the conversion array and keep checking the
13424 if(value <= conversion[0].startVal){
13427 scaledDimension:firstDimension
13433 for(var index in conversion){
13434 var c = conversion[index];
13436 if(value > c.startVal)
13440 var scaleFactor = conversion[endIndex].scaleFactor;
13441 var scaledVal = value/scaleFactor;
13442 var scaledDimension=conversion[endIndex].dimension;
13445 scaledVal:scaledVal,
13446 scaledDimension:scaledDimension
13454 .factory('sliderDraggable', ['utils', function(utils) {
13457 The MIT License (MIT)
13458 Copyright (c) 2013 Julien Valéry
13461 function Draggable(){
13462 this._init.apply( this, arguments );
13465 Draggable.prototype.oninit = function(){
13468 Draggable.prototype.events = function(){
13471 Draggable.prototype.onmousedown = function(){
13472 this.ptr.css({ position: "absolute" });
13475 Draggable.prototype.onmousemove = function( evt, x, y ){
13476 this.ptr.css({ left: x, top: y });
13479 Draggable.prototype.onmouseup = function(){};
13481 Draggable.prototype.isDefault = {
13488 Draggable.prototype._init = function() {
13489 if( arguments.length > 0 ){
13490 this.ptr = arguments[0];
13491 this.parent = arguments[2];
13497 angular.extend( this.is, this.isDefault );
13498 var offset = utils.offset(this.ptr);
13503 width: this.ptr[0].clientWidth,
13504 height: this.ptr[0].clientHeight
13507 this.oninit.apply( this, arguments );
13513 Draggable.prototype._getPageCoords = function( event ){
13517 if( event.targetTouches && event.targetTouches[0] ){
13518 value= { x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY };
13520 value= { x: event.pageX, y: event.pageY };
13527 Draggable.prototype._bindEvent = function( ptr, eventType, handler ){
13530 if( this.supportTouches_ ){
13531 ptr[0].attachEvent( this.events_[ eventType ], handler);
13535 ptr.bind( this.events_[ eventType ], handler );
13540 Draggable.prototype._events = function(){
13543 this.supportTouches_ = 'ontouchend' in document;
13545 "click": this.supportTouches_ ? "touchstart" : "click",
13546 "down": this.supportTouches_ ? "touchstart" : "mousedown",
13547 "move": this.supportTouches_ ? "touchmove" : "mousemove",
13548 "up" : this.supportTouches_ ? "touchend" : "mouseup",
13549 "mousedown" : this.supportTouches_ ? "mousedown" : "mousedown"
13552 var documentElt = angular.element(window.document);
13554 this._bindEvent(documentElt, "move", function(event) {
13556 event.stopPropagation();
13557 event.preventDefault();
13558 if (!self.parent.disabled) {
13559 self._mousemove(event);
13563 this._bindEvent(documentElt, "down", function(event) {
13565 event.stopPropagation();
13566 event.preventDefault();
13569 this._bindEvent(documentElt, "up", function(event) {
13570 self._mouseup(event);
13573 this._bindEvent( this.ptr, "down", function(event) {
13574 self._mousedown( event );
13577 this._bindEvent( this.ptr, "up", function(event) {
13578 self._mouseup( event );
13584 Draggable.prototype._mousedown = function( evt ){
13585 this.is.drag = true;
13586 this.is.clicked = false;
13587 this.is.mouseup = false;
13589 var coords = this._getPageCoords( evt );
13590 this.cx = coords.x - this.ptr[0].offsetLeft;
13591 this.cy = coords.y - this.ptr[0].offsetTop;
13593 angular.extend(this.d, {
13594 left: this.ptr[0].offsetLeft,
13595 top: this.ptr[0].offsetTop,
13596 width: this.ptr[0].clientWidth,
13597 height: this.ptr[0].clientHeight
13600 if( this.outer && this.outer.get(0) ){
13601 this.outer.css({ height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden" });
13604 this.onmousedown( evt );
13607 Draggable.prototype._mousemove = function( evt ){
13612 this.is.toclick = false;
13613 var coords = this._getPageCoords( evt );
13614 this.onmousemove( evt, coords.x - this.cx, coords.y - this.cy );
13617 Draggable.prototype._mouseup = function( evt ){
13620 if( this.is.drag ){
13621 this.is.drag = false;
13623 if( this.outer && this.outer.get(0) ) {
13625 if( $.browser.mozilla ){
13626 this.outer.css({ overflow: "hidden" });
13628 this.outer.css({ overflow: "visible" });
13631 if( $.browser.msie && $.browser.version == '6.0' ){
13632 this.outer.css({ height: "100%" });
13634 this.outer.css({ height: "auto" });
13638 this.onmouseup( evt );
13644 .factory('sliderPointer', ['sliderDraggable', 'utils', function(Draggable, utils) {
13647 The MIT License (MIT)
13648 Copyright (c) 2013 Julien Valéry
13650 function SliderPointer() {
13651 Draggable.apply(this, arguments);
13654 SliderPointer.prototype = new Draggable();
13656 SliderPointer.prototype.oninit = function(ptr, id, _constructor) {
13658 this.parent = _constructor;
13660 this.settings = angular.copy(_constructor.settings);
13663 SliderPointer.prototype.onmousedown = function(evt) {
13665 var off = utils.offset(this.parent.domNode);
13670 width: this.parent.domNode[0].clientWidth,
13671 height: this.parent.domNode[0].clientHeight
13676 width: offset.width,
13677 height: offset.height
13680 this.ptr.addClass("jslider-pointer-hover");
13681 this.setIndexOver();
13684 SliderPointer.prototype.onmousemove = function(evt, x, y) {
13685 var coords = this._getPageCoords( evt );
13687 //val is the percent where the slider pointer is located
13688 var val = this.calc(coords.x);
13690 if(!this.parent.settings.smooth){
13692 val = utils.roundUpToScale(val,
13693 this.parent.settings.scale,
13694 this.parent.settings.cutOffWidth,
13695 this.parent.settings.cutOffIndex);
13699 var cutOffWidth = this.parent.settings.cutOffWidth;
13701 var valPrc = val + (4/5000);
13703 if(cutOffWidth && val < cutOffWidth)
13709 SliderPointer.prototype.onmouseup = function(evt) {
13711 if( this.settings.callback && angular.isFunction(this.settings.callback) ){
13712 var val = this.parent.getValue();
13713 this.settings.callback.call( this.parent, val);
13716 this.ptr.removeClass("jslider-pointer-hover");
13719 SliderPointer.prototype.setIndexOver = function() {
13720 this.parent.setPointersIndex(1);
13724 SliderPointer.prototype.index = function(i) {
13727 SliderPointer.prototype.limits = function(x) {
13728 return this.parent.limits(x, this);
13731 SliderPointer.prototype.calc = function(coords) {
13732 var diff = coords-this._parent.offset.left;
13733 var val = this.limits( (diff*100)/this._parent.width);
13737 SliderPointer.prototype.set = function(value, opt_origin) {
13738 this.value.origin = this.parent.round(value);
13739 this._set(this.parent.valueToPrc(value,this), opt_origin);
13742 SliderPointer.prototype._set = function(prc, opt_origin) {
13744 this.value.origin = this.parent.prcToValue(prc);
13746 this.value.prc = prc;
13748 //Sets the location of the SliderPointer
13749 this.ptr.css({left:prc+'%'});
13750 this.parent.redraw(this);
13753 return SliderPointer;
13755 .factory('slider', ['sliderPointer', 'sliderConstants', 'utils', function(SliderPointer, sliderConstants, utils) {
13758 The MIT License (MIT)
13759 Copyright (c) 2013 Julien Valéry
13763 function Slider() {
13764 return this.init.apply( this, arguments );
13767 function changeCutOffWidth(width){
13768 cutOffDom.css('width',width);
13771 Slider.prototype.changeCutOffWidth = changeCutOffWidth;
13773 Slider.prototype.init = function( inputNode, templateNode, settings ){
13774 this.settings = sliderConstants.SLIDER.settings;
13775 angular.extend(this.settings, angular.copy(settings));
13777 this.inputNode = inputNode;
13778 this.inputNode.addClass("ng-hide");
13780 this.settings.interval = this.settings.to-this.settings.from;
13782 if( this.settings.calculate && $.isFunction( this.settings.calculate ) )
13783 this.nice = this.settings.calculate;
13785 if( this.settings.onstatechange && $.isFunction( this.settings.onstatechange ) )
13786 this.onstatechange = this.settings.onstatechange;
13788 this.is = { init: false };
13791 this.create(templateNode);
13794 Slider.prototype.create = function(templateNode){
13797 this.domNode = templateNode;
13799 var off = utils.offset(this.domNode);
13804 width: this.domNode[0].clientWidth,
13805 height: this.domNode[0].clientHeight
13808 this.sizes = { domWidth: this.domNode[0].clientWidth, domOffset: offset };
13810 angular.extend(this.o, {
13814 o : angular.element(this.domNode.find('div')[5])
13817 o : angular.element(this.domNode.find('div')[6])
13821 0: angular.element(this.domNode.find('div')[3]),
13822 1: angular.element(this.domNode.find('div')[5])
13826 angular.extend(this.o.labels[0], {
13827 value: this.o.labels[0].o.find("span")
13830 angular.extend(this.o.labels[1], {
13831 value: this.o.labels[1].o.find("span")
13834 if( !$this.settings.value.split(";")[1] ) {
13835 this.settings.single = true;
13840 var domNodeDivs = this.domNode.find('div');
13841 cutOffDom = angular.element(domNodeDivs[8]);
13842 if(cutOffDom && cutOffDom.css)
13843 cutOffDom.css('width','0%');
13845 var pointers = [ angular.element(domNodeDivs[1]), angular.element(domNodeDivs[2]) ];
13847 angular.forEach(pointers, function(pointer, key ) {
13848 $this.settings = angular.copy($this.settings);
13849 var value = $this.settings.value.split(';')[key];
13851 $this.o.pointers[key] = new SliderPointer( pointer, key, $this );
13853 var prev = $this.settings.value.split(';')[key-1];
13854 if( prev && parseInt(value, 10) < parseInt(prev, 10 )) value = prev;
13856 var value1 = value < $this.settings.from ? $this.settings.from : value;
13857 value1 = value > $this.settings.to ? $this.settings.to : value;
13859 $this.o.pointers[key].set( value1, true );
13862 $this.domNode.bind('mousedown', $this.clickHandler.apply($this));
13867 this.o.value = angular.element(this.domNode.find("i")[2]);
13868 this.is.init = true;
13870 angular.forEach(this.o.pointers, function(pointer, key){
13871 $this.redraw(pointer);
13876 Slider.prototype.clickHandler = function() {
13880 return function(evt) {
13885 var className = evt.target.className;
13888 if (className.indexOf('jslider-pointer-to') > 0) {
13892 var _off = utils.offset(self.domNode);
13897 width: self.domNode[0].clientWidth,
13898 height: self.domNode[0].clientHeight
13902 var targetPtr = self.o.pointers[targetIdx];
13904 targetPtr._parent = { offset: offset, width: offset.width, height: offset.height};
13905 targetPtr._mousemove(evt);
13906 targetPtr.onmouseup();
13913 Slider.prototype.disable = function(bool) {
13914 this.disabled = bool;
13917 Slider.prototype.nice = function( value ){
13921 Slider.prototype.onstatechange = function(){};
13923 Slider.prototype.limits = function( x, pointer ){
13925 if( !this.settings.smooth ){
13926 var step = this.settings.step*100 / ( this.settings.interval );
13927 x = Math.round( x/step ) * step;
13930 var another = this.o.pointers[1-pointer.uid];
13931 if( another && pointer.uid && x < another.value.prc )
13932 x = another.value.prc;
13933 if( another && !pointer.uid && x > another.value.prc )
13934 x = another.value.prc;
13937 if( x > 100 ) x = 100;
13939 var val = Math.round( x*10) / 10;
13943 Slider.prototype.setPointersIndex = function( i ){
13944 angular.forEach(this.getPointers(), function(pointer, i) {
13945 pointer.index( i );
13949 Slider.prototype.getPointers = function(){
13950 return this.o.pointers;
13953 Slider.prototype.onresize = function(){
13957 domWidth: this.domNode[0].clientWidth,
13958 domHeight: this.domNode[0].clientHeight,
13960 left: this.domNode[0].offsetLeft,
13961 top: this.domNode[0].offsetTop,
13962 width: this.domNode[0].clientWidth,
13963 height: this.domNode[0].clientHeight
13967 angular.forEach(this.o.pointers, function(ptr, key) {
13972 Slider.prototype.update = function(){
13977 Slider.prototype.drawScale = function(){
13980 Slider.prototype.redraw = function( pointer ){
13982 if(!this.settings.smooth){
13984 var newMousePrc = utils.roundUpToScale(pointer.value.prc,
13985 this.settings.scale,
13986 this.settings.cutOffWidth,
13987 this.settings.cutOffIndex);
13989 pointer.value.origin = newMousePrc;
13990 pointer.value.prc = newMousePrc;
13993 if( !this.is.init )
13998 var width = this.o.pointers[1].value.prc;
13999 var newPos = {left:'0%', width:width + '%'};
14001 this.o.value.css(newPos);
14003 var htmlValue = this.nice(pointer.value.origin);
14004 var scaledDimension=this.settings.firstDimension;
14006 if(this.settings.stepWithDifferentScale && !this.settings.smooth){
14007 htmlValue = utils.valueForDifferentScale(this.settings.from,
14008 this.settings.to,htmlValue, this.settings.prcToValueMapper);
14011 //This is the base value before the conversion
14012 if( this.settings.realtimeCallback && angular.isFunction(this.settings.realtimeCallback)
14013 && this.settings.cutOffVal != undefined && pointer.uid == 1){
14015 this.settings.realtimeCallback(htmlValue);
14018 //Need to change this to the correct value for the scale
14019 if(this.settings.conversion){
14020 var conversionObj = utils.getConversionFactorValue(parseInt(htmlValue),
14021 this.settings.conversion,
14022 this.settings.firstDimension);
14024 htmlValue = conversionObj.scaledVal;
14025 scaledDimension = conversionObj.scaledDimension;
14028 //Check if we need to round the decimal places
14029 if(this.settings.decimalPlaces || this.settings.decimalPlaces == 0){
14030 if(typeof htmlValue == 'number'){
14031 htmlValue = htmlValue.toFixed(this.settings.decimalPlaces);
14035 this.o.labels[pointer.uid].value.html(htmlValue+' '+scaledDimension);
14037 //Top tooltip label
14038 this.redrawLabels(pointer);
14041 Slider.prototype.redrawLabels = function( pointer ) {
14043 function setPosition( label, sizes, prc ){
14044 sizes.margin = -sizes.label/2;
14045 var domSize = self.sizes.domWidth;
14047 var label_left = sizes.border + sizes.margin;
14048 if( label_left < 0 )
14049 sizes.margin -= label_left;
14051 if( sizes.border+sizes.label / 2 > domSize ){
14053 sizes.right = true;
14055 sizes.right = false;
14057 //Adjust the tooltip location
14058 sizes.margin = -((label.o[0].clientWidth/2) - label.o[0].clientWidth/20);
14060 label.o.css({ left: prc + "%", marginLeft: sizes.margin, right: "auto" });
14063 label.o.css({ left: "auto", right: 0 });
14069 var label = this.o.labels[pointer.uid];
14070 var prc = pointer.value.prc;
14073 label: label.o[0].offsetWidth,
14075 border: ( prc * domSize ) / 100
14078 var another_label = null;
14079 var another = null;
14081 if (!this.settings.single){
14082 another = this.o.pointers[1-pointer.uid];
14083 another_label = this.o.labels[another.uid];
14085 switch( pointer.uid ){
14087 if( sizes.border+sizes.label / 2 > another_label.o[0].offsetLeft-this.sizes.domOffset.left ){
14088 another_label.o.css({ visibility: "hidden" });
14090 another_label.value.html( this.nice( another.value.origin ) );
14092 label.o.css({ visibility: "hidden" });
14094 prc = ( another.value.prc - prc ) / 2 + prc;
14095 if( another.value.prc != pointer.value.prc ){
14096 label.value.html( this.nice(pointer.value.origin) + " – " + this.nice(another.value.origin) );
14098 sizes.label = label.o[0].clientWidth;
14099 sizes.border = ( prc * domSize ) / 100;
14102 another_label.o.css({ visibility: "visible" });
14106 if( sizes.border - sizes.label / 2 < another_label.o[0].offsetLeft - this.sizes.domOffset.left + another_label.o[0].clientWidth ){
14107 another_label.o.css({ visibility: "hidden" });
14108 another_label.value.html( this.nice(another.value.origin) );
14110 label.o.css({ visibility: "visible" });
14112 prc = ( prc - another.value.prc ) / 2 + another.value.prc;
14114 if( another.value.prc != pointer.value.prc ){
14115 label.value.html( this.nice(another.value.origin) + " – " + this.nice(pointer.value.origin) );
14116 sizes.label = label.o[0].clientWidth;
14117 sizes.border = ( prc * domSize ) / 100;
14120 another_label.o.css({ visibility: "visible" });
14126 sizes = setPosition( label, sizes, prc );
14128 var domSize = self.sizes.domWidth;
14130 //This is the 0th pointer
14131 if( another_label ){
14134 label: another_label.o[0].clientWidth,
14136 border: ( another.value.prc * this.sizes.domWidth ) / 100
14139 sizes = setPosition( another_label, sizes, another.value.prc );
14143 Slider.prototype.redrawLimits = function() {
14145 if( this.settings.limits ) {
14147 var limits = [ true, true ];
14149 for( var key in this.o.pointers ){
14151 if( !this.settings.single || key === 0 ){
14153 var pointer = this.o.pointers[key];
14154 var label = this.o.labels[pointer.uid];
14155 var label_left = label.o[0].offsetLeft - this.sizes.domOffset.left;
14157 var limit = this.o.limits[0];
14158 if( label_left < limit[0].clientWidth )
14161 limit = this.o.limits[1];
14162 if( label_left + label.o[0].clientWidth > this.sizes.domWidth - limit[0].clientWidth )
14167 for( var i=0; i < limits.length; i++ ){
14169 angular.element(this.o.limits[i]).addClass("animate-show");
14171 angular.element(this.o.limits[i]).addClass("animate-hidde");
14176 Slider.prototype.setValue = function(){
14177 var value = this.getValue();
14178 this.inputNode.attr( "value", value );
14179 this.onstatechange.call( this, value, this.inputNode );
14182 Slider.prototype.getValue = function(){
14189 angular.forEach( this.o.pointers, function(pointer, key){
14190 if( pointer.value.prc !== undefined && !isNaN(pointer.value.prc) ) {
14192 var pointerPrc = pointer.value.prc;
14194 var myValue = $this.prcToValue(pointerPrc);
14196 if(!$this.settings.smooth){
14197 var myValue = utils.valueForDifferentScale($this.settings.from,
14200 $this.settings.prcToValueMapper);
14203 value += (key > 0 ? ";" : "") +myValue;
14211 Slider.prototype.getPrcValue = function(){
14212 if(!this.is.init) return false;
14216 $.each( this.o.pointers, function(i){
14217 if( this.value.prc !== undefined && !isNaN(this.value.prc) )
14218 value += (i > 0 ? ";" : "") + this.value.prc;
14223 Slider.prototype.prcToValue = function( prc ){
14225 if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){
14226 var h = this.settings.heterogeneity;
14229 var _from = this.settings.from;
14231 for( var i=0; i <= h.length; i++ ){
14234 v = h[i].split("/");
14236 v = [100, this.settings.to];
14238 if( prc >= _start && prc <= v[0] ) {
14239 value = _from + ( (prc-_start) * (v[1]-_from) ) / (v[0]-_start);
14247 value = this.settings.from + ( prc * this.settings.interval ) / 100;
14250 var roundedValue = this.round(value);
14251 return roundedValue;
14254 Slider.prototype.valueToPrc = function( value, pointer ){
14257 if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){
14258 var h = this.settings.heterogeneity;
14261 var _from = this.settings.from;
14263 for (var i=0; i <= h.length; i++) {
14266 v = h[i].split("/");
14268 v = [100, this.settings.to];
14270 if(value >= _from && value <= v[1]){
14271 prc = pointer.limits(_start + (value-_from)*(v[0]-_start)/(v[1]-_from));
14274 _start = v[0]; _from = v[1];
14278 prc = pointer.limits((value-this.settings.from)*100/this.settings.interval);
14284 Slider.prototype.round = function( value ){
14286 value = Math.round( value / this.settings.step ) * this.settings.step;
14288 if( this.settings.round )
14289 value = Math.round( value * Math.pow(10, this.settings.round) ) / Math.pow(10, this.settings.round);
14291 value = Math.round( value );
14298 .directive('attStepSlider', [
14299 '$compile', '$templateCache','$timeout', '$window', 'slider', 'sliderConstants','utils',
14300 function(compile, templateCache, timeout, win, Slider, sliderConstants,utils) {
14303 The MIT License (MIT)
14304 Copyright (c) 2013 Julien Valéry
14307 var templateUrl = 'app/scripts/ng_js_att_tpls/slider/attStepSlider.html';
14311 require: '?ngModel',
14317 templateUrl: templateUrl,
14318 link : function(scope, element, attrs, ngModel) {
14319 if(!ngModel) return;
14321 scope.mainSliderClass = 'step-slider';
14323 element.after(compile(templateCache.get(templateUrl))(scope, function(clonedElement, scope) {
14324 scope.tmplElt = clonedElement;
14327 ngModel.$render = function () {
14328 var singleValue = false;
14330 if(ngModel.$viewValue.split && ngModel.$viewValue.split(";").length == 1){
14331 ngModel.$viewValue = '0;'+ngModel.$viewValue;
14332 }else if(typeof(ngModel.$viewValue) === 'number'){
14333 ngModel.$viewValue = '0;'+ngModel.$viewValue;
14336 if (!ngModel.$viewValue && ngModel.$viewValue !== 0) {
14340 if (typeof(ngModel.$viewValue) === 'number') {
14341 ngModel.$viewValue = ''+ngModel.$viewValue;
14344 if (scope.slider) {
14345 var firstPointer ='0';
14346 var secondPointer =ngModel.$viewValue.split(";")[1];
14348 scope.slider.getPointers()[0].set(firstPointer, true);
14350 if (ngModel.$viewValue.split(";")[1]) {
14351 var value = ngModel.$viewValue.split(";")[1];
14352 if(value.length >= 4){
14353 value = value.substring(0,2);
14356 if(!scope.options.realtime)
14357 scope.options.callback(parseFloat(ngModel.$viewValue.split(";")[1]));
14359 scope.slider.getPointers()[1].set(ngModel.$viewValue.split(";")[1], true);
14364 var init = function() {
14366 scope.from = ''+scope.options.from;
14367 scope.to = ''+scope.options.to;
14369 if (scope.options.calculate && typeof scope.options.calculate === 'function') {
14370 scope.from = scope.options.calculate(scope.from);
14371 scope.to = scope.options.calculate(scope.to);
14374 scope.showDividers = scope.options.showDividers;
14375 scope.COLORS = sliderConstants.COLORS;
14377 scope.sliderColor = scope.options.sliderColor;
14378 if(!scope.sliderColor)
14379 scope.sliderColor = sliderConstants.COLORS.REGULAR;
14381 var scaleArray = scope.options.scale;
14384 //Make a copy of the scaleArray before converting it to percentage for the bars
14385 var nonPercentScaleArray = [];
14387 //Create Mapper for the percentage to value
14388 var prcToValueMapper = {};
14390 for(var i in scaleArray){
14391 var s = scaleArray[i];
14392 nonPercentScaleArray.push(s);
14395 function addScaleArrayStartAndEnd(){
14396 if(scaleArray[0] != 0){
14397 scaleArray.splice(0,0,0);
14400 if(scaleArray[scaleArray.length - 1] != 100){
14401 scaleArray.splice(scaleArray.length, 0, 100);
14405 function convertScaleArrayToPercentage(){
14407 if(scaleArray[scaleArray.length - 1] != scope.options.to){
14408 scaleArray.splice(scaleArray.length, 0, scope.options.to);
14411 for(var i in scaleArray){
14413 var fromValueCheck = (scaleArray[i]/scope.options.from);
14414 var toValueCheck = (scaleArray[i]/scope.options.to);
14416 var prcValue = ( (scaleArray[i] - scope.options.from)/ (scope.options.to - scope.options.from))*100;
14417 var realValue = scaleArray[i];
14419 if(toValueCheck == 1){
14422 else if(fromValueCheck == 1){
14426 scaleArray[i] = prcValue;
14428 prcToValueMapper[''+prcValue] = realValue;
14434 if( (scope.options.from != 0 || scope.options.to != 100)
14435 && scope.options.smooth){
14437 scale array is in real values.
14439 addScaleArrayStartAndEnd();
14440 scope.options.stepWithDifferentScale = true;
14442 for(var i in scaleArray){
14443 scaleArray[i] = (scaleArray[i]/100)*scope.options.to;
14447 else if( (scope.options.from != 0 || scope.options.to != 100)
14448 && !scope.options.smooth){
14450 Case for different from and to values other than 0 and 100
14451 so we have to do some different calculations
14453 scope.options.stepWithDifferentScale = true;
14454 convertScaleArrayToPercentage();
14455 addScaleArrayStartAndEnd();
14459 This is the normal case where the from and to values are 0 and
14462 //Check that the scale starts at 0 and 100
14463 convertScaleArrayToPercentage();
14464 addScaleArrayStartAndEnd();
14467 var decimalPlaces = 0;
14468 if(scope.options.decimalPlaces){
14469 decimalPlaces = scope.options.decimalPlaces;
14472 //Modify the endDimension based on whether converison was passed in
14473 //Also change the toStr value to scale to the last factor
14474 scope.endDimension = scope.options.dimension;
14476 if(scope.options.conversion){
14477 //Get the dimension of the last conversion
14478 var lastIndex = scope.options.conversion.length - 1;
14479 var lastDimension = scope.options.conversion[lastIndex].dimension;
14480 var lastScaleFactor = scope.options.conversion[lastIndex].scaleFactor;
14481 scope.endDimension = " "+lastDimension;
14483 var toVal = (scope.to/lastScaleFactor).toFixed(decimalPlaces);
14484 scope.toStr = toVal;
14486 scope.toStr = scope.options.to;
14490 from: scope.options.from,
14491 to: scope.options.to,
14492 step: scope.options.step,
14493 smooth: scope.options.smooth,
14495 stepWithDifferentScale: scope.options.stepWithDifferentScale,
14496 round: scope.options.round || false,
14497 value: ngModel.$viewValue,
14498 scale: scope.options.scale,
14499 nonPercentScaleArray: nonPercentScaleArray,
14500 prcToValueMapper: prcToValueMapper,
14501 firstDimension:scope.options.dimension,
14502 decimalPlaces: decimalPlaces,
14503 conversion: scope.options.conversion,
14504 realtimeCallback: scope.options.callback
14507 if(angular.isFunction(scope.options.realtime)){
14508 OPTIONS.realtimeCallback = function(value){
14509 ngModel.$setViewValue(value);
14510 scope.options.callback(value);
14514 OPTIONS.callback = forceApply;
14517 OPTIONS.calculate = scope.options.calculate || undefined;
14518 OPTIONS.onstatechange = scope.options.onstatechange || undefined;
14521 //timeout(function() {
14523 var scaleDiv = scope.tmplElt.find('div')[7];
14524 if(!OPTIONS.conversion){
14526 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-left', '10px');
14527 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-right', '15px');
14531 scope.slider = angular.element.slider(element, scope.tmplElt, OPTIONS);
14532 angular.element(scaleDiv).html(scope.generateScale());
14533 scope.drawScale(scaleDiv);
14536 scope.$watch('options.disable',function(val){
14537 if (scope.slider) {
14538 scope.tmplElt.toggleClass('disabled',val);
14539 scope.slider.disable(val);
14543 scope.$watch('cutOff', function(cutOffVal){
14547 if(cutOffVal && cutOffVal > 0){
14549 var cutOffPrc = (cutOffVal - scope.slider.settings.from)/(scope.slider.settings.to -
14550 scope.slider.settings.from);
14551 cutOffPrc = cutOffPrc*100;
14553 scope.isCutOffSlider = true;
14554 scope.slider.settings.cutOffWidth = cutOffPrc;
14556 //cutOffVal is the actual value of the cutoff point
14557 scope.cutOffVal = cutOffVal;
14558 if(scope.options.conversion){
14559 var convertedVal = utils.getConversionFactorValue(cutOffVal, scope.options.conversion, scope.options.dimension);
14560 convertedVal.scaledVal = parseFloat(convertedVal.scaledVal).toFixed(scope.options.decimalPlaces);
14561 scope.cutOffVal = convertedVal.scaledVal +' '+convertedVal.scaledDimension;
14563 scope.slider.settings.cutOffVal = cutOffVal;
14564 //Calculate the cutOff percentage
14565 scope.slider.changeCutOffWidth(cutOffPrc + '%');
14567 var scale = scope.slider.settings.nonPercentScaleArray;
14569 //Calculate where the cutOff point in relation to the scale array
14570 for(var i in scale){
14572 var lowerVal = scale[i - 1];
14573 var higherVal = scale[i];
14575 if(cutOffVal > lowerVal && cutOffVal <= higherVal){
14576 scope.slider.settings.cutOffIndex = i;
14583 scope.slider.settings.cutOffVal = 0;
14591 function initListener() {
14592 angular.element(win).bind('resize', function(event) {
14593 scope.slider.onresize();
14597 scope.generateScale = function(){
14598 if( scope.options.scale && scope.options.scale.length > 0 ){
14600 var s = scope.options.scale;
14601 var position = 'left';
14603 for(var i=0; i < s.length; i++){
14604 if(i != 0 && i != s.length - 1){
14606 var scaledPosition = ( (s[i] - scope.from)/(scope.to - scope.from))*100;
14607 if(scope.options.stepWithDifferentScale && !scope.options.smooth){
14608 scaledPosition = s[i];
14610 str += '<span style="'+ position + ': ' + scaledPosition+ '%"></span>';
14619 scope.drawScale = function(scaleDiv){
14620 angular.forEach(angular.element(scaleDiv).find('ins'), function(scaleLabel, key) {
14621 scaleLabel.style.marginLeft = - scaleLabel.clientWidth / 2;
14625 var forceApply = function(value) {
14626 var val = value.split(";")[1];
14628 scope.$apply(function() {
14629 ngModel.$setViewValue(parseInt(val));
14631 if (scope.options.callback){
14632 scope.options.callback(parseInt(val));
14637 scope.$watch('options', function(value) {
14641 angular.element.slider = function( inputElement, element, settings) {
14642 if(!element.data('jslider'))
14643 element.data('jslider', new Slider( inputElement, element, settings ));
14644 var sliderObj = element.data('jslider');
14651 angular.module('att.abs.splitButtonDropdown', ['att.abs.utilities'])
14652 .directive('attButtonDropdown', ['$document', '$parse', '$documentBind', function($document, $parse, $documentBind) {
14657 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html',
14664 link: function(scope, element, attr) {
14665 scope.isSmall = false;
14666 scope.isDropDownOpen = false;
14667 scope.isActionDropdown = false;
14670 if (attr.small === "") {
14671 scope.isSmall = true;
14674 if (!(scope.btnText)) {
14675 scope.isActionDropdown = true;
14678 scope.clickFxn = function() {
14679 if(typeof scope.btnClick === "function" && !scope.btnLink){
14680 scope.btnClick = $parse(scope.btnClick);
14685 scope.toggleDropdown = function() {
14686 if (!(scope.btnType === 'disabled')) {
14687 flag = scope.isDropDownOpen = !scope.isDropDownOpen;
14691 scope.showDropdown = function() {
14692 if (!(scope.btnType === 'disabled')) {
14693 scope.isDropDownOpen = true;
14698 scope.hideDropdown = function() {
14699 if (!(scope.btnType === 'disabled')) {
14700 scope.isDropDownOpen = false;
14705 var outsideClick = function(e) {
14707 scope.$apply(function() {
14708 scope.isDropDownOpen = false;
14714 $documentBind.click('isDropDownOpen', outsideClick, scope);
14716 attr.$observe('btnType', function(val) {
14717 scope.btnType = val;
14723 .constant('iconStateConstants', {
14727 NEXT_TO_DROPDOWN:'next-to-dropdown',
14728 LEFT_NEXT_TO_DROPDOWN:'left-next-to-dropdown',
14740 SPLIT_ICON_BTN_EVENT_EMITTER_KEY: 'splitIconButtonTap'
14742 .directive('expandableLine', ['$document',function($document){
14747 require: ['^attSplitIconButton', 'expandableLine'],
14748 controller: ['$scope', function($scope){
14749 $scope.isActive = false;
14750 this.setActiveState = function(isActive){
14751 $scope.isActive = isActive;
14754 this.isActive = $scope.isActive;
14755 this.dirType = $scope.dirType;
14757 template: '<div ng-class="{\'expand-line-container\': !isActive, \'expand-line-container-active\': isActive}"> <div ng-class="{\'hovered-line\':isActive, \'vertical-line\':!isActive}"> </div></div>',
14761 link: function(scope,element,attr,ctrls){
14762 var attSplitIconButtonCtrl = ctrls[0];
14763 var expandableLineCtrl = ctrls[1];
14764 attSplitIconButtonCtrl.addSubCtrl(expandableLineCtrl);
14768 .controller('AttSplitIconCtrl', ['$scope', function($scope){
14769 this.setType = function(type){
14770 $scope.type = type;
14773 this.isDropdown = function(isDropdown){
14774 $scope.isDropdown = isDropdown;
14777 this.dropDownClicked = function(){
14778 if($scope.dropDownClicked)
14779 $scope.dropDownClicked();
14782 this.dirType = $scope.dirType;
14785 .directive('attSplitIcon', ['$document', '$timeout','iconStateConstants','$documentBind','events',
14786 function($document,$timeout,iconStateConstants,$documentBind, events){
14792 require: ['^attSplitIconButton','attSplitIcon'],
14793 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIcon.html',
14797 dropDownWatch: '=',
14800 controller:'AttSplitIconCtrl',
14801 link: function(scope,element,attr,ctrls){
14803 var attSplitIconButtonCtrl = ctrls[0];
14804 var attSplitIconCtrl = ctrls[1];
14805 attSplitIconButtonCtrl.addSubCtrl(attSplitIconCtrl);
14807 scope.iconStateConstants = iconStateConstants;
14809 var currentIndex = 0;
14810 var isMyElement = false;
14813 scope.isDropdown = false;
14814 scope.isDropdownOpen = false;
14817 scope.$on(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, function(evnt, data){
14818 if(typeof data == 'boolean' && data){
14819 scope.dropDownClicked();
14822 Check if the dropdown is open and if we are selecting one
14823 of the items, so that when pressing enter it will trigger it.
14825 if(scope.isDropDownOpen){
14826 listElements[currentIndex].eq(0).find('a')[0].click();
14831 //Only trigger the keyboard event if the icon button is a dropdown type
14832 if(scope.isDropdown)
14833 triggerKeyboardEvents(e);
14836 function triggerKeyboardEvents(e){
14837 if(e.which == iconStateConstants.KEYBOARD.ESC){
14840 if( e.which == iconStateConstants.KEYBOARD.UP ||
14841 e.which == iconStateConstants.KEYBOARD.DOWN){
14843 e.preventDefault();
14844 events.stopPropagation(e);
14845 //e.stopPropagation();
14847 if(e.which == iconStateConstants.KEYBOARD.DOWN){
14848 //Dropdown is open and the user taps down again
14850 if(scope.isDropDownOpen){
14851 //Now we need to go through the rows in the dropdown
14852 scope.nextItemInDropdown();
14854 //Dropdown is not open
14856 isMyElement = true;
14858 listElementsInit();
14861 else if(e.which == iconStateConstants.KEYBOARD.UP){
14862 if(scope.isDropDownOpen){
14863 scope.previousItemInDropdown();
14869 isMyElement = false;
14872 }else if(e.which == iconStateConstants.KEYBOARD.ENTER){
14873 if(scope.isDropDownOpen){
14874 listElementsInit();
14880 function listElementsInit(){
14881 if(listElements == undefined){
14883 var liTemps = element.find('li');
14884 for(var i = 0; i < liTemps.length; i++){
14885 listElements.push(liTemps.eq(i));
14887 listElements[currentIndex].children().eq(0).addClass('selected-item');
14893 scope.nextItemInDropdown = function(){
14894 if(listElements && currentIndex < listElements.length - 1){
14896 listElements[currentIndex - 1].children().eq(0).removeClass('selected-item');
14897 listElements[currentIndex].children().eq(0).addClass('selected-item');
14901 scope.previousItemInDropdown = function(){
14902 if(currentIndex > 0){
14904 listElements[currentIndex].children().eq(0).addClass('selected-item');
14906 if(currentIndex + 1 < listElements.length)
14907 listElements[currentIndex + 1].children().eq(0).removeClass('selected-item');
14911 scope.$watch('isIconHovered', function(val){
14912 scope.hoverWatch = val;
14915 scope.$watch('type', function(val){
14917 function toggleValues(isMiddle,isNextToDropDown,isRight,isLeft,isLeftNextDropdown){
14918 scope['isMiddle'] = isMiddle;
14919 scope['isNextToDropDown'] = isNextToDropDown;
14920 scope['isRight'] = isRight;
14921 scope['isLeft'] = isLeft;
14922 scope['isLeftNextDropdown'] = isLeftNextDropdown;
14925 if(val == scope.iconStateConstants.MIDDLE){
14926 toggleValues(true,false,false,true,false);
14928 else if(val == scope.iconStateConstants.LEFT){
14929 toggleValues(false,false,false,true,false);
14931 else if(val == scope.iconStateConstants.RIGHT){
14932 toggleValues(false,false,true,false,false);
14933 }else if(val == scope.iconStateConstants.NEXT_TO_DROPDOWN){
14934 toggleValues(false,true,true,true,false);
14935 }else if(val == scope.iconStateConstants.LEFT_NEXT_TO_DROPDOWN){
14936 toggleValues(false,false,false,true,true);
14940 if(attr.dropDownId && attr.dropDownId != ''){
14941 scope.dropDownId = attr.dropDownId;
14942 scope.isDropdown = true;
14945 scope.dropDownClicked = function(){
14946 isMyElement = true;
14949 scope.toggleDropdown = function(val) {
14950 if(val != undefined)
14951 scope.isDropDownOpen=val;
14953 scope.isDropDownOpen = !scope.isDropDownOpen;
14955 scope.dropDownWatch = scope.isDropDownOpen;
14958 var outsideClick = function(e) {
14959 if(scope.isDropdown){
14961 isMyElement = false;
14962 scope.toggleDropdown();
14964 scope.toggleDropdown(false);
14970 $documentBind.click('isDropdown', outsideClick, scope);
14974 .controller('AttSplitIconButtonCtrl',['$scope', 'iconStateConstants',function($scope,iconStateConstants){
14976 this.subCtrls = [];
14978 $scope.isLeftLineShown=true;
14979 $scope.isRightLineShown=true;
14980 $scope.childrenScopes = [];
14982 var origLeftLineShown = $scope.isLeftLineShown;
14983 var origRightLineShown = $scope.isRightLineShown;
14987 function getDirIndex(dirType){
14989 for(var c in that.subCtrls){
14990 var ctrl = that.subCtrls[c];
14991 if(ctrl.dirType==dirType){
14999 this.addSubCtrl = function(sub){
15000 this.subCtrls.push(sub);
15003 this.isLeftLineShown = function(isShown){
15004 if(isShown == undefined)
15005 return $scope.isLeftLineShown;
15007 $scope.isLeftLineShown = isShown;
15010 this.isRightLineShown = function(isShown){
15011 if(isShown == undefined)
15012 return $scope.isRightLineShown;
15014 $scope.isRightLineShown = isShown;
15017 this.setLeftLineHover = function(isHovered){
15018 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
15020 if($scope.isLeftLineShown){
15021 if(this.subCtrls[leftLineIndex] && this.subCtrls[leftLineIndex].setActiveState){
15022 this.subCtrls[leftLineIndex].setActiveState(isHovered);
15027 this.setRightLineHover = function(isHovered){
15028 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
15029 if($scope.isRightLineShown){
15030 if(this.subCtrls[rightLineIndex] && this.subCtrls[rightLineIndex].setActiveState){
15031 this.subCtrls[rightLineIndex].setActiveState(isHovered);
15036 this.toggleLines = function(isHovered,buttonGroupCtrl,buttonCtrl,isDropDownOpen){
15038 var subIconButtons = buttonGroupCtrl.subIconButtons;
15039 var subIconButtonsLength = subIconButtons.length;
15041 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
15042 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
15044 function noVerticalLineToggle(){
15045 for(var i =0; i < subIconButtonsLength; i++){
15046 if(subIconButtons[i] == buttonCtrl){
15047 if(i + 1 <= subIconButtonsLength - 1){
15048 if(subIconButtons[i+1].isLeftLineShown() && subIconButtons[i+1].subCtrls[leftLineIndex]
15049 && subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState)
15050 subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState(isHovered);
15053 if(subIconButtons[i-1].isRightLineShown() && subIconButtons[i-1].subCtrls[rightLineIndex]
15054 && subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState)
15055 subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState(isHovered);
15062 if(isDropDownOpen){
15064 If the button is next to the dropdown button then just keep the
15065 buttons left line or its left neighbors right line toggled on
15066 If the button is the dropdown button don't do anything
15067 else do things normally witht the button
15069 if(subIconButtons[subIconButtonsLength-1] == buttonCtrl){
15072 else if(subIconButtons[subIconButtonsLength-2]==buttonCtrl){
15073 if(subIconButtons[subIconButtonsLength-2].isLeftLineShown())
15074 subIconButtons[subIconButtonsLength-2].subCtrls[leftLineIndex].setActiveState(isHovered);
15075 else if(subIconButtonsLength - 3 >= 0){
15076 if(subIconButtons[subIconButtonsLength-3].isRightLineShown())
15077 subIconButtons[subIconButtonsLength-3].subCtrls[rightLineIndex].setActiveState(isHovered);
15081 noVerticalLineToggle();
15083 if($scope.isLeftLineShown){
15084 this.subCtrls[leftLineIndex].setActiveState(isHovered);
15087 if($scope.isRightLineShown){
15088 this.subCtrls[rightLineIndex].setActiveState(isHovered);
15093 //Handle Special cases where they aren't showing any vertical lines
15094 //and the dropdown isn't down
15095 if(!$scope.isLeftLineShown && !$scope.isRightLineShown){
15096 noVerticalLineToggle();
15099 if($scope.isLeftLineShown){
15100 if(this.subCtrls[leftLineIndex].setActiveState)
15101 this.subCtrls[leftLineIndex].setActiveState(isHovered);
15104 if($scope.isRightLineShown){
15105 if(this.subCtrls[rightLineIndex].setActiveState)
15106 this.subCtrls[rightLineIndex].setActiveState(isHovered);
15111 this.setButtonType = function(type){
15112 var buttonIndex = getDirIndex(iconStateConstants.DIR_TYPE.BUTTON);
15113 if(this.subCtrls[buttonIndex] && this.subCtrls[buttonIndex].setType)
15114 this.subCtrls[buttonIndex].setType(type);
15118 .directive('attSplitIconButton', ['$document', 'iconStateConstants',
15119 function($document,iconStateConstants){
15125 require: ['^attSplitIconButtonGroup', 'attSplitIconButton'],
15126 controller: 'AttSplitIconButtonCtrl',
15127 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButton.html',
15132 link: function(scope,element,attr,ctrls){
15135 var attSplitButtonGroupCtrl = ctrls[0];
15136 var attSplitIconButtonCtrl = ctrls[1];
15138 attSplitButtonGroupCtrl.addIconButton(attSplitIconButtonCtrl);
15140 element.bind('keydown', function(e){
15141 //Check if the key is the up or down key
15143 if(e.which == iconStateConstants.KEYBOARD.UP ||
15144 e.which == iconStateConstants.KEYBOARD.DOWN ||
15145 e.which == iconStateConstants.KEYBOARD.ENTER ||
15146 e.which == iconStateConstants.KEYBOARD.ESC ) {
15148 scope.clickHandler();
15149 scope.$broadcast(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, e);
15153 scope.dropDownWatch = false;
15155 scope.iconStateConstants = iconStateConstants;
15157 scope.clickHandler = function(){
15158 attSplitButtonGroupCtrl.hideLeftLineRightButton(attSplitIconButtonCtrl);
15161 scope.$watch('isHovered', function(val){
15163 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
15165 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
15169 scope.$watch('dropDownWatch', function(val){
15170 attSplitButtonGroupCtrl.isDropDownOpen = val;
15171 attSplitButtonGroupCtrl.toggleDropdownState(val);
15176 .controller('AttSplitIconButtonGroupCtrl', ['$scope','iconStateConstants',function($scope,iconStateConstants){
15178 this.subIconButtons = [];
15179 this.addIconButton = function(iconButton){
15180 this.subIconButtons.push(iconButton);
15183 this.isDropDownOpen = false;
15185 this.hideLeftLineRightButton = function(btn){
15186 var numButtons = this.subIconButtons.length;
15187 var buttonLeftOfRightMost = this.subIconButtons[numButtons - 2];
15188 var rightMostButton = this.subIconButtons[numButtons -1];
15190 if (btn != buttonLeftOfRightMost && btn != rightMostButton ){
15191 rightMostButton.setLeftLineHover(false);
15195 this.toggleDropdownState = function(isDropDownOpen){
15197 var numButtons = this.subIconButtons.length;
15199 if(numButtons > 2){
15201 if(isDropDownOpen){
15203 if(this.subIconButtons[numButtons - 2].isRightLineShown())
15204 this.subIconButtons[numButtons - 2].setRightLineHover(true);
15206 this.subIconButtons[numButtons - 1].setLeftLineHover(true);
15208 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.NEXT_TO_DROPDOWN);
15211 this.subIconButtons[numButtons - 1].setLeftLineHover(false);
15212 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.MIDDLE);
15217 if(isDropDownOpen){
15218 this.subIconButtons[0].setRightLineHover(true);
15219 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT_NEXT_TO_DROPDOWN);
15221 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT);
15228 .directive('attSplitIconButtonGroup', ['$document', '$timeout', 'iconStateConstants' ,function($document,$timeout,iconStateConstants){
15234 require: 'attSplitIconButtonGroup',
15235 controller: 'AttSplitIconButtonGroupCtrl',
15236 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButtonGroup.html',
15238 link: function(scope,element,attr,ctrls){
15240 $timeout(initialize,100);
15242 function initialize(){
15244 var subIconButtonCtrls = ctrls.subIconButtons;
15245 var leftMostButtonIndex = 0;
15246 var rightMostButtonIndex =subIconButtonCtrls.length-1;
15248 //left most button config
15249 subIconButtonCtrls[leftMostButtonIndex].setButtonType(iconStateConstants.LEFT);
15250 subIconButtonCtrls[leftMostButtonIndex].isLeftLineShown(false);
15251 subIconButtonCtrls[leftMostButtonIndex].isRightLineShown(true);
15253 //right most button config
15254 subIconButtonCtrls[rightMostButtonIndex].setButtonType(iconStateConstants.RIGHT);
15255 subIconButtonCtrls[rightMostButtonIndex].isRightLineShown(false);
15256 subIconButtonCtrls[rightMostButtonIndex].isLeftLineShown(false);
15258 //middle buttons config
15259 if(rightMostButtonIndex >= 2){
15261 while(index < rightMostButtonIndex){
15262 subIconButtonCtrls[index].setButtonType(iconStateConstants.MIDDLE);
15263 subIconButtonCtrls[index].isRightLineShown(false);
15264 subIconButtonCtrls[index].isLeftLineShown(false);
15269 while(skipIndex <= rightMostButtonIndex){
15270 if(skipIndex == rightMostButtonIndex){
15271 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
15273 subIconButtonCtrls[skipIndex].isRightLineShown(true);
15274 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
15276 skipIndex = skipIndex + 2;
15280 //reposition the dropdown
15281 var ulElem = element.find('ul');
15282 if(ulElem.length > 0){
15283 var numButtons = rightMostButtonIndex+1;
15284 if(numButtons > 2){
15285 var offset = (numButtons)*34-70+(numButtons/1.5) + 0.5;
15286 var offSetStr = offset+'px';
15287 angular.element(ulElem).css('left',offSetStr);
15288 angular.element(ulElem).css('border-top-left-radius','0px');
15290 angular.element(ulElem).css('left','0px');
15298 angular.module('att.abs.steptracker', ['att.abs.transition'])
15299 .directive('steptracker', ['$timeout', function($timeout) {
15301 priority: 100, // This allows dev's clickHandler to cancel an operation
15304 cstep:"=currentStep",
15305 clickHandler: '=?',
15310 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/step-tracker.html',
15311 link: function(scope, elem, attr, ctrl) {
15312 if (scope.disableClick === undefined) {
15313 scope.disableClick = false;
15316 $timeout(function() {
15317 if(scope.cstep < 1){
15320 else if(scope.cstep > scope.sdata.length){
15321 scope.cstep = scope.sdata.length;
15324 var divs = elem.find('div');
15325 var slidertracks = [];
15326 for(var i in divs){
15328 var el = divs.eq(i)[0].className;
15329 if(el.indexOf('track ng-scope') > -1){
15330 slidertracks.push(divs.eq(i));
15337 var currentTrack = updateCurrentTrack(scope.cstep);
15339 function updateCurrentTrack(step) {
15340 // Always return the step-1 because array starts at 0
15341 return angular.element(slidertracks[step-1]);
15344 function updateTrackWidth() {
15345 if (scope.cstep > 0 && scope.cstep <= scope.sdata.length-1 && currentPage > 0) {
15346 var newWidth = ((currentPage/totalPage)*100) + "%";
15347 currentTrack = updateCurrentTrack(scope.cstep);
15348 currentTrack.css('width', newWidth);
15352 function updatePages() {
15353 if (scope.cstep <= scope.sdata.length) {
15354 currentPage = scope.sdata[scope.cstep-1]['currentPage'];
15355 totalPage = scope.sdata[scope.cstep-1]['totalPages'];
15359 // dynamically add width for steps, depending on the number of steps.
15360 scope.set_width = function(indexval) {
15361 var setwidth = (100 / (scope.sdata.length - 1)) + "%";
15363 // skip last element and add width for all other element
15364 if ((scope.sdata.length - 1) > indexval) {
15365 return {'width': setwidth};
15369 scope.$watch('sdata', function(current, previous) {
15371 var prevStep = scope.cstep;
15373 // Before anything, ensure currentPage is never below 1
15374 if (currentPage < 1) {
15377 if (scope.cstep != 1) {
15378 // Decrease step, current track width is 0%, new step width updates
15383 // Move to next step, reset currentPage, totalPage, and ensure previous steps are completed
15384 if (currentPage > totalPage) {
15385 if (scope.cstep > scope.sdata.length-1) {
15389 currentPage = totalPage;
15390 updateTrackWidth();
15393 updateTrackWidth();
15397 if (currentPage < 1 && prevStep === scope.cstep) {
15399 if (scope.cstep > 1) {
15401 scope.sdata[scope.cstep-1]['currentPage'] = scope.sdata[scope.cstep-1]['totalPages'];
15402 scope.sdata[scope.cstep]['currentPage'] = 1;
15406 updateTrackWidth();
15410 //add the active class for current step
15411 scope.activestep = function(index) {
15412 if (index === scope.cstep-1)
15417 //add the done class for finished step
15418 scope.donesteps = function(index) {
15419 if (index < scope.cstep-1)
15424 //add the last class for final step
15425 scope.laststep = function(index) {
15426 if (index === scope.sdata.length-1)
15432 scope.isIncomplete = function(index) {
15433 if (index === scope.cstep-1) return false;
15435 if (index >= 0 && index < scope.sdata.length-1) {
15436 // If currentPage <= totalPage then return true
15437 var step = scope.sdata[index];
15438 if (step['currentPage'] <= step['totalPages']) return true; else return false;
15443 scope.stepclick = function($event, steps) {
15445 // If we are decreasing steps, reset all currentPage counts to 1
15446 if (steps < scope.cstep) {
15447 for (var i = scope.cstep-1; i > steps; i--) {
15448 scope.sdata[i]['currentPage'] = 1;
15450 scope.sdata[steps]['currentPage']--;
15453 if (angular.isFunction(scope.clickHandler)) {
15454 scope.clickHandler($event, steps);
15457 scope.cstep=steps+1;
15459 // In the case we decremented previously from this step, we need to reset currentpage to default
15460 if (scope.cstep <= scope.sdata.length && scope.sdata[scope.cstep]['currentPage'] < 1) {
15461 scope.sdata[scope.cstep]['currentPage'] = 1;
15464 updateTrackWidth();
15471 .constant('timelineConstants',{
15474 COMPLETED:'completed',
15475 CANCELLED: 'cancelled'
15478 .controller('AttTimelineCtrl' , ['$scope', '$timeout', function($scope,$timeout){
15480 var timelineBarCtrls = [];
15481 var timelineDotCtrls = [];
15485 this.isAlternate = function(){
15486 return $scope.alternate;
15489 this.addTimelineBarCtrls = function(t){
15490 timelineBarCtrls.push(t);
15493 this.addTimelineDotCtrls = function(b){
15494 timelineDotCtrls.push(b);
15497 $timeout(init,200);
15501 function compare(a,b) {
15502 if (a.order < b.order)
15504 if (a.order > b.order)
15509 timelineDotCtrls.sort(compare);
15510 timelineBarCtrls.sort(compare);
15512 if($scope.$parent.animate)
15515 $scope.$watch('trigger', function(val){
15517 $scope.resetTimeline();
15519 $scope.$parent.animate = false;
15524 function animateSequence(){
15526 var dotsDuration = .25;
15527 var timelineBarProgressDuration = .25;
15529 if(typeof $scope.barAnimateDuration == 'number')
15530 timelineBarProgressDuration = $scope.barAnimateDuration;
15532 var start = createAnimation(0,timelineBarProgressDuration);
15534 function setToInactiveStates(){
15536 for(var i in timelineDotCtrls){
15537 var dotCtrl = timelineDotCtrls[i];
15540 dotCtrl.unhoveredStateForBelow(.25);
15542 dotCtrl.unhoveredStateForAbove(.25);
15545 if(dotCtrl.isStop())
15551 function createAnimation(i, duration){
15554 if(timelineDotCtrls[i+1].isStop() && timelineDotCtrls[i+1].isCancelled()){
15555 timelineBarCtrls[i].isCancelled(true);
15557 timelineBarCtrls[i].animate(createAnimation(i+1, duration), duration);
15559 }else if(i == timelineBarCtrls.length - 1){
15562 //Removes the bolded text from the start
15563 if(timelineDotCtrls[0].isCurrentStep()){
15564 timelineDotCtrls[0].isCurrentStep(false);
15567 if(timelineDotCtrls[i].isStop()){
15568 timelineDotCtrls[i-1].shrinkAnimate(dotsDuration);
15569 timelineDotCtrls[i].isCurrentStep(true);
15571 timelineDotCtrls[i-1].shrinkAnimate(dotsDuration);
15572 timelineBarCtrls[i].animate(createAnimation(i+1, duration), duration);
15575 timelineDotCtrls[i].expandedAnimate(dotsDuration);
15577 $timeout(function(){
15578 setToInactiveStates();
15583 else if(i == timelineBarCtrls.length){
15586 //Removes the bolded text from the start
15587 if(timelineDotCtrls[0].isCurrentStep()){
15588 timelineDotCtrls[0].isCurrentStep(false);
15591 timelineDotCtrls[i-1].shrinkAnimate(dotsDuration);
15592 timelineDotCtrls[i].expandedAnimate(dotsDuration);
15593 timelineDotCtrls[i].isCurrentStep(true);
15595 $timeout(function(){
15596 setToInactiveStates();
15603 //Removes the bolded text from the start
15604 if(timelineDotCtrls[0].isCurrentStep()){
15605 timelineDotCtrls[0].isCurrentStep(false);
15608 //timelineDotCtrls[i].setColor();
15609 if(timelineDotCtrls[i].isStop()){
15610 timelineDotCtrls[i-1].shrinkAnimate(dotsDuration);
15611 timelineDotCtrls[i].expandedAnimate(dotsDuration);
15612 timelineDotCtrls[i].isCurrentStep(true);
15614 $timeout(function(){
15615 setToInactiveStates();
15620 if(timelineDotCtrls[i+1].isStop() && timelineDotCtrls[i+1].isCancelled()){
15621 timelineBarCtrls[i].isCancelled(true);
15624 timelineDotCtrls[i-1].shrinkAnimate(dotsDuration);
15625 timelineBarCtrls[i].animate(createAnimation(i+1, duration), duration);
15626 timelineDotCtrls[i].expandedAnimate(dotsDuration);
15637 .directive('attTimeline', ['$timeout', '$compile', function($timeout,$compile){
15645 barAnimateDuration: '='
15647 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timeline.html',
15648 controller: 'AttTimelineCtrl',
15649 link: function(scope,element,attrs,ctrl){
15650 var init = function(){
15651 var tempCtrls = [];
15652 var steps = scope.steps;
15654 var middleSteps = [];
15655 for(var i = 1; i < steps.length; i++){
15656 var aStep = steps[i];
15657 middleSteps.push(aStep);
15660 scope.middleSteps = middleSteps;
15662 //Used in calculating the width of the loading bars
15663 ctrl.numSteps = steps.length - 1;
15668 //Recompile in case of scope changes
15669 scope.resetTimeline = function(){
15670 scope.animate = true;
15671 $compile(element)(scope);
15676 .controller('TimelineBarCtrl', ['$scope', function($scope){
15677 this.type = 'timelinebar';
15678 this.order = parseInt($scope.order);
15680 this.animate = function(callback,duration){
15681 $scope.loadingAnimation(callback,duration);
15684 this.isCancelled = function(isCancelled){
15685 $scope.isCancelled = isCancelled;
15689 .directive('timelineBar', ['animation', '$progressBar', function(animation, $progressBar){
15693 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineBar.html',
15697 require: ['^attTimeline', 'timelineBar'],
15698 controller: 'TimelineBarCtrl',
15699 link: function(scope,element,attrs, ctrls){
15701 var attTimelineCtrl = ctrls[0];
15702 var timelineBarCtrl = ctrls[1];
15704 attTimelineCtrl.addTimelineBarCtrls(timelineBarCtrl);
15706 scope.isCompleted = true;
15708 var widthPerc = (100/attTimelineCtrl.numSteps)-3;
15710 element.css('width', widthPerc+'%');
15712 var elem = element.find('div').eq(0);
15714 animation.set(elem, {opacity: 0.0});
15716 var updateCallback = function(selfElement){
15717 animation.set(elem, {opacity:1.0});
15718 animation.set(elem,{
15719 scaleX:selfElement.progress(),
15720 transformOrigin: "left"
15724 scope.loadingAnimation = $progressBar(updateCallback);
15728 .controller('TimelineDotCtrl', ['$scope','$timeout', 'timelineConstants',function($scope,$timeout,timelineConstants){
15731 this.order = parseInt($scope.order);
15734 $timeout(function(){
15736 if(self.order != 0){
15737 if(self.order %2 != 0){
15738 $scope.initializeAboveForAnimation();
15741 $scope.initializeBelowForAnimation();
15747 this.expandedAnimate = function(duration){
15750 $scope.expandedAnimate(duration);
15752 if(self.order != 0 && !$scope.isStepsLessThanFive()){
15753 if(self.order % 2 != 0){
15754 $scope.expandContentForAbove(duration);
15756 $scope.expandContentForBelow(duration);
15762 this.unhoveredStateForAbove = function(duration){
15763 $scope.unhoveredStateForAbove(duration);
15766 this.unhoveredStateForBelow = function(duration){
15767 $scope.unhoveredStateForBelow(duration);
15770 this.shrinkAnimate = function(duration){
15771 $scope.shrinkAnimate(duration);
15774 this.setExpanded = function(){
15778 this.isStop = function(){
15779 return $scope.isStop;
15782 this.isCancelled = function(){
15783 if($scope.type == timelineConstants.STEP_TYPE.CANCELLED)
15789 this.isAlert = function(){
15790 if($scope.type == timelineConstants.STEP_TYPE.ALERT)
15796 //Sets the bolded text
15797 this.isCurrentStep = function(isCurrentStep){
15798 if(isCurrentStep != undefined){
15799 $scope.isCurrentStep = isCurrentStep;
15801 return $scope.isCurrentStep;
15805 .directive('timelineDot', ['$timeout', 'animation', 'timelineConstants',
15806 function($timeout,animation,timelineConstants){
15818 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineDot.html',
15819 require: ['^attTimeline', 'timelineDot'],
15820 controller: 'TimelineDotCtrl',
15821 link: function(scope,element,attrs,ctrls){
15823 var attTimelineCtrl = ctrls[0];
15824 var timelineDotCtrl = ctrls[1];
15825 attTimelineCtrl.addTimelineDotCtrls(timelineDotCtrl);
15827 scope.numSteps = attTimelineCtrl.numSteps + 1;
15829 scope.isCurrentStep = false;
15830 scope.isCompleted = false;
15831 scope.isStop = false;
15833 if(scope.type == timelineConstants.STEP_TYPE.ALERT || scope.type == timelineConstants.STEP_TYPE.CANCELLED){
15834 scope.isStop = true;
15837 scope.isInactive = true;
15839 var divs = element.find('div');
15841 var biggerCircleElem = divs.eq(0);
15842 var expandableCircleElem = divs.eq(2);
15843 var infoboxElem = divs.eq(3);
15844 var titleElem = divs.eq(5);
15845 var contentElem = divs.eq(6);
15846 var dateElem = divs.eq(9);
15849 function isEmptyStep(){
15850 if(!scope.description && !scope.by && !scope.date)
15855 scope.isStepsLessThanFive = function(){
15856 if(scope.numSteps < 5)
15863 scope.titleMouseover=function(num){
15865 if(!scope.isStepsLessThanFive()){
15866 if(!isEmptyStep()){
15867 if(num == 1 && scope.order%2 == 0){
15868 scope.expandContentForBelow(.25);
15871 if(num == 2 && scope.order%2 != 0){
15872 scope.expandContentForAbove(.25);
15879 scope.titleMouseleave = function(num){
15880 if(scope.order%2 == 0){
15881 scope.unhoveredStateForBelow(.25);
15884 scope.unhoveredStateForAbove(.25);
15888 scope.initializeAboveForAnimation = function(){
15889 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15890 animation.set(contentElem,{opacity:0});
15891 animation.set(dateElem,{opacity:0});
15893 if(!isEmptyStep()){
15894 var yOffset = contentElem[0].offsetHeight + dateElem[0].offsetHeight;
15896 animation.set(titleElem,{'top':yOffset });
15901 scope.expandContentForAbove = function(duration){
15903 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15904 animation.to(titleElem,duration, {'top':0});
15905 animation.to(contentElem,duration,{opacity:1});
15906 animation.to(dateElem,duration,{opacity:1});
15911 scope.unhoveredStateForAbove = function(duration){
15913 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15914 animation.set(contentElem,{opacity:0});
15915 animation.set(dateElem,{opacity:1});
15916 var yOffset = contentElem[0].offsetHeight;
15917 animation.to(titleElem,duration,{'top':yOffset});
15922 scope.initializeBelowForAnimation = function(){
15923 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15924 animation.set(contentElem,{height:'0%',opacity:0, top:'-20px'});
15925 animation.set(dateElem,{opacity:0});
15929 scope.expandContentForBelow = function(duration){
15931 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15932 animation.set(dateElem,{opacity:1});
15933 animation.to(contentElem,duration,{ height:'auto',opacity:1, top:'0px'});
15938 scope.unhoveredStateForBelow = function(duration){
15940 if(!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()){
15941 animation.to(contentElem,duration,{height:'0%',opacity:0, top:'-20px', position:'relative'});
15942 animation.set(dateElem,{opacity:1});
15948 Default Initializaztion
15951 //If the info box is above and the description and date and by are empty then we have do reset its position
15953 //IT has to be an alternating version for it to be above
15954 if(scope.order%2 != 0 && attTimelineCtrl.isAlternate())
15955 infoboxElem.css('top', '-47px');
15959 //Check if the order is odd and set the appropiate above or below and other effects
15960 //scope.isAboveInfoBoxShown = true;
15961 if(scope.order%2 == 0 || !attTimelineCtrl.isAlternate()){
15962 scope.isBelowInfoBoxShown=true;
15965 scope.isBelowInfoBoxShown=false;
15968 //modify some css for steps less than 5 and not alternating
15969 if(scope.isStepsLessThanFive() && !attTimelineCtrl.isAlternate()){
15970 animation.set(dateElem,{marginTop:10});
15974 animation.set(biggerCircleElem,{opacity: '.5'});
15976 //shrink the expandableCircle to we can expand it later
15977 animation.set(expandableCircleElem, {opacity: '0.0'});
15978 animation.set(expandableCircleElem, {scale: .10});
15980 if(scope.order == 0){
15981 animation.set(expandableCircleElem, {opacity: '1.0'});
15982 animation.set(expandableCircleElem,{scale: 1});
15983 animation.set(biggerCircleElem,{scale:3});
15985 scope.isCurrentStep = true;
15986 scope.isInactive=false;
15987 scope.isCompleted = true;
15990 scope.setColor = function(){
15991 scope.isInactive=false;
15992 if(scope.type == timelineConstants.STEP_TYPE.CANCELLED){
15993 scope.isCancelled=true;
15995 else if(scope.type == timelineConstants.STEP_TYPE.ALERT){
15996 scope.isAlert=true;
15999 scope.isCompleted = true;
16006 scope.setSize = function(size){
16007 animation.set(biggerCircle,{scale:size});
16010 scope.setExpandedCircle = function(){
16011 animation.set(expandableCircleElem, {opacity: '1.0'});
16012 animation.set(expandableCircleElem,{scale: 1});
16015 scope.expandedAnimate = function(duration){
16016 animation.to(biggerCircleElem,duration,{scale:3});
16017 animation.set(expandableCircleElem, {opacity: '1.0'});
16018 animation.to(expandableCircleElem,duration,{scale: 1});
16021 scope.shrinkAnimate = function(duration){
16022 animation.to(biggerCircleElem,duration,{scale:1});
16028 angular.module('att.abs.table', ['att.abs.utilities'])
16029 .constant('tableConfig', {
16030 defaultSortPattern: false, //true for descending & false for ascending
16031 highlightSearchStringClass: 'tablesorter-search-highlight'
16034 .directive('attTable', ['$filter', function($filter) {
16044 searchCategory: "=",
16047 require: 'attTable',
16048 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTable.html',
16049 controller: ['$scope', function($scope) {
16051 this.currentSortIndex = null;
16052 this.setIndex = function(headerScope) {
16053 this.headers.push(headerScope);
16055 this.getIndex = function(headerName) {
16056 for (var i = 0; i < this.headers.length; i++) {
16057 if (this.headers[i].headerName === headerName) {
16058 return this.headers[i].index;
16063 this.sortData = function(columnIndex, reverse) {
16064 $scope.$parent.columnIndex = columnIndex;
16065 $scope.$parent.reverse = reverse;
16066 this.currentSortIndex = columnIndex;
16067 $scope.currentPage = 1;
16068 this.resetSortPattern();
16070 this.getSearchString = function() {
16071 return $scope.searchString;
16073 this.resetSortPattern = function() {
16074 for(var i = 0; i < this.headers.length; i++) {
16075 var currentScope = this.headers[i];
16076 if(currentScope.index !== this.currentSortIndex) {
16077 currentScope.resetSortPattern();
16082 link: function(scope, elem, attr, ctrl) {
16083 scope.searchCriteria = {};
16084 scope.$watchCollection('tableData', function(value) {
16085 if(value && !isNaN(value.length)) {
16086 scope.totalRows = value.length;
16089 scope.$watch('currentPage', function(val) {
16090 scope.$parent.currentPage = val;
16092 scope.$watch('viewPerPage', function(val) {
16093 scope.$parent.viewPerPage = val;
16095 scope.$watch(function() {
16096 return scope.totalRows / scope.viewPerPage;
16097 }, function(value) {
16098 if(!isNaN(value)) {
16099 scope.totalPage = Math.ceil(value);
16100 scope.currentPage = 1;
16103 var resetSearchCriteria = function() {
16104 scope.searchCriteria = {};
16106 scope.$watch('searchCategory', function(value) {
16107 if (angular.isDefined(value) && value !== null && value !== "" && angular.isDefined(scope.searchString) && scope.searchString !== null && scope.searchString !== "") {
16108 var index = ctrl.getIndex(value);
16109 if (index !== null) {
16110 resetSearchCriteria();
16111 scope.searchCriteria[index] = scope.searchString;
16113 resetSearchCriteria();
16115 } else if (angular.isDefined(scope.searchString) && scope.searchString !== null && scope.searchString !== "" && (!angular.isDefined(value) || value === null || value === "")) {
16116 scope.searchCriteria = {
16117 $: scope.searchString
16120 resetSearchCriteria();
16123 scope.$watch('searchString', function(value) {
16124 if (angular.isDefined(value) && value !== null && value !== "" && angular.isDefined(scope.searchCategory)
16125 && scope.searchCategory !== null && scope.searchCategory !== "") {
16126 var index = ctrl.getIndex(scope.searchCategory);
16127 if (index !== null) {
16128 resetSearchCriteria();
16129 scope.searchCriteria[index] = value;
16131 resetSearchCriteria();
16133 } else if (angular.isDefined(value) && value !== null && value !== ""
16134 && (!angular.isDefined(scope.searchCategory) || scope.searchCategory === null || scope.searchCategory === ""))
16136 scope.searchCriteria = {
16140 resetSearchCriteria();
16143 scope.$watchCollection('searchCriteria', function(val) {
16144 scope.$parent.searchCriteria = val;
16145 scope.totalRows = ($filter('filter')(scope.tableData, val, false)).length;
16146 scope.currentPage = 1;
16152 .directive('attTableRow', [function() {
16155 compile: function (elem, attr) {
16156 if (attr.type === 'header') {
16157 elem.find('tr').eq(0).addClass('tablesorter-headerRow');
16158 } else if (attr.type === 'body') {
16159 var html = elem.children();
16162 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1)"));
16164 html.attr('ng-class', "{'alt-row': $even,'normal-row': $odd}");
16171 .directive('attTableHeader', ['tableConfig', function(tableConfig) {
16180 arrowDirection: '=',
16183 require: '^attTable',
16184 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableHeader.html',
16185 link: function(scope, elem, attr, ctrl) {
16186 var reverse = tableConfig.defaultSortPattern;
16187 scope.headerName = elem.text();
16188 scope.sortPattern = null;
16189 ctrl.setIndex(scope);
16191 scope.$watch('arrowDirection', function(val){
16193 scope.sortPattern = 'asc';
16195 scope.sortPattern = 'desc';
16198 scope.$watch(function() {
16199 return elem.text();
16200 }, function(value) {
16201 scope.headerName = value;
16203 scope.sort = function(sortType) {
16204 if(sortType === true || sortType === false) {
16205 reverse = sortType;
16207 ctrl.sortData(scope.index, reverse);
16208 scope.sortPattern = reverse ? 'desc' : 'asc';
16209 reverse = !reverse;
16211 scope.$watch(function() {
16212 return ctrl.currentSortIndex;
16213 }, function(value) {
16214 if (value !== scope.index) {
16215 scope.sortPattern = null;
16218 if(scope.sortable !== 'false') {
16219 if(scope.defaultSort === 'A' || scope.defaultSort === 'a') {
16221 } else if(scope.defaultSort === 'D' || scope.defaultSort === 'd') {
16225 scope.resetSortPattern = function() {
16226 reverse = tableConfig.defaultSortPattern;
16232 .directive('attTableBody', ['$filter', '$timeout', 'tableConfig', function($filter, $timeout, tableConfig) {
16235 require: '^attTable',
16238 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableBody.html',
16239 link: function (scope, elem, attr, ctrl) {
16240 var highlightSearchStringClass = tableConfig.highlightSearchStringClass;
16241 var searchString = "";
16242 $timeout(function () {
16243 var actualHtml = elem.children();
16244 scope.$watch(function () {
16245 return ctrl.getSearchString();
16246 }, function (val) {
16247 searchString = val;
16249 if (actualHtml.length > 0) {
16257 var traverse = function (elem) {
16258 var innerHtml = elem.children();
16259 if (innerHtml.length > 0) {
16260 for (var i = 0; i < innerHtml.length; i++) {
16261 traverse(innerHtml.eq(i));
16269 var wrapElement = function (elem) {
16270 var text = elem.text();
16272 elem.append($filter('highlight')(text, searchString, highlightSearchStringClass));
16275 var clearWrap = function (elem) {
16276 var elems = elem.find('*');
16277 for (var i = 0; i < elems.length; i++) {
16278 if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
16279 var text = elems.eq(i).text();
16280 elems.eq(i).replaceWith(text);
16288 angular.module('att.abs.tabs', [])
16289 .directive('attTabs', function() {
16297 controller: ['$scope', function($scope) {
16298 this.getData = function() {
16299 return $scope.tabs;
16301 this.onClickTab = function(tab) {
16303 return $scope.currentTab = tab.url;
16305 this.isActiveTab = function(tab) {
16306 return tab === $scope.currentTab;
16309 link: function(scope, elem, attr, ctrl) {
16310 for (var i = 0; i < scope.tabs.length; i++) {
16311 if (scope.tabs[i].selected) {
16312 if (scope.tabs[i].url) {
16313 scope.currentTab = scope.tabs[i].url;
16320 .directive('floatingTabs', function() {
16322 require: '^attTabs',
16329 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/floatingTabs.html',
16330 link: function(scope, elem, attr, attTabsCtrl) {
16331 scope.tabs = attTabsCtrl.getData();
16332 scope.onClickTab = attTabsCtrl.onClickTab;
16333 scope.isActiveTab = attTabsCtrl.isActiveTab;
16337 .directive('simplifiedTabs', function() {
16339 require: '^attTabs',
16346 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html',
16347 link: function(scope, elem, attr, attTabsCtrl) {
16348 scope.tabs = attTabsCtrl.getData();
16349 scope.clickTab = function(tab) {
16350 return scope.ctab = tab.id;
16352 scope.isActive = function(tab) {
16353 return tab === scope.ctab;
16359 .directive('genericTabs', function() {
16361 require: '^attTabs',
16368 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/genericTabs.html',
16369 link: function(scope, elem, attr, attTabsCtrl) {
16370 scope.tabs = attTabsCtrl.getData();
16371 scope.clickTab = function(tab) {
16372 return scope.ctab = tab.id;
16374 scope.isActive = function(tab) {
16375 return tab === scope.ctab;
16380 .directive('parentTab',[ function() {
16388 controller: ['$scope',function($scope){
16389 $scope.megaMenu=$scope.menuItems;
16390 $scope.megaMenuTab;
16391 $scope.megaMenuHoverTab;
16392 this.setMenu=function(index){
16393 $scope.menuItems=$scope.megaMenu;
16394 for(var i=0; i<$scope.menuItems.length; i++){
16395 if($scope.menuItems[i].active == true){
16396 $scope.activeMenu=$scope.menuItems[i];
16399 this.setSubMenuStatus(false);
16403 this.setActiveMenu=function(){
16404 if(!($scope.megaMenuTab=="undefined" || $scope.megaMenuTab==null)){
16405 $scope.menuItems=[$scope.megaMenuTab];
16406 $scope.activeMenu={};
16407 $scope.activeSubMenu=$scope.megaMenuTab;
16408 this.setSubMenuStatus(true);
16411 for(var i=0; i<$scope.menuItems.length; i++){
16412 ($scope.menuItems[i].active = false);
16413 if($scope.menuItems[i].subItems)
16414 for(var j=0; j<$scope.menuItems[i].subItems.length; j++){
16415 $scope.menuItems[i].subItems[j].active = false;
16418 $scope.menuItems=$scope.megaMenu;
16422 var checkSubMenuStatus = false;
16424 this.setSubMenuStatus = function(value){
16425 checkSubMenuStatus = value;
16427 this.getSubMenuStatus = function(){
16428 return checkSubMenuStatus;
16430 this.setActiveMenuTab=function(tab){
16431 $scope.megaMenuTab=tab;
16433 this.setActiveMenuHoverTab=function(tab){
16434 $scope.megaMenuHoverTab=tab;
16436 this.setActiveSubMenuTab=function(){
16437 $scope.megaMenuTab=$scope.megaMenuHoverTab;
16439 this.resetMenuTab=function(){
16440 $scope.megaMenuTab='undefined';
16445 .directive('parentmenuTabs',[ function() {
16454 controller: ['$scope',function($scope){
16455 this.getMenu=function(){
16456 return $scope.menuItems;
16458 this.setMenu=function(menuItem){
16459 $scope.menuItems=menuItem;
16462 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html'
16465 .directive('menuTabs',["$window","$document", function(win,$document) {
16470 require: ['^parentTab', '^?parentmenuTabs'],
16477 templateUrl:function(element, attrs) {
16478 if(attrs.megaMenu){
16479 return 'app/scripts/ng_js_att_tpls/tabs/menuTab.html';
16482 return 'app/scripts/ng_js_att_tpls/tabs/submenuTab.html';
16485 link: function(scope, elem, attr,ctrl) {
16486 var parentCtrl = ctrl[0];
16487 var parentmenuCtrl = ctrl[1];
16488 scope.clickInactive=true;
16489 scope.showHoverChild = function(e){
16490 scope.clickInactive=false;
16491 scope.hoverChild=ctrl[0].getSubMenuStatus();
16492 if(e.type=="mouseover" && ctrl[0].getSubMenuStatus())
16494 scope.showChildren(e);
16497 scope.showChildren = function(e){
16498 scope.parentMenuItems=parentmenuCtrl.getMenu();
16499 for(var i=0; i<scope.parentMenuItems.length; i++){
16500 scope.parentMenuItems[i].active = false;
16501 if(scope.parentMenuItems[i].subItems){
16502 for(var j=0; j<scope.parentMenuItems[i].subItems.length; j++){
16503 scope.parentMenuItems[i].subItems[j].active = false;
16506 scope.clickInactive=true;
16508 scope.menuItem.active = true;
16509 scope.activeMenu=scope.menuItem;
16510 e.stopPropagation();
16512 scope.$watch("subItemActive",function(value){
16513 if(value=="true" && scope.subMenu=='true'){
16514 parentCtrl.setActiveMenuHoverTab(scope.menuItem);
16518 scope.showMenuClick=function(){
16519 parentCtrl.setActiveMenuTab(scope.menuItem);
16521 scope.showSubMenuClick=function(){
16522 parentCtrl.setActiveSubMenuTab();
16524 scope.resetMenu=function(){
16525 parentCtrl.resetMenuTab();
16528 function debounce(method, delay) {
16529 clearTimeout(method._tId);
16530 method._tId= setTimeout(function(){
16531 parentCtrl.setMenu();
16534 function debounce1(method, delay) {
16535 clearTimeout(method._tId);
16536 method._tId= setTimeout(function(){
16537 parentCtrl.setActiveMenu();
16540 $document.bind('scroll', function() {
16541 if(win.pageYOffset===0){
16542 debounce(parentCtrl.setMenu, 100);
16544 else if(win.pageYOffset>1 && win.pageYOffset<1500){
16545 debounce1(parentCtrl.setActiveMenu, 100);
16551 angular.module('att.abs.tagBadges', [])
16552 .directive('tagBadges', ['$parse', '$timeout', function($parse, $timeout) {
16557 templateUrl: 'app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html',
16562 link: function(scope, elem, attr, ctrl) {
16563 scope.isSmall = false;
16564 scope.isIcon = false;
16565 scope.isColor = false;
16566 scope.display = true;
16567 scope.isClosable = false;
16568 scope.isHighlight = false;
16569 scope.customColor = false;
16571 if (attr.small === "") {
16572 scope.isSmall = true;
16575 if (scope.styleType === "icon") {
16576 scope.isIcon = true;
16578 else if (scope.styleType === "color") {
16579 scope.isColor = true;
16580 if(attr.color != undefined && attr.color != "") {
16581 scope.customColor = true;
16582 attr.$observe("color", function(val) {
16583 scope.border_type_borderColor = val;
16584 scope.background_type_backgroundColor = val;
16585 scope.background_type_borderColor = val;
16590 scope.activeHighlight = function(state){
16591 if(scope.customColor){
16593 scope.isHighlight = true;
16596 scope.isHighlight = false;
16601 if (attr.closable === "") {
16602 scope.isClosable = true;
16604 scope.closeMe = function() {
16605 scope.display = false;
16607 $timeout(function(){
16608 elem.attr("tabindex", "0");
16610 elem.bind('blur', function(){
16615 if(attr['onClose']){
16616 scope.onClose = $parse(scope.onClose);
16624 angular.module('att.abs.textOverflow', [])
16625 .constant('textDefaultOptions', {
16628 .directive('attTextOverflow', ['textDefaultOptions','$compile',function(textDefaultOptions,$compile)
16632 link: function(scope, elem, attrs, ctrl)
16634 var tooltipText = elem.text();
16635 elem.addClass('text-ellipsis');
16636 attrs.$observe('attTextOverflow', function(val){
16638 elem.css({"width":val});
16640 elem.css({"width":textDefaultOptions.width});
16642 if(!(elem.attr('tooltip'))){
16643 elem.attr("tooltip", tooltipText);
16644 elem.attr("tooltip-placement", 'above');
16645 var newElem = angular.element(elem);
16646 $compile(newElem)(scope);
16652 angular.module('att.abs.toggle', ['angular-gestures', 'att.abs.position'])
16653 .directive('attToggleTemplate', ['$compile', '$log', '$position', function($compile, $log, $position)
16657 require: 'ngModel',
16660 modelVal: "=ngModel"
16662 templateUrl: 'app/scripts/ng_js_att_tpls/toggle/demoToggle.html',
16663 link: function(scope, element, attr, ctrl) {
16665 scope.initialDragPosition = 0;
16666 var dragStatus = 0;
16667 var switchMovementPath = ($position.offset(element.children().eq(1).children().eq(0)).width -1);
16668 scope.drag = function(e) {
16671 if (e.type === 'dragstart') {
16672 scope.initialDragPosition = $position.position(element.children().eq(1)).left;
16674 element.children().eq(1).addClass('dragging');
16675 } else if (e.type === 'drag') {
16676 var left = Math.min(0, Math.max(scope.initialDragPosition + e.gesture.deltaX, -switchMovementPath));
16677 element.children().eq(1).css({
16680 } else if (e.type === 'dragend') {
16681 var isOn = $position.position(element.children().eq(1)).left > (switchMovementPath*-1)/2;
16682 element.children().eq(1).removeClass('dragging');
16683 TweenMax.to(element.children().eq(1), .1, {left: isOn ? 0 : (switchMovementPath*-1), ease: Power4.easeOut, onComplete: function(){element.children().eq(1).css({left: ''}) } });
16687 else if(isOn === false && e.gesture.direction === "left"){
16696 scope.directiveValue = attr.attToggleTemplate;
16697 scope.on = attr.trueValue;
16698 scope.off = attr.falseValue;
16699 var switchMovementPathPixels = ((switchMovementPath)*-1) + 'px';
16700 scope.$watch('modelVal', function(newVal) {
16701 scope.attrValue = newVal;
16702 if (newVal === attr.ngTrueValue || newVal === true) {
16703 element.children().eq(1).css({
16706 element.addClass('att-checkbox--on');
16707 element.attr("aria-checked", true);
16710 element.children().eq(1).css({
16711 left : switchMovementPathPixels
16713 element.removeClass('att-checkbox--on');
16714 element.attr("aria-checked", false);
16717 element.children().eq(1).css({
16723 var updateModelVal = function() {
16724 if (scope.attrValue === attr.ngTrueValue || scope.attrValue === true)
16726 scope.modelVal = false;
16730 scope.modelVal = true;
16733 scope.updateModel = function(env){
16735 if (dragStatus !== 1) {
16740 env.preventDefault();
16750 .directive('attToggleMain', ['$compile', '$log', function($compile, $log)
16754 require: 'ngModel',
16758 modelValue: "=ngModel",
16759 trueValue: "=ngTrueValue",
16760 falseValue: "=ngFalseValue"
16762 link: function(scope, element, attr, ctrl) {
16766 element.removeAttr('att-toggle-main');
16767 scope.on = attr.ngTrueValue;
16768 scope.off = attr.ngFalseValue;
16769 scope.largeValue = attr.attToggleMain;
16770 if (angular.isDefined(attr.ngTrueValue)) {
16771 html += ' true-value="{{on}}" false-value="{{off}}"';
16773 if (scope.largeValue !== undefined)
16775 attrVal += ' ="{{largeValue}}"';
16778 element.css({display:'none'});
16779 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>'); elm = $compile(elm)(scope);
16780 element.replaceWith(elm);
16785 angular.module('att.abs.tooltip', ['att.abs.position', 'att.abs.utilities', 'ngSanitize'])
16787 // The default options tooltip and popover.
16788 .constant('tooltipDefaultOptions', {
16789 placement: 'above',
16797 * The $tooltip service creates tooltip- and popover-like directives as well as
16798 * houses global options for them.
16800 .provider('$tooltip', ['tooltipDefaultOptions', function(tooltipDefaultOptions) {
16802 // Default hide triggers for each show trigger
16804 'mouseenter': 'mouseleave',
16807 'mouseover':'mouseout'
16810 // The options specified to the provider globally.
16811 var globalOptions = {};
16813 this.options = function(value) {
16814 angular.extend(globalOptions, value);
16818 * This allows you to extend the set of trigger mappings available. E.g.:
16820 * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
16822 this.setTriggers = function setTriggers(triggers) {
16823 angular.extend(triggerMap, triggers);
16827 * This is a helper function for translating camel-case to snake-case.
16829 function snake_case(name) {
16830 var regexp = /[A-Z]/g;
16831 var separator = '-';
16832 return name.replace(regexp, function(letter, pos) {
16833 return (pos ? separator : '') + letter.toLowerCase();
16838 * Returns the actual instance of the $tooltip service.
16840 this.$get = ['$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function($window, $compile, $timeout, $parse, $document, $position, $interpolate) {
16841 return function $tooltip(type, prefix, defaultTriggerShow) {
16842 var options = angular.extend({}, tooltipDefaultOptions, globalOptions);
16845 * Returns an object of show and hide triggers.
16847 * If a trigger is supplied,
16848 * it is used to show the tooltip; otherwise, it will use the `trigger`
16849 * option passed to the `$tooltipProvider.options` method; else it will
16850 * default to the trigger supplied to this directive factory.
16852 * The hide trigger is based on the show trigger. If the `trigger` option
16853 * was passed to the `$tooltipProvider.options` method, it will use the
16854 * mapped trigger from `triggerMap` or the passed trigger if the map is
16855 * undefined; otherwise, it uses the `triggerMap` value of the show
16856 * trigger; else it will just use the show trigger.
16858 function getTriggers(trigger) {
16859 var show = trigger || options.trigger || defaultTriggerShow;
16860 var hide = triggerMap[show] || show;
16867 var directiveName = snake_case(type);
16869 var startSym = $interpolate.startSymbol();
16870 var endSym = $interpolate.endSymbol();
16872 '<div ' + directiveName + '-popup ' +
16873 'title="' + startSym + 'tt_title' + endSym + '" ' +
16874 'content="' + startSym + 'tt_content' + endSym + '" ' +
16875 'placement="' + startSym + 'tt_placement' + endSym + '" ' +
16876 'animation="tt_animation()" ' +
16877 'is-open="tt_isOpen" ' +
16878 'stylett="' + startSym + 'tt_style' + endSym + '" ' +
16885 link: function link(scope, element, attrs) {
16887 element.attr("tabindex", "0");
16888 element.bind('mouseenter', function(){
16889 element.removeAttr("title");
16891 element.bind('mouseleave', function(){
16892 element.attr("title", scope.tt_content);
16895 var tooltip = $compile(template)(scope);
16896 var transitionTimeout;
16899 var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
16900 var triggers = getTriggers(undefined);
16901 var hasRegisteredTriggers = false;
16902 var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
16904 // By default, the tooltip is not open.
16905 // TODO add ability to start tooltip opened
16906 scope.tt_isOpen = false;
16908 //Adding a scope watch, to remove the created popup from DOM, incase it is updated outside the provider code.
16909 scope.$watch('tt_isOpen', function(newVal, oldVal){
16910 if(newVal !== oldVal){
16911 if( newVal === false ){
16918 function toggleTooltipBind() {
16919 if (!scope.tt_isOpen) {
16926 // Show the tooltip with delay if specified, otherwise show it immediately
16927 function showTooltipBind() {
16928 tooltip = $compile(template)(scope);
16930 if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
16933 if (scope.tt_popupDelay) {
16934 popupTimeout = $timeout(show, scope.tt_popupDelay);
16936 scope.$apply(show);
16940 function hideTooltipBind() {
16941 scope.$apply(function() {
16946 // Show the tooltip popup element.
16953 // Don't show empty tooltips.
16954 if (!scope.tt_content) {
16958 // If there is a pending remove transition, we must cancel it, lest the
16959 // tooltip be mysteriously removed.
16960 if (transitionTimeout) {
16961 $timeout.cancel(transitionTimeout);
16964 // Set the initial positioning.
16965 tooltip.css({top: 0, left: 0, display: 'block', 'z-index': 9999});
16967 // Now we add it to the DOM because need some info about it. But it's not
16968 // visible yet anyway.
16970 if (appendToBody) {
16971 $body = $body || $document.find('body');
16972 $body.append(tooltip);
16974 element.after(tooltip);
16977 // Get the position of the directive element.
16978 position = appendToBody ? $position.offset(element) : $position.position(element);
16979 // alert(JSON.stringify(position));
16981 // Get the height and width of the tooltip so we can center it.
16982 ttWidth = tooltip.prop('offsetWidth');
16983 ttHeight = tooltip.prop('offsetHeight');
16985 // Calculate the tooltip's top and left coordinates to center it with
16987 var ttArrowOffset = 10;
16989 switch (scope.tt_placement) {
16993 top: position.top + position.height / 2 - ttHeight / 2,
16994 left: position.left + position.width
16998 top: position.top + position.height / 2 - ttHeight / 2,
16999 left: position.left + position.width + ttArrowOffset
17006 top: position.top + position.height,
17007 left: position.left + position.width / 2 - ttWidth / 2
17011 top: position.top + position.height + ttArrowOffset,
17012 left: position.left + position.width / 2 - ttWidth / 2
17019 top: position.top + position.height / 2 - ttHeight / 2,
17020 left: position.left - ttWidth
17024 top: position.top + position.height / 2 - ttHeight / 2,
17025 left: position.left - ttWidth - ttArrowOffset
17032 top: position.top - ttHeight,
17033 left: position.left + position.width / 2 - ttWidth / 2
17037 top: position.top - ttHeight - ttArrowOffset,
17038 left: position.left + position.width / 2 - ttWidth / 2
17044 ttPosition.top += 'px';
17045 ttPosition.left += 'px';
17047 // Now set the calculated positioning.
17048 tooltip.css(ttPosition);
17050 // And show the tooltip.
17051 scope.tt_isOpen = true;
17054 // Hide the tooltip popup element.
17056 // First things first: we don't show it anymore.
17057 scope.tt_isOpen = false;
17059 //if tooltip is going to be shown after delay, we must cancel this
17060 $timeout.cancel(popupTimeout);
17062 // And now we remove it from the DOM. However, if we have animation, we
17063 // need to wait for it to expire beforehand.
17064 // FIXME: this is a placeholder for a port of the transitions library.
17065 if (angular.isDefined(scope.tt_animation) && scope.tt_animation()) {
17066 transitionTimeout = $timeout(function() {
17075 * Observe the relevant attributes.
17077 attrs.$observe(type, function(val) {
17079 scope.tt_content = val;
17080 element.attr('title',val);
17082 if (scope.tt_isOpen) {
17088 attrs.$observe(prefix + 'Title', function(val) {
17089 scope.tt_title = val;
17092 attrs.$observe(prefix + 'Placement', function(val) {
17093 scope.tt_placement = angular.isDefined(val) ? val : options.placement;
17096 attrs.$observe(prefix + 'Style', function(val) {
17097 scope.tt_style = angular.isDefined(val) ? val : options.stylett;
17100 attrs.$observe(prefix + 'Animation', function(val) {
17101 scope.tt_animation = angular.isDefined(val) ? $parse(val) : function() {
17102 return options.animation;
17106 attrs.$observe(prefix + 'PopupDelay', function(val) {
17107 var delay = parseInt(val, 10);
17108 scope.tt_popupDelay = !isNaN(delay) ? delay : options.popupDelay;
17111 attrs.$observe(prefix + 'Trigger', function(val) {
17113 if (hasRegisteredTriggers) {
17114 element.unbind(triggers.show, showTooltipBind);
17115 element.unbind(triggers.hide, hideTooltipBind);
17118 triggers = getTriggers(val);
17120 if (triggers.show === triggers.hide) {
17121 element.bind(triggers.show, toggleTooltipBind);
17123 element.bind(triggers.show, showTooltipBind);
17124 element.bind(triggers.hide, hideTooltipBind);
17127 hasRegisteredTriggers = true;
17130 attrs.$observe(prefix + 'AppendToBody', function(val) {
17131 appendToBody = angular.isDefined(val) ? $parse(val)(scope) : appendToBody;
17134 // if a tooltip is attached to <body> we need to remove it on
17135 // location change as its parent scope will probably not be destroyed
17137 if (appendToBody) {
17138 scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess() {
17139 if (scope.tt_isOpen) {
17145 // Make sure tooltip is destroyed and removed.
17146 scope.$on('$destroy', function onDestroyTooltip() {
17147 if (scope.tt_isOpen) {
17159 .directive('tooltipPopup', ['$document', '$documentBind', function($document, $documentBind) {
17164 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
17165 templateUrl: 'app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html',
17166 link: function(scope, elem, attr, ctrl) {
17169 scope.$watch("isOpen", function(value) {
17170 flag = scope.isOpen;
17173 elem.bind('click', function (e) {
17174 e.stopPropagation();
17177 var outsideClick = function(e) {
17179 scope.$apply(function() {
17180 scope.isOpen = false;
17186 $documentBind.click('isOpen', outsideClick, scope);
17191 .directive('tooltip', ['$tooltip', function($tooltip) {
17192 return $tooltip('tooltip', 'tooltip', 'mouseenter');
17195 .directive('tooltipCondition', [ '$timeout',function($timeout) {
17200 tooltipCondition:"@?"
17202 template:'<p><span tooltip=\"{{tooltipCondition}}\" ng-if=\"showpop\">{{tooltipCondition}}</span><span id=\"innerElement\" ng-hide=\"showpop\">{{tooltipCondition}}</span></p>',
17203 link: function(scope, elem, attr){
17204 scope.showpop=false;
17205 if(attr.height==='true'){
17206 $timeout(function () {
17207 var maxHeight=(elem[0].offsetHeight);
17208 var elemHeight=elem.children(0)[0].offsetHeight;
17209 if(elemHeight > maxHeight){
17210 scope.showpop=true;
17214 else if(scope.tooltipCondition.length>=25){
17215 scope.showpop=true;
17222 angular.module('att.abs.treeview', [])
17223 .directive('treeView', function() {
17226 link: function(scope, elem, attrs) {
17227 var el = elem.children('ul li');
17228 var list = TweenMax.from(el, .2, {display: 'none', paused: true, reversed: true});
17229 elem.attr("tabindex","0");
17230 function toggleBranch() {
17231 if (list.reversed())
17239 function toggleTree(e){
17240 e.stopPropagation();
17241 if ($(e.target).attr("tree-view") !== undefined)
17243 if (elem.hasClass('minus'))
17245 elem.removeClass('minus');
17249 elem.addClass('minus');
17254 elem.on('click', function(e) {
17257 elem.on('keypress', function (e) {
17258 var activeCode = e.keyCode ? e.keyCode : e.charCode;
17259 var keyCode = [13,32];
17260 if(keyCode.length > 0 && ((activeCode && keyCode.indexOf(activeCode) > -1))) {
17262 e.preventDefault();
17269 angular.module('att.abs.typeAhead', ['att.abs.tagBadges'])
17271 .directive('focusMe',['$timeout', '$parse', function($timeout, $parse) {
17273 link: function(scope, element, attrs) {
17274 var model = $parse(attrs.focusMe);
17276 scope.$watch(model, function(value) {
17277 if (value === true) {
17278 $timeout(function() {
17279 element[0].focus();
17280 scope.inputActive=true;
17285 element.bind('blur', function() {
17286 scope.$apply(model.assign(scope, false));
17287 scope.inputActive=false;
17293 .directive('typeAhead', ['$timeout', function($timeout) {
17296 templateUrl: 'app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html',
17306 link: function(scope, elem, attrs) {
17307 scope.lineItems = [];
17308 scope.filteredListLength = -1;
17309 scope.filteredList = [];
17310 scope.inputfocus = false;
17312 scope.setFocus = function() {
17313 scope.clickFocus = true;
17316 scope.handleSelection = function(selectedItem,emailItem) {
17317 scope.lineItems.push(selectedItem);
17318 scope.emailIdList.push(emailItem);
17321 scope.selected = true;
17322 scope.clickFocus = true;
17326 scope.theMethodToBeCalled = function(index) {
17327 var tempArr = scope.lineItems.slice();
17328 scope.emailIdList.splice(index, 1);
17329 tempArr.splice(index, 1);
17330 $timeout(function() {
17331 scope.lineItems = [];
17333 scope.lineItems = scope.lineItems.concat(tempArr);
17339 scope.selected = true;
17341 scope.isCurrent = function(index, itemName,itemEmail,dropdownLength) {
17342 if (scope.current === index) {
17343 scope.itemName = itemName;
17344 scope.itemEmail = itemEmail;
17347 scope.dropdownLength=dropdownLength;
17348 return scope.current === index;
17351 scope.setCurrent = function(index) {
17352 scope.current = index;
17355 scope.selectionIndex = function(evt) {
17357 if (evt.keyCode === 38 && scope.current > 0) {
17358 evt.preventDefault();
17359 scope.current = scope.current - 1;
17360 scope.isCurrent(scope.current);
17361 } else if (evt.keyCode === 9) {
17362 scope.selected = true;
17363 } else if (evt.keyCode === 13 && scope.dropdownLength!==scope.items.length) {
17364 scope.handleSelection(scope.itemName,scope.itemEmail);
17365 } else if (evt.keyCode === 8 && scope.model.length === 0) {
17366 scope.theMethodToBeCalled(scope.lineItems.length - 1);
17367 } else if (evt.keyCode === 46) {
17368 scope.theMethodToBeCalled(scope.lineItems.length - 1);
17369 } else if (evt.keyCode === 40 && scope.current < scope.dropdownLength-1) {
17370 evt.preventDefault();
17371 scope.current = scope.current + 1;
17372 scope.isCurrent(scope.current);
17375 elem[0].querySelector('.list-scrollable').scrollTop = (scope.current - 1) * 35;
17380 angular.module('att.abs.userMessages',[])
17381 .constant('messageConstants', {
17382 TABLE_MESSAGE_TYPES: {
17388 USER_MESSAGE_TYPES: {
17393 .directive('attTableMessage', ['messageConstants',function(messageConstants) {
17401 onRefreshClick: '&'
17403 templateUrl: 'app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html',
17404 link: function(scope,elements,attr){
17405 scope.messageConstants = messageConstants;
17406 scope.refreshAction= function(evt){
17407 scope.onRefreshClick(evt);
17411 }]).directive('attUserMessage', ['messageConstants',function(messageConstants) {
17423 templateUrl: 'app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html',
17424 link: function(scope,element,attrs) {
17425 scope.messageConstants= messageConstants;
17429 angular.module('att.abs.verticalSteptracker', [])
17430 .directive('verticalSteptracker', [
17438 template: '<div class="vertical-nav"><ul ng-transclude class="tickets-list-height"></ul></div>',
17439 link:function(scope,elem,attribute,ctrl) {
17445 .directive('verticalSteptrackerStep',[
17455 templateUrl: 'app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html',
17456 link: function(scope, elem, attr, ctrl) {
17464 .directive('attAbsLink',[function(){
17469 template: '<span ng-transclude class="view-log"></span>',
17470 link: function(scope, elem, attr, ctrl) {
17478 angular.module('att.abs.videoControls', [])
17479 .config(['$compileProvider' , function ($compileProvider) {
17480 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|javascript):/);
17482 .directive('videoControls', [function() {
17487 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/videoControls.html'
17490 .directive('photoControls', [function() {
17495 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/photoControls.html',
17500 link: function(scope, elem, attr, ctrl) {
17501 if(!attr['prevLink'])
17502 scope.prevLink = 'javascript:void(0)';
17504 if(!attr['nextLink'])
17505 scope.nextLink = 'javascript:void(0)';
17508 prevLink : scope.prevLink,
17509 nextLink : scope.nextLink
17514 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
17515 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion.html",
17516 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
17517 " <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" +
17518 " <span>{{heading}}</span>\n" +
17519 " <i ng-class=\"{'icon-chevron-down':!isOpen,'icon-chevron-up':isOpen }\" class=\"pull-right\"></i>\n" +
17521 " <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" +
17522 " <div id=\"panel{{index}}\" aria-labelledby=\"tab{{index}}\" aria-hidden=\"{{!isOpen}}\" role=\"tabpanel\" collapse=\"!isOpen\" class=\"att-accordion__body\" ng-transclude>\n" +
17524 " <div class=\"att-accordion__bottom--border\"></div> \n" +
17528 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html", []).run(["$templateCache", function($templateCache) {
17529 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html",
17530 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
17531 " <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" +
17533 " <span>{{heading}}</span>\n" +
17534 " <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" +
17539 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccord.html", []).run(["$templateCache", function($templateCache) {
17540 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccord.html",
17541 "<div ng-transclude></div>");
17544 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html", []).run(["$templateCache", function($templateCache) {
17545 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html",
17546 "<div ng-transclude></div>");
17549 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html", []).run(["$templateCache", function($templateCache) {
17550 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html",
17551 "<div ng-click=\"clickFunc()\">\n" +
17552 " <div ng-transclude>\n" +
17553 " <i class=\"icon-chevron-down\"></i>\n" +
17558 angular.module("app/scripts/ng_js_att_tpls/alert/alert.html", []).run(["$templateCache", function($templateCache) {
17559 $templateCache.put("app/scripts/ng_js_att_tpls/alert/alert.html",
17560 "<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" +
17561 " <div class=\"container\">\n" +
17562 " <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" +
17563 " <span ng-transclude> </span>\n" +
17568 angular.module("app/scripts/ng_js_att_tpls/colorselector/colorselector.html", []).run(["$templateCache", function($templateCache) {
17569 $templateCache.put("app/scripts/ng_js_att_tpls/colorselector/colorselector.html",
17570 "<div class=\"att-radio att-color-selector__item\" \n" +
17571 " ng-class=\"{'att-radio--on': (iconColor === selected)}\">\n" +
17572 " <div class=\"att-radio__indicator\" tabindex=\"0\" att-accessibility-click=\"32,13\"ng-click=\"selectedcolor(iconColor)\" \n" +
17573 " ng-style=\"applycolor\" ng-transclude></div>\n" +
17577 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html", []).run(["$templateCache", function($templateCache) {
17578 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html",
17579 "<div class=\"calendar\" ng-class=\"{'monthpicker':mode === 1}\">\n" +
17580 " <div class=\"select2-container\" ng-class=\"{'select2-container-active select2-dropdown-open': showDropdownList}\" style=\"width: 100%; z-index:0\">\n" +
17581 " <a tabindex=\"0\" class=\"select2-choice\" href=\"javascript:void(0)\" ng-show=\"!showCalendar\" att-accessibility-click=\"13,32\" ng-click=\"showDropdown()\">\n" +
17582 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
17583 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" ng-change=\"getDropdownText()\" />\n" +
17584 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
17585 " <span ng-class=\"{'select2-arrow': mode !== 1, 'calendar-icon': mode === 1}\"><b></b></span>\n" +
17587 " <a class=\"select2-choice\" href=\"javascript:void(0)\" ng-show=\"showCalendar\">\n" +
17588 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
17589 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" ng-change=\"getDropdownText()\" />\n" +
17590 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
17591 " <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" +
17594 " <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" +
17595 " <ul class=\"select2-results options\" style=\"margin-top:0px;height:120px;overflow:auto;\" ng-transclude></ul>\n" +
17596 " <ul class=\"select2-results sttings\" style=\"margin-top:0px\">\n" +
17597 " <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" +
17598 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Single Date...</div>\n" +
17599 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom single month...</div>\n" +
17601 " <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" +
17602 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Range...</div>\n" +
17603 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom month range...</div>\n" +
17605 " <li class=\"select2-result select2-highlighted btnContainer\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
17606 " <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" +
17607 " <button tabindex=\"0\" att-button=\"\" btn-type=\"secondary\" size=\"small\" att-accessibility-click=\"13,32\" ng-click=\"cancel()\">Cancel</button>\n" +
17609 " <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" +
17610 " <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" +
17615 " <div class=\"datepicker-wrapper show-right\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
17616 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusSingleDateCalendar\" ng-show=\"checkCurrentSelection('Custom Single Date')\"></span>\n" +
17617 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusRangeCalendar\" ng-show=\"checkCurrentSelection('Custom Range')\"></span>\n" +
17623 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html", []).run(["$templateCache", function($templateCache) {
17624 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html",
17625 "<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" +
17626 " <div class=\"select2-result-label\" ng-class=\"{'disabled':disabled}\" ng-transclude></div>\n" +
17630 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
17631 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepicker.html",
17632 "<ul id=\"datepicker\" class=\"datepicker\" ng-class=\"{'monthpicker': mode === 1}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
17633 " <div class=\"datepicker-days\" style=\"display: block;\">\n" +
17634 " <table class=\"table-condensed\">\n" +
17637 " <th id=\"month\" tabindex=\"0\" align=\"left\" class=\"datepicker-switch\" colspan=\"{{(mode !== 1) && (currentRows[0].length - 2) || (currentRows[0].length)}}\">{{currentTitle}}</th>\n" +
17638 " <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" +
17639 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-left-circle\" ng-class=\"{'disabled': disablePrev}\"></i>\n" +
17640 " </div><span class=\"hidden-spoken\">Previous Month</span>\n" +
17642 " <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" +
17643 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-right-circle\" ng-class=\"{'disabled': disableNext}\"></i>\n" +
17644 " </div><span class=\"hidden-spoken\">Next Month</span>\n" +
17647 " <tr ng-if=\"labels.length > 0\">\n" +
17648 " <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" +
17653 " <td id=\"datepickerBody\" att-scrollbar colspan=\"{{currentRows[0].length}}\" style=\"padding: 0px;\">\n" +
17654 " <table ng-class=\"{'table-condensed': mode === 0, 'monthtable-condensed': mode === 1}\" style=\"padding: 0px;\">\n" +
17656 " <tr ng-repeat=\"row in currentRows\">\n" +
17657 " <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" +
17659 " <tr ng-if=\"mode === 1\" class=\"divider\"><td colspan=\"{{nextRows[0].length}}\"><hr></td></tr>\n" +
17661 " <th id=\"month\" tabindex=\"0\" align=\"left\" class=\"datepicker-switch internal\" colspan=\"{{nextRows[0].length}}\">{{nextTitle}}</th>\n" +
17663 " <tr ng-repeat=\"row in nextRows\">\n" +
17664 " <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" +
17677 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html", []).run(["$templateCache", function($templateCache) {
17678 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html",
17679 "<div class=\"calendar\">\n" +
17680 " <div class=\"box\" ng-class=\"{'active': isOpen}\">\n" +
17681 " <span ng-transclude></span>\n" +
17682 " <i class=\"calendar-icon\" tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\"></i>\n" +
17684 " <div class=\"datepicker-wrapper datepicker-wrapper-display-none\" ng-style=\"{display: (isOpen && 'block') || 'none'}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
17685 " <span datepicker></span>\n" +
17691 angular.module("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html", []).run(["$templateCache", function($templateCache) {
17692 $templateCache.put("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html",
17693 "<div class=\"divider-container\" ng-class=\"{'divider-container-light': lightContainer}\">\n" +
17694 " <hr ng-class=\"{'divider-light': lightContainer}\">\n" +
17700 angular.module("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html", []).run(["$templateCache", function($templateCache) {
17701 $templateCache.put("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html",
17702 "<label class=\"fileContainer\"><span ng-transclude></span><input type=\"file\" att-file-change></label>");
17705 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html", []).run(["$templateCache", function($templateCache) {
17706 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html",
17707 "<div class=\"form-field\" ng-class=\"{'error': errorMessage, 'warning': warningMessage}\">\n" +
17708 " <label class=\"form-field__label\" ng-class=\"{'form-field__label--show': showLabel, 'form-field__label--hide': hideLabel}\"></label>\n" +
17709 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
17713 angular.module("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html", []).run(["$templateCache", function($templateCache) {
17714 $templateCache.put("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html",
17715 "<div class=\"hourpicker\">\n" +
17716 " <div class=\"dropdown-width\">\n" +
17717 " <div ng-model=\"showlist\" class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" >\n" +
17718 " <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" +
17719 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
17720 " <span class=\"select2-arrow\"><b></b></span>\n" +
17723 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultTopWidth\" ng-show=\"showlist\"> \n" +
17724 " <ul class=\"select2-results resultTopMargin\" > \n" +
17725 " <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" +
17729 " <div ng-show=\"showDaysSelector\" class=\"customdays-width\">\n" +
17730 " <div att-divider-lines class=\"divider-margin-f\"></div> \n" +
17731 " <div class=\"col-md-3 fromto-margin\">\n" +
17732 " <div>From</div> <br>\n" +
17733 " <div>To</div>\n" +
17735 " <div ng-repeat=\"day in days\">\n" +
17736 " <div class=\"col-md-3 col-md-days\">\n" +
17737 " <div class=\"col-md-1 daysselect-margin\">\n" +
17738 " <input type=\"checkbox\" ng-model=\"daysList[day]\" title=\"Day selection\" att-checkbox ng-change=\"addSelectedValue(day)\"> \n" +
17740 " <span>{{day}}</span><br>\n" +
17742 " <div class=\"dropDownMarginBottom\">\n" +
17743 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': FrtimeListDay[day]}\" >\n" +
17744 " <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" +
17745 " <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" +
17749 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultFromDropDown\" ng-show=\"FrtimeListDay[day]\"> \n" +
17750 " <ul class=\"select2-results resultTopMargin\" > \n" +
17751 " <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" +
17756 " <div class=\"dropDownMarginBottom\">\n" +
17757 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': TotimeListDay[day]}\" >\n" +
17758 " <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" +
17759 " <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" +
17763 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultToDropDown\" ng-show=\"TotimeListDay[day]\"> \n" +
17764 " <ul class=\"select2-results resultTopMargin\" > \n" +
17765 " <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" +
17771 " <div att-divider-lines class=\"divider-margin-s\"></div> \n" +
17773 " <div ng-transclude></div>\n" +
17777 angular.module("app/scripts/ng_js_att_tpls/links/readMore.html", []).run(["$templateCache", function($templateCache) {
17778 $templateCache.put("app/scripts/ng_js_att_tpls/links/readMore.html",
17780 " <div ng-bind-html=\"textToDisplay\" ng-class=\"{'att--readMore': readFlag, 'att--readLess': !readFlag}\" ng-style=\"readLinkStyle\"></div>\n" +
17781 " <span class=\"att--readmore__link\" ng-show=\"readMoreLink\">
\85 <a href=\"#\" ng-click=\"readMore()\" att-accessbility-click=\"32,13\">Read More</a>\n" +
17784 "<span class=\"att--readless__link\" ng-show=\"readLessLink\">\n" +
17785 " <a href=\"#\" ng-click=\"readLess()\" att-accessbility-click=\"32,13\">Read Less</a>\n" +
17789 angular.module("app/scripts/ng_js_att_tpls/loading/loading.html", []).run(["$templateCache", function($templateCache) {
17790 $templateCache.put("app/scripts/ng_js_att_tpls/loading/loading.html",
17791 "<div data-progress=\"{{progressStatus}}\" class=\"{{colorClass}}\" ng-class=\"{'att-loading-count':icon == 'count','loading--small':icon == 'small','loading': icon != 'count'}\">\n" +
17792 " <div class=\"att-loading-circle\" ng-if=\"icon == 'count'\">\n" +
17793 " <div class=\"att-loading-circle__mask att-loading-circle__full\">\n" +
17794 " <div class=\"att-loading-circle__fill\"></div>\n" +
17796 " <div class=\"att-loading-circle__mask att-loading-circle__half\">\n" +
17797 " <div class=\"att-loading-circle__fill\"></div>\n" +
17798 " <div class=\"att-loading-circle__fill att-loading-circle__fix\"></div>\n" +
17801 " <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" +
17807 angular.module("app/scripts/ng_js_att_tpls/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
17808 $templateCache.put("app/scripts/ng_js_att_tpls/modal/backdrop.html",
17809 "<div class=\"overlayed\" ng-class=\"{show: animate}\" \n" +
17810 " ng-style=\"{'z-index': 2000 + index*10,'overflow':'scroll'}\"> \n" +
17814 angular.module("app/scripts/ng_js_att_tpls/modal/window.html", []).run(["$templateCache", function($templateCache) {
17815 $templateCache.put("app/scripts/ng_js_att_tpls/modal/window.html",
17816 "<div tabindex=\"-1\" role=\"dialog\" att-element-focus=\"focusModalFlag\" class=\"modals {{ windowClass }}\" ng-class=\"{show: animate}\" \n" +
17817 " ng-style=\"{'z-index': 2010 + index*10}\" ng-click=\"close($event)\" ng-transclude> \n" +
17822 angular.module("app/scripts/ng_js_att_tpls/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
17823 $templateCache.put("app/scripts/ng_js_att_tpls/pagination/pagination.html",
17824 "<div class=\"pager\">\n" +
17825 " <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" +
17826 " <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" +
17827 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage > 3\">...</span>\n" +
17828 " <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" +
17829 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage < totalPages - 2 && showInput !== true\">...</span>\n" +
17830 " <span ng-show=\"totalPages > 7 && showInput === true\"><input class=\"pager__item--input\" type=\"text\" placeholder=\"...\" maxlength=\"2\" ng-model=\"currentPage\"/></span>\n" +
17831 " <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" +
17832 " <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" +
17836 angular.module("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html", []).run(["$templateCache", function($templateCache) {
17837 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html",
17838 "<div class='inner-pane'>\n" +
17839 " <div ng-transclude>\n" +
17844 angular.module("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html", []).run(["$templateCache", function($templateCache) {
17845 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html",
17846 "<div class='pane-group'>\n" +
17847 " <div ng-transclude>\n" +
17852 angular.module("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html", []).run(["$templateCache", function($templateCache) {
17853 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html",
17854 "<div class='side-pane'> \n" +
17855 " <div ng-transclude>\n" +
17860 angular.module("app/scripts/ng_js_att_tpls/profileCard/addUser.html", []).run(["$templateCache", function($templateCache) {
17861 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/addUser.html",
17862 "<div class=\"col-md-9 profile-card add-user\">\n" +
17863 " <div class=\"atcenter\">\n" +
17864 " <div><i class=\"icon-add\"></i></div>\n" +
17865 " <span>add User</span>\n" +
17870 angular.module("app/scripts/ng_js_att_tpls/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
17871 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/profileCard.html",
17872 "<div class=\"col-md-9 profile-card\">\n" +
17873 " <div class=\"top-block\">\n" +
17874 " <div class=\"profile-image\">\n" +
17875 " <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\">\n" +
17876 " <span ng-hide=\"image\" class=\"default-img\">{{initials}}</span>\n" +
17877 " <p class=\"name\" tooltip-condition=\"{{profile.name}}\" height=\"true\"></p>\n" +
17878 " <p class=\"status\">\n" +
17879 " <span class=\"status-icon\" ng-class=\"{'icon-green':colorIcon==='green','icon-red':colorIcon==='red','icon-blue':colorIcon==='blue','icon-yellow':colorIcon==='yellow'}\"> \n" +
17881 " <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
17885 " <div class=\"bottom-block\">\n" +
17886 " <div class=\"profile-details\">\n" +
17887 " <label>Username</label>\n" +
17888 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.userName}}\">{{profile.userName}}</p>\n" +
17889 " <label>Email</label>\n" +
17890 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.email}}\">{{profile.email}}</p>\n" +
17891 " <label>Role</label>\n" +
17892 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.role}}\">{{profile.role}}</p>\n" +
17893 " <label>Last Login</label>\n" +
17894 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.lastLogin}}\">{{profile.lastLogin}}</p>\n" +
17900 angular.module("app/scripts/ng_js_att_tpls/progressBars/progressBars.html", []).run(["$templateCache", function($templateCache) {
17901 $templateCache.put("app/scripts/ng_js_att_tpls/progressBars/progressBars.html",
17902 "<div class=\"att-progress\">\n" +
17903 " <div class=\"att-progress-value\"> </div>\n" +
17907 angular.module("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html", []).run(["$templateCache", function($templateCache) {
17908 $templateCache.put("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html",
17909 "<div class=\"scroll-bar\">\n" +
17910 " <div class=\"scroll-thumb\"></div>\n" +
17912 "<div class=\"scroll-viewport\">\n" +
17913 " <div class=\"scroll-overview\" ng-transclude></div>\n" +
17917 angular.module("app/scripts/ng_js_att_tpls/search/search.html", []).run(["$templateCache", function($templateCache) {
17918 $templateCache.put("app/scripts/ng_js_att_tpls/search/search.html",
17919 "<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" +
17920 " <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" +
17921 " <span class=\"select2-chosen needsclick\">{{selectedOption}}</span>\n" +
17922 " <abbr class=\"select2-search-choice-close needsclick\"></abbr> \n" +
17923 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
17924 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
17927 " <label class=\"select2-offscreen\"></label>\n" +
17928 " <input class=\"select2-focusser select2-offscreen\" tabindex=\"-1\" type=\"text\" aria-haspopup=\"true\" role=\"button\">\n" +
17930 "<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" +
17931 " <div class=\"select2-search\"> \n" +
17932 " <label class=\"select2-offscreen\"></label> \n" +
17933 " <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-expanded=\"true\" \n" +
17934 " aria-autocomplete=\"list\" placeholder=\"\"> \n" +
17936 " <ul class=\"select2-results\" role=\"listbox\">\n" +
17937 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\">No matches found</li>\n" +
17938 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17939 " ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\" \n" +
17940 " ng-click=\"selectOption(selectMsg, '-1')\" \n" +
17941 " ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\" \n" +
17942 " ng-mouseover=\"hoverIn(-1)\">\n" +
17943 " <div class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className\" role=\"option\">\n" +
17944 " <span class=\"select2-match\" ></span>\n" +
17947 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
17948 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\" \n" +
17949 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
17950 " ng-click=\"selectOption(item.title,item.index)\"\n" +
17951 " ng-mouseover=\"hoverIn(item.index)\">\n" +
17952 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className\" role=\"option\">\n" +
17953 " <span class=\"select2-match\" ></span>\n" +
17961 angular.module("app/scripts/ng_js_att_tpls/search/search_2.html", []).run(["$templateCache", function($templateCache) {
17962 $templateCache.put("app/scripts/ng_js_att_tpls/search/search_2.html",
17963 "<div ng-model=\"showlist\" class=\"select2-container\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" style=\"width: 100%; z-index:0\">\n" +
17964 " <a tabindex=\"-1\" class=\"select2-choice\" href=\"javascript:void(0)\" ng-click=\"showDropdown()\">\n" +
17965 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
17966 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
17967 " <span class=\"select2-arrow\"><b></b></span>\n" +
17969 " <input type=\"text\" class=\"select2-focusser select2-offscreen\">\n" +
17971 "<select ng-model=\"value\" ng-options=\"c.title for c in cName\" class=\"select2-offscreen\"></select>\n" +
17972 "<div class=\"select2-drop select2-display-none select2-with-searchbox select2-drop-active show-search\" style=\"display: block; width: 100%;\" ng-show=\"showlist\">\n" +
17973 " <div ng-show=\"showSearch\" class=\"select2-search\">\n" +
17974 " <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" +
17976 " <ul class=\"select2-results\" style=\"margin-top:0px;max-height:205px\">\n" +
17977 " <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" +
17978 " <div class=\"select2-result-label\" ng-bind-html=\"country.title | highlight:title:className\"><span class=\"select2-match\"></span>\n" +
17986 angular.module("app/scripts/ng_js_att_tpls/select/select.html", []).run(["$templateCache", function($templateCache) {
17987 $templateCache.put("app/scripts/ng_js_att_tpls/select/select.html",
17988 "<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" +
17989 " <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" +
17990 " <span class=\"select2-chosen needsclick\">{{selectedOption}}</span>\n" +
17991 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
17992 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
17993 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
17996 " <label class=\"select2-offscreen\"></label>\n" +
17997 " <input class=\"select2-focusser select2-offscreen\" tabindex=\"-1\" type=\"text\" aria-haspopup=\"true\" role=\"button\">\n" +
17999 "<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" +
18000 " <div class=\"select2-search\">\n" +
18001 " <label class=\"select2-offscreen\"></label>\n" +
18002 " <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-expanded=\"true\" \n" +
18003 " aria-autocomplete=\"list\" placeholder=\"\">\n" +
18005 " <ul class=\"select2-results\" role=\"listbox\">\n" +
18006 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\">No matches found</li>\n" +
18007 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
18008 " ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\"\n" +
18009 " ng-click=\"selectOption(selectMsg, '-1')\"\n" +
18010 " ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\"\n" +
18011 " ng-mouseover=\"hoverIn(-1)\"\n" +
18013 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg\" role=\"option\">\n" +
18014 " <span class=\"select2-match\" ></span>\n" +
18016 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className\" role=\"option\">\n" +
18017 " <span class=\"select2-match\" ></span>\n" +
18020 " <li ng-if=\"startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
18021 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | startsWith:title:item)\"\n" +
18022 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
18023 " ng-click=\"selectOption(item.title,item.index)\"\n" +
18024 " ng-mouseover=\"hoverIn(item.index)\"\n" +
18026 " <div class=\"select2-result-label\" ng-bind-html=\"item.title\" role=\"option\">\n" +
18027 " <span class=\"select2-match\" ></span>\n" +
18031 " <li ng-if=\"!startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\"\n" +
18032 " ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\"\n" +
18033 " ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index}\"\n" +
18034 " ng-click=\"selectOption(item.title,item.index)\"\n" +
18035 " ng-mouseover=\"hoverIn(item.index)\"\n" +
18037 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className\" role=\"option\">\n" +
18038 " <span class=\"select2-match\" ></span>\n" +
18047 angular.module("app/scripts/ng_js_att_tpls/select/textDropdown.html", []).run(["$templateCache", function($templateCache) {
18048 $templateCache.put("app/scripts/ng_js_att_tpls/select/textDropdown.html",
18049 "<div tabindex=\"0\" class=\"text-dropdown\">\n" +
18050 " <div class=\"dropdown\" ng-class=\"{'not-visible': isActionsShown}\" ng-click=\"toggle()\" >\n" +
18051 " <span class=\"action--selected\" ng-bind=\"currentAction\"></span>\n" +
18052 " <i ng-class=\"isActionsShown ? 'icon-dropdown-up' : 'icon-dropdown-down'\"></i>\n" +
18055 " <ul ng-class=\"isActionsShown ? 'actionsOpened' : 'actionsClosed'\" ng-show=\"isActionsShown\">\n" +
18056 " <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" +
18062 angular.module("app/scripts/ng_js_att_tpls/slider/attStepSlider.html", []).run(["$templateCache", function($templateCache) {
18063 $templateCache.put("app/scripts/ng_js_att_tpls/slider/attStepSlider.html",
18064 "<span ng-class=\"mainSliderClass\">\n" +
18068 " <div class=\"jslider-bg\">\n" +
18069 " <i class=\"l\"></i>\n" +
18070 " <i class=\"r\"></i>\n" +
18071 " <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" +
18073 " <div class=\"jslider-pointer\" id=\"left-pointer\"></div>\n" +
18074 " <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" +
18075 " <div class=\"jslider-label\"><span ng-bind=\"from\"></span><span ng-bind=\"options.dimension\"></span></div>\n" +
18076 " <div class=\"jslider-label jslider-label-to\"><span ng-bind=\"toStr\"></span><span ng-bind=\"endDimension\"></span></div>\n" +
18077 " <div class=\"jslider-value\" id=\"jslider-value-left\"><span></span>{{options.dimension}}</div>\n" +
18078 " <div class=\"jslider-value jslider-value-to\"><span></span>{{toolTipDimension}}</div>\n" +
18079 " <div class=\"jslider-scale\" ng-class=\"{'show-dividers': showDividers, 'cutoff-slider-dividers':isCutOffSlider}\">\n" +
18081 " <div class=\"jslider-cutoff\">\n" +
18082 " <div class=\"jslider-label jslider-label-cutoff\">\n" +
18083 " <span ng-bind=\"cutOffVal\"></span>\n" +
18093 angular.module("app/scripts/ng_js_att_tpls/slider/maxContent.html", []).run(["$templateCache", function($templateCache) {
18094 $templateCache.put("app/scripts/ng_js_att_tpls/slider/maxContent.html",
18095 "<div class=\"att-slider__label att-slider__label--max att-slider__label--below\" ng-transclude></div>");
18098 angular.module("app/scripts/ng_js_att_tpls/slider/minContent.html", []).run(["$templateCache", function($templateCache) {
18099 $templateCache.put("app/scripts/ng_js_att_tpls/slider/minContent.html",
18100 "<div class=\"att-slider__label att-slider__label--min att-slider__label--below\" ng-transclude></div>");
18103 angular.module("app/scripts/ng_js_att_tpls/slider/slider.html", []).run(["$templateCache", function($templateCache) {
18104 $templateCache.put("app/scripts/ng_js_att_tpls/slider/slider.html",
18105 "<div class=\"att-slider\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\">\n" +
18106 " <div class=\"att-slider__track\">\n" +
18107 " <div class=\"att-slider__range att-slider__range--disabled\" ng-style=\"disabledStyle\"></div>\n" +
18108 " <div class=\"att-slider__range\" ng-style=\"rangeStyle\"></div>\n" +
18110 " <div class=\"att-slider__handles-container\">\n" +
18111 " <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" +
18112 " <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" +
18113 " <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" +
18115 " <div ng-transclude></div>\n" +
18119 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html", []).run(["$templateCache", function($templateCache) {
18120 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html",
18121 "<div class=\" btn-group\" \n" +
18122 " ng-class=\"{'buttons-dropdown--large':!isSmall, \n" +
18123 " 'buttons-dropdown--small':isSmall, \n" +
18124 " 'action-dropdown':isActionDropdown, \n" +
18125 " 'open':isDropDownOpen}\">\n" +
18126 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"button btn buttons-dropdown__split\" \n" +
18127 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
18128 " 'button--secondary':btnType=='secondary', \n" +
18129 " 'button--disabled':btnType=='disabled', \n" +
18130 " 'button--small':isSmall}\" \n" +
18131 " ng-if=\"!isActionDropdown\"\n" +
18132 " ng-click=\"btnType==='disabled'?undefined:clickFxn()\" att-accessibility-click=\"13,32\">{{btnText}}</a>\n" +
18133 " <a tabindex=\"0\" href=\"javascript:void(0)\" role=\"button\" aria-label=\"Toggle Dropdown\" class=\"button buttons-dropdown__drop dropdown-toggle\" \n" +
18134 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
18135 " 'button--secondary':btnType=='secondary', \n" +
18136 " 'button--disabled':btnType=='disabled', \n" +
18137 " 'button--small':isSmall}\" ng-click=\"toggleDropdown()\" att-accessibility-click=\"13,32\"></a>\n" +
18138 " <ul class=\"dropdown-menu\" ng-click=\"hideDropdown()\" ng-transclude></ul>\n" +
18142 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIcon.html", []).run(["$templateCache", function($templateCache) {
18143 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIcon.html",
18144 "<div class='split-icon-button-container'>\n" +
18146 " <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" +
18147 " <a class='{{icon}}' aria-label='{{icon}}' role='button' tabindex=\"0\"></a>\n" +
18148 " <i ng-if=\"isRight && !isMiddle && !isLeftNextDropdown && !isNextToDropDown\" \n" +
18149 " ng-class=\"isDropDownOpen ? 'icon-dropdown-up' : 'icon-dropdown-down'\"> </i>\n" +
18152 " <ul ng-if='isDropdown' class='dropdown-menu {{dropDownId}}' ng-show='\n" +
18153 " isDropDownOpen' ng-click='toggleDropdown(false)' ng-transclude>\n" +
18159 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButton.html", []).run(["$templateCache", function($templateCache) {
18160 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButton.html",
18162 " <div ng-if='isLeftLineShown' dir-type='{{iconStateConstants.DIR_TYPE.LEFT}}' expandable-line></div>\n" +
18163 " <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" +
18164 " <div ng-transclude>\n" +
18167 " <div ng-if='isRightLineShown' dir-type='{{iconStateConstants.DIR_TYPE.RIGHT}}' expandable-line></div>\n" +
18171 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButtonGroup.html", []).run(["$templateCache", function($templateCache) {
18172 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitIconButtonGroup.html",
18173 "<div ng-transclude>\n" +
18177 angular.module("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html", []).run(["$templateCache", function($templateCache) {
18178 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html",
18179 "<div class=\"steptracker1\">\n" +
18180 " <div class=\"steptracker-bg\">\n" +
18181 " <div class=\"steptracker-track size-onethird\" ng-repeat=\"step in sdata\"\n" +
18182 " ng-style=\"set_width($index)\"\n" +
18183 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index), 'incomplete': isIncomplete($index), 'disabled': disableClick}\">\n" +
18184 " <div class=\"circle\" tabindex=\"0\"\n" +
18185 " ng-click=\"stepclick($event, $index);\"\n" +
18186 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
18187 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
18194 angular.module("app/scripts/ng_js_att_tpls/steptracker/step.html", []).run(["$templateCache", function($templateCache) {
18195 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step.html",
18196 "<div class=\"steptracker1\">\n" +
18197 " <div class=\"steptracker-bg\">\n" +
18198 " <div class=\"steptracker-track size-onethird\" \n" +
18199 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index)}\">\n" +
18200 " <div class=\"circle\" tabindex=\"0\" \n" +
18201 " ng-click=\"stepclick($event, $index);\" \n" +
18202 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
18203 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
18210 angular.module("app/scripts/ng_js_att_tpls/steptracker/timeline.html", []).run(["$templateCache", function($templateCache) {
18211 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timeline.html",
18212 "<div class='att-timeline'>\n" +
18213 " <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" +
18215 " <div ng-repeat=\"m in middleSteps track by $index\">\n" +
18216 " <div timeline-bar order='{{$index}}'></div>\n" +
18217 " <div timeline-dot order='{{$index + 1}}' title='{{m.title}}' description='{{m.description}}' by='{{m.by}}' date='{{m.date}}' type='{{m.type}}'>\n" +
18224 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html", []).run(["$templateCache", function($templateCache) {
18225 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html",
18226 "<div class='timeline-bar'>\n" +
18227 " <div class='progress-bar' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
18233 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html", []).run(["$templateCache", function($templateCache) {
18234 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html",
18235 "<div class='timeline-dot'>\n" +
18237 " <div class='bigger-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
18240 " <div class='inactive-circle'>\n" +
18243 " <div class='expandable-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
18246 " <div ng-class=\"{'below-info-box':isBelowInfoBoxShown, 'above-info-box': !isBelowInfoBoxShown}\">\n" +
18248 " <div ng-if='isBelowInfoBoxShown' class='vertical-line'>\n" +
18251 " <div class='info-container' ng-init='isContentShown=false'>\n" +
18252 " <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(1)' ng-bind='title' ></div>\n" +
18253 " <div class='content'>\n" +
18254 " <div class='description' ng-bind='description'></div>\n" +
18255 " <div class='submitter' ng-bind='by'></div>\n" +
18257 " <div class='date' ng-mouseover='titleMouseover(2)' ng-mouseleave='titleMouseleave(2)' ng-bind='date'></div>\n" +
18260 " <div ng-if='!isBelowInfoBoxShown' class='vertical-line'>\n" +
18267 angular.module("app/scripts/ng_js_att_tpls/table/attTable.html", []).run(["$templateCache", function($templateCache) {
18268 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTable.html",
18269 "<table class=\"tablesorter tablesorter-default\" ng-transclude></table>\n" +
18273 angular.module("app/scripts/ng_js_att_tpls/table/attTableBody.html", []).run(["$templateCache", function($templateCache) {
18274 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableBody.html",
18275 "<td ng-transclude></td>\n" +
18279 angular.module("app/scripts/ng_js_att_tpls/table/attTableHeader.html", []).run(["$templateCache", function($templateCache) {
18280 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableHeader.html",
18281 "<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" +
18285 angular.module("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html", []).run(["$templateCache", function($templateCache) {
18286 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html",
18287 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
18288 " <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" +
18289 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
18294 angular.module("app/scripts/ng_js_att_tpls/tabs/genericTabs.html", []).run(["$templateCache", function($templateCache) {
18295 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/genericTabs.html",
18296 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
18297 " <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" +
18298 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
18304 angular.module("app/scripts/ng_js_att_tpls/tabs/menuTab.html", []).run(["$templateCache", function($templateCache) {
18305 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/menuTab.html",
18306 "<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>");
18309 angular.module("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html", []).run(["$templateCache", function($templateCache) {
18310 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html",
18311 "<div ng-class=\"{'megamenu-tabs': megaMenu,'submenu-tabs': !megaMenu}\">\n" +
18312 " <ul class=\"megamenu__items\" ng-transclude>\n" +
18317 angular.module("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html", []).run(["$templateCache", function($templateCache) {
18318 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html",
18319 "<div class=\"simplified-tabs\">\n" +
18320 "<ul class=\"simplified-tabs__items\">\n" +
18321 " <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" +
18322 " <li class=\"tabs__pointer\"></li>\n" +
18327 angular.module("app/scripts/ng_js_att_tpls/tabs/submenuTab.html", []).run(["$templateCache", function($templateCache) {
18328 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/submenuTab.html",
18329 "<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" +
18333 angular.module("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html", []).run(["$templateCache", function($templateCache) {
18334 $templateCache.put("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html",
18335 "<div class=\"tags__item\" \n" +
18336 " ng-class=\"{'tags__item--small':isSmall, \n" +
18337 " 'tags__item--color':isColor, \n" +
18338 " 'tags__item--cloud':!isClosable && !isColor,'active':applyActiveClass}\"\n" +
18339 " ng-if=\"display\" \n" +
18340 " ng-style=\"{borderColor: border_type_borderColor, background: isHighlight?'#bbb':undefined, color: isHighlight?'#444':undefined }\"\n" +
18341 " ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\">\n" +
18342 " <i class=\"icon-filter tags__item--icon\" ng-if=\"isIcon\"> </i>\n" +
18343 " <i class=\"tags__item--color-icon\" ng-if=\"isColor\" ng-style=\"{backgroundColor: background_type_backgroundColor, borderColor: background_type_borderColor}\"></i>\n" +
18344 " <span class=\"tags__item--title\" tabindex=0 aria-label ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\" ng-transclude></span>\n" +
18345 " <a href=\"javascript:void(0)\" title=\"Dismiss Link\" class=\"tags__item--action\" ng-click=\"closeMe();$event.preventDefault()\" ng-if=\"isClosable\"\n" +
18346 " ng-style=\"{color: (isHighlight && '#444') || '#888' , borderLeft: (isHighlight && '1px solid #444')|| '1px solid #888' }\">\n" +
18347 " <i class=\"icon-erase\"> </i>\n" +
18352 angular.module("app/scripts/ng_js_att_tpls/toggle/demoToggle.html", []).run(["$templateCache", function($templateCache) {
18353 $templateCache.put("app/scripts/ng_js_att_tpls/toggle/demoToggle.html",
18354 "<span ng-transclude></span>\n" +
18355 "<!--<div class=\"att-switch-content\" hm-drag-left = \"dragleft($event)\" hm-drag-right = \"dragright($event)\" hm-dragstart = \"drag($event)\" 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" +
18356 "<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" +
18357 " <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" +
18358 " <div class=\"att-switch-thumb\" tabindex=\"0\" ng-class=\"{'large' : directiveValue == 'large'}\"></div>\n" +
18359 " <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" +
18364 angular.module("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
18365 $templateCache.put("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html",
18366 "<div class=\"att-tooltip \" \n" +
18367 " ng-class=\"{ 'att-tooltip--on': isOpen, \n" +
18368 " 'att-tooltip--dark att-tooltip--dark--hover':stylett=='dark', \n" +
18369 " 'att-tooltip--light att-tooltip--light--hover':stylett=='light',\n" +
18370 " 'att-tooltip--left':placement=='left', \n" +
18371 " 'att-tooltip--above':placement=='above', \n" +
18372 " 'att-tooltip--right':placement=='right', \n" +
18373 " 'att-tooltip--below':placement=='below'}\" \n" +
18374 " ng-bind-html=\"content\" ></div>");
18377 angular.module("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html", []).run(["$templateCache", function($templateCache) {
18378 $templateCache.put("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html",
18379 "<div class=\"typeahead mainContainerOuter\">\n" +
18380 " <span class=\"message\">To</span> \n" +
18381 " <div class='maincontainer' ng-click=\"setFocus()\" ng-class =\"{'typeahed_active':inputActive}\">\n" +
18382 " <span tag-badges closable ng-repeat =\"lineItem in lineItems track by $index\" on-close=\"theMethodToBeCalled($index)\" >{{lineItem}}</span>\n" +
18383 " <input type=\"text\" focus-me=\"clickFocus\" id=\"inpute\" aria-label=\"model\" role=\"textfiled\" ng-model=\"model\" ng-keydown=\"selected = false; selectionIndex($event)\"/><br/> \n" +
18385 " <div ng-hide=\"!model.length || selected\">\n" +
18386 " <div class=\"filtercontainer list-scrollable\" ng-show=\"( items | filter:model).length\">\n" +
18387 " <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" +
18388 " <span class=\"title\" >{{item[title]}}</span>\n" +
18389 " <span class=\"subtitle\">{{item[subtitle]}}</span>\n" +
18394 " <div class=\"textAreaEmailContentDiv\">\n" +
18395 " <span class=\"message\">Message</span>\n" +
18396 " <textarea rows=\"4\" cols=\"50\" role=\"textarea\" class=\"textAreaEmailContent\" ng-model=\"emailMessage\">To send \n" +
18397 " a text, picture, or video message1 to an AT&T wireless device from your email:my message.</textarea>\n" +
18404 angular.module("app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html", []).run(["$templateCache", function($templateCache) {
18405 $templateCache.put("app/scripts/ng_js_att_tpls/userMessages/attTableMessage.html",
18406 "<div class=\"att-table-message\">\n" +
18407 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.noMatching\">\n" +
18408 " <div class=\"img-magnify-glass\"></div> \n" +
18410 " <div ng-transclude></div>\n" +
18413 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.errorLoading\">\n" +
18414 " <div class=\"img-oops-exclamation\"></div> \n" +
18415 " <div>Oops!</div>\n" +
18416 " <div>The information could not load at this time.</div>\n" +
18417 " <div>Please <a href=\"javascript:void(0)\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
18420 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.magnifySearch\">\n" +
18421 " <div class=\"img-magnify-glass\"></div>\n" +
18423 " <p class=\"title\">Please input values to <br/> begin your search.</p>\n" +
18426 " <div class=\"message loading-message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.isLoading\">\n" +
18427 " <div class=\"img-loading-dots\"></div>\n" +
18428 " <div ng-transclude></div>\n" +
18433 angular.module("app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html", []).run(["$templateCache", function($templateCache) {
18434 $templateCache.put("app/scripts/ng_js_att_tpls/userMessages/attUserMessage.html",
18435 "<div class=\"att-user-message\">\n" +
18436 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.error && trigger ? 'message-wrapper-error' : 'hidden'\">\n" +
18437 " <div class=\"message-icon-error\"> <i class=\"icon-info-alert\"></i> </div>\n" +
18439 " <div class=\"message-body-wrapper\">\n" +
18440 " <div class=\"message-title-error\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\"></span> </div>\n" +
18441 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\"> </div>\n" +
18442 " <div class=\"message-bottom\">\n" +
18443 " <div ng-transclude></div>\n" +
18448 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.success && trigger ? 'message-wrapper-success' : 'hidden'\">\n" +
18449 " <div class=\"message-icon-success\"> <i class=\"icon-included-checkmark\"></i> </div>\n" +
18451 " <div class=\"message-body-wrapper\">\n" +
18452 " <div class=\"message-title-success\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\"></span> </div>\n" +
18453 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\"> </div>\n" +
18454 " <div class=\"message-bottom\">\n" +
18455 " <div ng-transclude></div>\n" +
18464 angular.module("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html", []).run(["$templateCache", function($templateCache) {
18465 $templateCache.put("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html",
18467 " <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" +
18468 " <span ng-transclude></span>\n" +
18474 angular.module("app/scripts/ng_js_att_tpls/videoControls/photoControls.html", []).run(["$templateCache", function($templateCache) {
18475 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/photoControls.html",
18477 " <a title=\"Previous Link\" ng-href=\"{{links.prevLink}}\"><i class=\"icon-arrow-left\"> </i></a>\n" +
18478 " <span ng-transclude></span>\n" +
18479 " <a title=\"Next Link\" ng-href=\"{{links.nextLink}}\"><i class=\"icon-arrow-right\"> </i></a>\n" +
18483 angular.module("app/scripts/ng_js_att_tpls/videoControls/videoControls.html", []).run(["$templateCache", function($templateCache) {
18484 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/videoControls.html",
18485 "<div class=\"video-player\">\n" +
18486 " <div class=\"video-player__control video-player__play-button\">\n" +
18487 " <a class=\"video-player__button gigant-play\" data-toggle-buttons=\"icon-play, icon-pause\" data-target=\"i\"><i class=\"icon-play\"></i></a>\n" +
18489 " <div class=\"video-player__control video-player__track\">\n" +
18491 " <div class=\"video-player__track--inner\">\n" +
18492 " <div class=\"video-player__track--loaded\" style=\"width: 75%\"></div>\n" +
18493 " <div class=\"video-player__track--played\" style=\"width: 40%\">\n" +
18494 " <div class=\"att-tooltip att-tooltip--on att-tooltip--dark att-tooltip--above video-player__track-tooltip\" ng-transclude></div>\n" +
18495 " <div class=\"video-player__track-handle\"></div>\n" +
18499 " <a class=\"video-player__time\" ng-transclude></a>\n" +
18500 " <div class=\"video-player__control video-player__volume_icon\">\n" +
18501 " <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" +
18503 " <ul class=\"video-player__control video-player__volume\">\n" +
18504 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
18505 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
18506 " <li class=\"video-player__volume-bar\"> </li>\n" +
18507 " <li class=\"video-player__volume-bar\"> </li>\n" +
18508 " <li class=\"video-player__volume-bar\"> </li>\n" +
18510 " <div class=\"video-player__control video-player__toggle-fullscreen-button\">\n" +
18511 " <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" +