2 * FileName att-style-guide
4 * Build number 5c64ecd381d5984c483cdfaa078a1890
8 (function(angular, window){
9 angular.module("att.abs", ["att.abs.tpls", "att.abs.utilities","att.abs.position","att.abs.transition","att.abs.accordion","att.abs.alert","att.abs.boardStrip","att.abs.breadCrumbs","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.tooltip","att.abs.popOvers","att.abs.profileCard","att.abs.progressBars","att.abs.radio","att.abs.scrollbar","att.abs.search","att.abs.select","att.abs.slider","att.abs.splitButtonDropdown","att.abs.splitIconButton","att.abs.stepSlider","att.abs.steptracker","att.abs.table","att.abs.tableMessages","att.abs.tabs","att.abs.tagBadges","att.abs.textOverflow","att.abs.toggle","att.abs.treeview","att.abs.typeAhead","att.abs.verticalSteptracker","att.abs.videoControls"]);
10 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/boardStrip/attAddBoard.html","app/scripts/ng_js_att_tpls/boardStrip/attBoard.html","app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html","app/scripts/ng_js_att_tpls/buttons/buttonDropdown.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/formField/attFormFieldValidationAlertPrv.html","app/scripts/ng_js_att_tpls/formField/creditCardImage.html","app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.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/tabbedItem.html","app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.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/tooltip/tooltip-popup.html","app/scripts/ng_js_att_tpls/popOvers/popOvers.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/select/select.html","app/scripts/ng_js_att_tpls/select/textDropdown.html","app/scripts/ng_js_att_tpls/slider/maxContent.html","app/scripts/ng_js_att_tpls/slider/minContent.html","app/scripts/ng_js_att_tpls/slider/slider.html","app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html","app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html","app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html","app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html","app/scripts/ng_js_att_tpls/steptracker/step-tracker.html","app/scripts/ng_js_att_tpls/steptracker/step.html","app/scripts/ng_js_att_tpls/steptracker/timeline.html","app/scripts/ng_js_att_tpls/steptracker/timelineBar.html","app/scripts/ng_js_att_tpls/steptracker/timelineDot.html","app/scripts/ng_js_att_tpls/table/attTable.html","app/scripts/ng_js_att_tpls/table/attTableBody.html","app/scripts/ng_js_att_tpls/table/attTableHeader.html","app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html","app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.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/typeAhead/typeAhead.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"]);
11 angular.module('att.abs.utilities', [])
13 .filter('unsafe',[ '$sce', function ($sce) {
15 return $sce.trustAsHtml(val);
19 .filter('highlight', function () {
20 function escapeRegexp(queryToEscape) {
21 return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
23 return function (matchItem, query, className) {
24 return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class=\"' + className + '\">$&</span>') : matchItem;
28 .filter('attLimitTo', function() {
29 return function(actualArray, _limit, _begin) {
36 if(actualArray && !isNaN(limit)) {
37 finalArray = actualArray.slice(begin, begin+limit);
39 finalArray = actualArray;
45 .filter('startsWith', function() {
46 if (typeof String.prototype.startsWith !== 'function') {
47 // see below for better implementation!
48 String.prototype.startsWith = function (str){
49 return this.indexOf(str) === 0;
53 return function(items, searchString) {
54 if (searchString === undefined || searchString === "") {
59 angular.forEach(items, function(item) {
60 if (item.title.toLowerCase().startsWith(searchString.toLowerCase())) {
68 .directive('attInputDeny', [function() {
72 link: function (scope, elem, attr, ctrl) {
73 var regexExpression = null;
74 attr.$observe('attInputDeny', function (value) {
76 regexExpression = new RegExp(value, 'g');
79 elem.bind('input', function () {
80 var inputString = ctrl.$viewValue && ctrl.$viewValue.replace(regexExpression, '');
81 if (inputString !== ctrl.$viewValue) {
82 ctrl.$setViewValue(inputString);
91 .directive('attAccessibilityClick', [function() {
94 link: function (scope, elem, attr) {
96 attr.$observe('attAccessibilityClick', function (value) {
98 keyCode = value.split(',');
101 elem.bind('keydown', function (ev) {
102 var keyCodeCondition = function(){
106 ev.keyCode = ev.which;
108 else if(ev.charCode){
109 ev.keyCode = ev.charCode;
112 if((ev.keyCode && keyCode.indexOf(ev.keyCode.toString()) > -1)){
117 if(keyCode.length > 0 && keyCodeCondition()) {
126 .directive('attElementFocus', [function() {
129 link: function(scope, elem, attr) {
130 scope.$watch(attr.attElementFocus, function (value) {
139 .directive('focusOn', ['$timeout',
140 function ($timeout) {
141 var checkDirectivePrerequisites = function (attrs) {
142 if (!attrs.focusOn && attrs.focusOn !== '') {
143 throw 'FocusOnCondition missing attribute to evaluate';
148 link: function (scope, element, attrs) {
149 checkDirectivePrerequisites(attrs);
151 scope.$watch(attrs.focusOn, function (currentValue) {
153 $timeout(function () {
162 .constant('whenScrollEndsConstants', {
167 .directive('whenScrollEnds', function(whenScrollEndsConstants, $log) {
170 link: function (scope, element, attrs) {
172 * Exposed Attributes:
173 * threshold - integer - number of pixels before scrollbar hits end that callback is called
174 * width - integer - override for element's width (px)
175 * height - integer - override for element's height (px)
176 * axis - string - x/y for scroll bar axis
178 var threshold = parseInt(attrs.threshold, 10) || whenScrollEndsConstants.threshold;
180 if (!attrs.axis || attrs.axis === '') {
181 $log.warn('axis attribute must be defined for whenScrollEnds.');
185 if (attrs.axis === 'x') {
186 visibleWidth = parseInt(attrs.width, 10) || whenScrollEndsConstants.width;
187 if (element.css('width')) {
188 visibleWidth = element.css('width').split('px')[0];
191 element[0].addEventListener('scroll', function() {
192 var scrollableWidth = element.prop('scrollWidth');
193 if (scrollableWidth === undefined) {
196 var hiddenContentWidth = scrollableWidth - visibleWidth;
198 if (hiddenContentWidth - element[0].scrollLeft <= threshold) {
199 /* Scroll almost at bottom, load more rows */
200 scope.$apply(attrs.whenScrollEnds);
203 } else if (attrs.axis === 'y') {
204 visibleHeight = parseInt(attrs.height, 10) || whenScrollEndsConstants.height;
205 if (element.css('width')) {
206 visibleHeight = element.css('height').split('px')[0];
209 element[0].addEventListener('scroll', function() {
210 var scrollableHeight = element.prop('scrollHeight');
211 if (scrollableHeight === undefined) {
212 scrollableHeight = 1;
214 var hiddenContentHeight = scrollableHeight - visibleHeight;
216 if (hiddenContentHeight - element[0].scrollTop <= threshold) {
217 /* Scroll almost at bottom, load more rows */
218 scope.$apply(attrs.whenScrollEnds);
226 .directive("validImei", function(){
230 link: function(scope, ele, attrs, ctrl)
232 ctrl.$parsers.unshift(function(value)
236 if (!isNaN(value) && value.length === 15)
240 for (var imeiIndex=0; imeiIndex<15; imeiIndex++)
242 posIMEI[imeiIndex] = parseInt(value.substring(imeiIndex,imeiIndex + 1),10);
243 if (imeiIndex % 2 !== 0)
245 posIMEI[imeiIndex] = parseInt((posIMEI[imeiIndex] * 2),10);
247 if (posIMEI[imeiIndex] > 9)
249 posIMEI[imeiIndex] = parseInt((posIMEI[imeiIndex] % 10),10) + parseInt((posIMEI[imeiIndex] / 10),10);
251 sumImeiVal=sumImeiVal+parseInt((posIMEI[imeiIndex]),10);
254 if((sumImeiVal % 10) === 0)
267 ctrl.$setValidity('invalidImei', scope.valid);
269 return scope.valid ? value : undefined;
275 .directive("togglePassword", function(){
279 link: function(scope, element, attr, ctrl)
281 element.bind("click", function()
283 var ipwd = attr.togglePassword;
284 element[0].innerHTML = element[0].innerHTML === "Show" ? "Hide" : "Show";
285 var e = angular.element(document.querySelector('#' + ipwd))[0].type;
286 angular.element(document.querySelector('#' + ipwd))[0].type = e === "password"? "text" : "password";
294 .factory('events', function(){
295 var _stopPropagation = function(evt){
296 if(evt.stopPropagation) {
297 evt.stopPropagation();
299 evt.returnValue = false;
302 var _preventDefault = function(evt) {
303 if (evt.preventDefault) {
304 evt.preventDefault();
306 evt.returnValue = false;
310 stopPropagation: _stopPropagation,
311 preventDefault: _preventDefault
315 .factory('$documentBind', ['$document', '$timeout', function ($document, $timeout) {
316 var _click = function (flag, callbackFunc, scope) {
317 scope.$watch(flag, function (val) {
318 $timeout(function () {
320 $document.bind('click', callbackFunc);
322 $document.unbind('click', callbackFunc);
328 var _event = function (event, flag, callbackFunc, scope, timeoutFlag, timeoutValue) {
330 if (!(timeoutValue)) {
333 scope.$watch(flag, function (newVal, oldVal) {
334 if (newVal !== oldVal) {
335 $timeout(function () {
337 $document.bind(event, callbackFunc);
339 $document.unbind(event, callbackFunc);
345 scope.$watch(flag, function (newVal, oldVal) {
346 if (newVal !== oldVal) {
348 $document.bind(event, callbackFunc);
350 $document.unbind(event, callbackFunc);
363 .factory('DOMHelper', function() {
365 function isTabable(node) {
366 var element = angular.element(node);
367 var hasTabindex = (parseInt(element.attr('tabindex'), 10) >= 0) ? true : false;
368 var tagName = element[0].tagName.toUpperCase();
370 if (hasTabindex || tagName === 'A' || tagName === 'INPUT' || tagName === 'TEXTAREA') {
371 return !(element[0].disabled || element[0].readOnly);
376 function isValidChild(child) {
377 return child.nodeType == 1 && child.nodeName != 'SCRIPT' && child.nodeName != 'STYLE';
380 function traverse(obj) {
381 var obj = obj || document.getElementsByTagName('body')[0];
382 if (isValidChild(obj) && isTabable(obj)) {
385 if (obj.hasChildNodes()) {
386 var child = obj.firstChild;
388 var res = traverse(child);
393 child = child.nextSibling;
402 var _firstTabableElement = function(el) {
403 /* This will return the first tabable element from the parent el */
405 if (el.hasOwnProperty('length')) {
409 return traverse(elem);
413 firstTabableElement: _firstTabableElement
417 .factory('keymap', function(){
439 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 : "'"
441 isControl: function (e) {
444 case this.KEY.COMMAND:
458 isFunctionKey: function (k) {
459 k = k.keyCode ? k.keyCode : k;
460 return k >= 112 && k <= 123;
462 isVerticalMovement: function (k){
463 return ~[this.KEY.UP, this.KEY.DOWN].indexOf(k);
465 isHorizontalMovement: function (k){
466 return ~[this.KEY.LEFT, this.KEY.RIGHT, this.KEY.BACKSPACE, this.KEY.DELETE].indexOf(k);
468 isAllowedKey: function (k){
469 return (~[this.KEY.SPACE, this.KEY.ESC, this.KEY.ENTER].indexOf(k)) || this.isHorizontalMovement(k) || this.isVerticalMovement(k);
474 .factory('keyMapAc', function(){
476 keys:{ "32":" ", "33":"!", "34":"\"", "35":"#", "36":"$", "37":"%", "38":"&", "39":"'"
477 , "40":"(", "41":")", "42":"*", "43":"+", "44":",", "45":"-", "46":".", "47":"\/", "58":":"
478 , "59":";", "60":"<", "61":"=", "62":">", "63":"?", "64":"@", "91":"[", "92":"\\", "93":"]"
479 , "94":"^", "95":"_", "96":"`", "123":"{", "124":"|", "125":"}", "126":"~"
481 keyRange:{"startNum":"48","endNum":"57","startSmallLetters":"97","endSmallLetters":"122"
482 ,"startCapitalLetters":"65","endCapitalLetters":"90"},
483 allowedKeys:{TAB:8, BACKSPACE:9, DELETE:16}
487 .factory('$attElementDetach', function () {
488 var _detach = function (element) {
489 if (element && element.parentNode) {
490 element.parentNode.removeChild(element);
496 .factory('$ieVersion', function () {
499 var loadIEVersion = function () {
500 var isIE10 = (eval("/*@cc_on!@*/false") && document.documentMode === 10);
505 div = document.createElement('div'),
506 all = div.getElementsByTagName('i');
508 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';
510 return v > 4 ? v : undefined;
515 ie = loadIEVersion();
521 String.prototype.toSnakeCase = function () {
522 return this.replace(/([A-Z])/g, function ($1) {
523 return "-" + $1.toLowerCase();
526 var concat = function (character, times) {
527 character = character || '';
528 times = (!isNaN(times) && times) || 0;
530 for (var i = 0; i < times; i++) {
531 finalChar += character;
536 // direction: true for left and false for right
537 var pad = function (actualString, width, character, direction) {
538 actualString = actualString || '';
539 width = (!isNaN(width) && width) || 0;
540 character = character || '';
541 if (width > actualString.length) {
543 return concat(character, (width - actualString.length)) + actualString;
545 return actualString + concat(character, (width - actualString.length));
551 String.prototype.lPad = function (width, character) {
552 return pad(this, width, character, true);
555 String.prototype.rPad = function (width, character) {
556 return pad(this, width, character, false);
559 if (!Array.prototype.indexOf) {
560 Array.prototype.indexOf = function (val) {
561 for (var index = 0; index < this.length; index++) {
562 if (this[index] === val) {
571 angular.module('att.abs.position', [])
573 .factory('$position', ['$document', '$window', function ($document, $window) {
574 function getStyle(el, cssprop) {
575 if (el.currentStyle) { //IE
576 return el.currentStyle[cssprop];
577 } else if ($window.getComputedStyle) {
578 return $window.getComputedStyle(el)[cssprop];
580 // finally try and get inline style
581 return el.style[cssprop];
585 * Checks if a given element is statically positioned
586 * @param element - raw DOM element
588 function isStaticPositioned(element) {
589 return (getStyle(element, "position") || 'static') === 'static';
593 * returns the closest, non-statically positioned parentOffset of a given element
596 var parentOffsetEl = function (element) {
597 var docDomEl = $document[0];
598 var offsetParent = element.offsetParent || docDomEl;
599 while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) {
600 offsetParent = offsetParent.offsetParent;
602 return offsetParent || docDomEl;
607 * Provides read-only equivalent of jQuery's position function:
608 * http://api.jquery.com/position/
610 position: function (element) {
611 var elBCR = this.offset(element);
612 var offsetParentBCR = {
616 var offsetParentEl = parentOffsetEl(element[0]);
617 if (offsetParentEl !== $document[0]) {
618 offsetParentBCR = this.offset(angular.element(offsetParentEl));
619 offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
620 offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
624 width: element.prop('offsetWidth'),
625 height: element.prop('offsetHeight'),
626 top: elBCR.top - offsetParentBCR.top,
627 left: elBCR.left - offsetParentBCR.left
632 * Provides read-only equivalent of jQuery's offset function:
633 * http://api.jquery.com/offset/
635 offset: function (element) {
636 var boundingClientRect = element[0].getBoundingClientRect();
638 width: element.prop('offsetWidth'),
639 height: element.prop('offsetHeight'),
640 top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
641 left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
647 .factory('$isElement', [function () {
648 var isElement = function (currentElem, targetElem, alternateElem) {
649 if (currentElem[0] === targetElem[0]) {
651 } else if (currentElem[0] === alternateElem[0]) {
654 return isElement((currentElem.parent()[0] && currentElem.parent()) || targetElem, targetElem, alternateElem);
661 .directive('attPosition', ['$position', function ($position) {
664 link: function (scope, elem, attr) {
665 scope.$watchCollection(function () {
666 return $position.position(elem);
667 }, function (value) {
668 scope[attr.attPosition] = value;
677 * UPDATES AND DOCS AT: http://www.greensock.com
679 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
680 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
681 * Club GreenSock members, the software agreement that was issued with your membership.
683 * @author: Jack Doyle, jack@greensock.com
685 (window._gsQueue || (window._gsQueue = [])).push( function() {
689 var _doc = document.documentElement,
691 _max = function(element, axis) {
692 var dim = (axis === "x") ? "Width" : "Height",
693 scroll = "scroll" + dim,
694 client = "client" + dim,
695 body = document.body;
696 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];
699 ScrollToPlugin = window._gsDefine.plugin({
700 propName: "scrollTo",
704 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
705 init: function(target, value, tween) {
706 this._wdw = (target === _window);
707 this._target = target;
709 if (typeof(value) !== "object") {
710 value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
712 this._autoKill = (value.autoKill !== false);
713 this.x = this.xPrev = this.getX();
714 this.y = this.yPrev = this.getY();
715 if (value.x != null) {
716 this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
717 this._overwriteProps.push("scrollTo_x");
721 if (value.y != null) {
722 this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
723 this._overwriteProps.push("scrollTo_y");
730 //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.)
732 this._super.setRatio.call(this, v);
734 var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
735 y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
736 yDif = y - this.yPrev,
737 xDif = x - this.xPrev;
739 if (this._autoKill) {
740 //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.
741 if (!this.skipX && (xDif > 7 || xDif < -7) && x < _max(this._target, "x")) {
742 this.skipX = true; //if the user scrolls separately, we should stop tweening!
744 if (!this.skipY && (yDif > 7 || yDif < -7) && y < _max(this._target, "y")) {
745 this.skipY = true; //if the user scrolls separately, we should stop tweening!
747 if (this.skipX && this.skipY) {
752 _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
755 this._target.scrollTop = this.y;
758 this._target.scrollLeft = this.x;
766 p = ScrollToPlugin.prototype;
768 ScrollToPlugin.max = _max;
770 p.getX = function() {
771 return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
774 p.getY = function() {
775 return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
778 p._kill = function(lookup) {
779 if (lookup.scrollTo_x) {
782 if (lookup.scrollTo_y) {
785 return this._super._kill.call(this, lookup);
788 }); if (window._gsDefine) { window._gsQueue.pop()(); }
792 * UPDATES AND DOCS AT: http://www.greensock.com
794 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
796 * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.
797 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
798 * Club GreenSock members, the software agreement that was issued with your membership.
800 * @author: Jack Doyle, jack@greensock.com
803 (window._gsQueue || (window._gsQueue = [])).push( function() {
807 window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
809 var _slice = [].slice,
810 TweenMax = function(target, duration, vars) {
811 TweenLite.call(this, target, duration, vars);
813 this._yoyo = (this.vars.yoyo === true);
814 this._repeat = this.vars.repeat || 0;
815 this._repeatDelay = this.vars.repeatDelay || 0;
816 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
817 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
819 _tinyNum = 0.0000000001,
820 TweenLiteInternals = TweenLite._internals,
821 _isSelector = TweenLiteInternals.isSelector,
822 _isArray = TweenLiteInternals.isArray,
823 p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
826 TweenMax.version = "1.12.1";
827 p.constructor = TweenMax;
828 p.kill()._gc = false;
829 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
830 TweenMax.getTweensOf = TweenLite.getTweensOf;
831 TweenMax.lagSmoothing = TweenLite.lagSmoothing;
832 TweenMax.ticker = TweenLite.ticker;
833 TweenMax.render = TweenLite.render;
835 p.invalidate = function() {
836 this._yoyo = (this.vars.yoyo === true);
837 this._repeat = this.vars.repeat || 0;
838 this._repeatDelay = this.vars.repeatDelay || 0;
840 return TweenLite.prototype.invalidate.call(this);
843 p.updateTo = function(vars, resetDuration) {
844 var curRatio = this.ratio, p;
845 if (resetDuration && this._startTime < this._timeline._time) {
846 this._startTime = this._timeline._time;
847 this._uncache(false);
849 this._enabled(true, false);
851 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.
855 this.vars[p] = vars[p];
859 this._initted = false;
862 this._enabled(true, false);
864 if (this._notifyPluginsOfEnabled && this._firstPT) {
865 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
867 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.
868 var prevTime = this._time;
869 this.render(0, true, false);
870 this._initted = false;
871 this.render(prevTime, true, false);
872 } else if (this._time > 0) {
873 this._initted = false;
875 var inv = 1 / (1 - curRatio),
876 pt = this._firstPT, endValue;
878 endValue = pt.s + pt.c;
880 pt.s = endValue - pt.c;
889 p.render = function(time, suppressEvents, force) {
890 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.
893 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
894 prevTime = this._time,
895 prevTotalTime = this._totalTime,
896 prevCycle = this._cycle,
897 duration = this._duration,
898 prevRawPrevTime = this._rawPrevTime,
899 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i;
900 if (time >= totalDur) {
901 this._totalTime = totalDur;
902 this._cycle = this._repeat;
903 if (this._yoyo && (this._cycle & 1) !== 0) {
905 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
907 this._time = duration;
908 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
910 if (!this._reversed) {
912 callback = "onComplete";
914 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.
915 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.
918 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
920 if (prevRawPrevTime > _tinyNum) {
921 callback = "onReverseComplete";
924 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.
927 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
928 this._totalTime = this._time = this._cycle = 0;
929 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
930 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
931 callback = "onReverseComplete";
932 isComplete = this._reversed;
935 this._active = false;
936 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.
937 if (prevRawPrevTime >= 0) {
940 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.
942 } 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.
946 this._totalTime = this._time = time;
948 if (this._repeat !== 0) {
949 cycleDuration = duration + this._repeatDelay;
950 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!)
951 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
952 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
954 this._time = this._totalTime - (this._cycle * cycleDuration);
955 if (this._yoyo) if ((this._cycle & 1) !== 0) {
956 this._time = duration - this._time;
958 if (this._time > duration) {
959 this._time = duration;
960 } else if (this._time < 0) {
965 if (this._easeType) {
966 r = this._time / duration;
967 type = this._easeType;
968 pow = this._easePower;
969 if (type === 1 || (type === 3 && r >= 0.5)) {
977 } else if (pow === 2) {
979 } else if (pow === 3) {
981 } else if (pow === 4) {
987 } else if (type === 2) {
989 } else if (this._time / duration < 0.5) {
992 this.ratio = 1 - (r / 2);
996 this.ratio = this._ease.getRatio(this._time / duration);
1001 if (prevTime === this._time && !force && prevCycle === this._cycle) {
1002 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.
1003 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1006 } else if (!this._initted) {
1008 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.
1010 } 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.
1011 this._time = prevTime;
1012 this._totalTime = prevTotalTime;
1013 this._rawPrevTime = prevRawPrevTime;
1014 this._cycle = prevCycle;
1015 TweenLiteInternals.lazyTweens.push(this);
1019 //_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.
1020 if (this._time && !isComplete) {
1021 this.ratio = this._ease.getRatio(this._time / duration);
1022 } else if (isComplete && this._ease._calcEnd) {
1023 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
1026 if (this._lazy !== false) {
1030 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
1031 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.
1033 if (prevTotalTime === 0) {
1034 if (this._initted === 2 && time > 0) {
1035 //this.invalidate();
1036 this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
1038 if (this._startAt) {
1040 this._startAt.render(time, suppressEvents, force);
1041 } else if (!callback) {
1042 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.
1045 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
1046 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1053 pt.t[pt.p](pt.c * this.ratio + pt.s);
1055 pt.t[pt.p] = pt.c * this.ratio + pt.s;
1060 if (this._onUpdate) {
1061 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.
1062 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.
1064 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
1065 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1068 if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
1069 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
1071 if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
1072 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.
1073 this._startAt.render(time, suppressEvents, force);
1076 if (this._timeline.autoRemoveChildren) {
1077 this._enabled(false, false);
1079 this._active = false;
1081 if (!suppressEvents && this.vars[callback]) {
1082 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1084 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.
1085 this._rawPrevTime = 0;
1090 //---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
1092 TweenMax.to = function(target, duration, vars) {
1093 return new TweenMax(target, duration, vars);
1096 TweenMax.from = function(target, duration, vars) {
1097 vars.runBackwards = true;
1098 vars.immediateRender = (vars.immediateRender != false);
1099 return new TweenMax(target, duration, vars);
1102 TweenMax.fromTo = function(target, duration, fromVars, toVars) {
1103 toVars.startAt = fromVars;
1104 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
1105 return new TweenMax(target, duration, toVars);
1108 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1109 stagger = stagger || 0;
1110 var delay = vars.delay || 0,
1112 finalComplete = function() {
1113 if (vars.onComplete) {
1114 vars.onComplete.apply(vars.onCompleteScope || this, arguments);
1116 onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
1119 if (!_isArray(targets)) {
1120 if (typeof(targets) === "string") {
1121 targets = TweenLite.selector(targets) || targets;
1123 if (_isSelector(targets)) {
1124 targets = _slice.call(targets, 0);
1128 for (i = 0; i < l; i++) {
1134 if (i === l - 1 && onCompleteAll) {
1135 copy.onComplete = finalComplete;
1137 a[i] = new TweenMax(targets[i], duration, copy);
1143 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1144 vars.runBackwards = true;
1145 vars.immediateRender = (vars.immediateRender != false);
1146 return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
1149 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1150 toVars.startAt = fromVars;
1151 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
1152 return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
1155 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
1156 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});
1159 TweenMax.set = function(target, vars) {
1160 return new TweenMax(target, 0, vars);
1163 TweenMax.isTweening = function(target) {
1164 return (TweenLite.getTweensOf(target, true).length > 0);
1167 var _getChildrenOf = function(timeline, includeTimelines) {
1170 tween = timeline._first;
1172 if (tween instanceof TweenLite) {
1175 if (includeTimelines) {
1178 a = a.concat(_getChildrenOf(tween, includeTimelines));
1181 tween = tween._next;
1185 getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
1186 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
1189 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
1190 if (tweens == null) {
1193 if (delayedCalls == null) {
1194 delayedCalls = true;
1196 var a = getAllTweens((timelines != false)),
1198 allTrue = (tweens && delayedCalls && timelines),
1200 for (i = 0; i < l; i++) {
1202 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
1204 tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
1206 tween._enabled(false, false);
1212 TweenMax.killChildTweensOf = function(parent, complete) {
1213 if (parent == null) {
1216 var tl = TweenLiteInternals.tweenLookup,
1217 a, curParent, p, i, l;
1218 if (typeof(parent) === "string") {
1219 parent = TweenLite.selector(parent) || parent;
1221 if (_isSelector(parent)) {
1222 parent = _slice.call(parent, 0);
1224 if (_isArray(parent)) {
1227 TweenMax.killChildTweensOf(parent[i], complete);
1233 curParent = tl[p].target.parentNode;
1235 if (curParent === parent) {
1236 a = a.concat(tl[p].tweens);
1238 curParent = curParent.parentNode;
1242 for (i = 0; i < l; i++) {
1244 a[i].totalTime(a[i].totalDuration());
1246 a[i]._enabled(false, false);
1250 var _changePause = function(pause, tweens, delayedCalls, timelines) {
1251 tweens = (tweens !== false);
1252 delayedCalls = (delayedCalls !== false);
1253 timelines = (timelines !== false);
1254 var a = getAllTweens(timelines),
1255 allTrue = (tweens && delayedCalls && timelines),
1260 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
1261 tween.paused(pause);
1266 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
1267 _changePause(true, tweens, delayedCalls, timelines);
1270 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
1271 _changePause(false, tweens, delayedCalls, timelines);
1274 TweenMax.globalTimeScale = function(value) {
1275 var tl = Animation._rootTimeline,
1276 t = TweenLite.ticker.time;
1277 if (!arguments.length) {
1278 return tl._timeScale;
1280 value = value || _tinyNum; //can't allow zero because it'll throw the math off
1281 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
1282 tl = Animation._rootFramesTimeline;
1283 t = TweenLite.ticker.frame;
1284 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
1285 tl._timeScale = Animation._rootTimeline._timeScale = value;
1290 //---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
1292 p.progress = function(value) {
1293 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);
1296 p.totalProgress = function(value) {
1297 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
1300 p.time = function(value, suppressEvents) {
1301 if (!arguments.length) {
1305 this.totalDuration();
1307 if (value > this._duration) {
1308 value = this._duration;
1310 if (this._yoyo && (this._cycle & 1) !== 0) {
1311 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
1312 } else if (this._repeat !== 0) {
1313 value += this._cycle * (this._duration + this._repeatDelay);
1315 return this.totalTime(value, suppressEvents);
1318 p.duration = function(value) {
1319 if (!arguments.length) {
1320 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.
1322 return Animation.prototype.duration.call(this, value);
1325 p.totalDuration = function(value) {
1326 if (!arguments.length) {
1328 //instead of Infinity, we use 999999999999 so that we can accommodate reverses
1329 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
1330 this._dirty = false;
1332 return this._totalDuration;
1334 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
1337 p.repeat = function(value) {
1338 if (!arguments.length) {
1339 return this._repeat;
1341 this._repeat = value;
1342 return this._uncache(true);
1345 p.repeatDelay = function(value) {
1346 if (!arguments.length) {
1347 return this._repeatDelay;
1349 this._repeatDelay = value;
1350 return this._uncache(true);
1353 p.yoyo = function(value) {
1354 if (!arguments.length) {
1374 * ----------------------------------------------------------------
1376 * ----------------------------------------------------------------
1378 window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
1380 var TimelineLite = function(vars) {
1381 SimpleTimeline.call(this, vars);
1383 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
1384 this.smoothChildTiming = (this.vars.smoothChildTiming === true);
1385 this._sortChildren = true;
1386 this._onUpdate = this.vars.onUpdate;
1391 if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
1392 v[p] = this._swapSelfInParams(val);
1395 if (_isArray(v.tweens)) {
1396 this.add(v.tweens, 0, v.align, v.stagger);
1399 _tinyNum = 0.0000000001,
1400 _isSelector = TweenLite._internals.isSelector,
1401 _isArray = TweenLite._internals.isArray,
1403 _globals = window._gsDefine.globals,
1404 _copy = function(vars) {
1411 _pauseCallback = function(tween, callback, params, scope) {
1412 tween._timeline.pause(tween._startTime);
1414 callback.apply(scope || tween._timeline, params || _blankArray);
1417 _slice = _blankArray.slice,
1418 p = TimelineLite.prototype = new SimpleTimeline();
1420 TimelineLite.version = "1.12.1";
1421 p.constructor = TimelineLite;
1422 p.kill()._gc = false;
1424 p.to = function(target, duration, vars, position) {
1425 var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
1426 return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
1429 p.from = function(target, duration, vars, position) {
1430 return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
1433 p.fromTo = function(target, duration, fromVars, toVars, position) {
1434 var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
1435 return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
1438 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1439 var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
1441 if (typeof(targets) === "string") {
1442 targets = TweenLite.selector(targets) || targets;
1444 if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
1445 targets = _slice.call(targets, 0);
1447 stagger = stagger || 0;
1448 for (i = 0; i < targets.length; i++) {
1450 vars.startAt = _copy(vars.startAt);
1452 tl.to(targets[i], duration, _copy(vars), i * stagger);
1454 return this.add(tl, position);
1457 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1458 vars.immediateRender = (vars.immediateRender != false);
1459 vars.runBackwards = true;
1460 return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
1463 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
1464 toVars.startAt = fromVars;
1465 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
1466 return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
1469 p.call = function(callback, params, scope, position) {
1470 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
1473 p.set = function(target, vars, position) {
1474 position = this._parseTimeOrLabel(position, 0, true);
1475 if (vars.immediateRender == null) {
1476 vars.immediateRender = (position === this._time && !this._paused);
1478 return this.add( new TweenLite(target, 0, vars), position);
1481 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
1483 if (vars.smoothChildTiming == null) {
1484 vars.smoothChildTiming = true;
1486 var tl = new TimelineLite(vars),
1487 root = tl._timeline,
1489 if (ignoreDelayedCalls == null) {
1490 ignoreDelayedCalls = true;
1492 root._remove(tl, true);
1494 tl._rawPrevTime = tl._time = tl._totalTime = root._time;
1495 tween = root._first;
1498 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
1499 tl.add(tween, tween._startTime - tween._delay);
1507 p.add = function(value, position, align, stagger) {
1508 var curTime, l, i, child, tl, beforeRawTime;
1509 if (typeof(position) !== "number") {
1510 position = this._parseTimeOrLabel(position, 0, true, value);
1512 if (!(value instanceof Animation)) {
1513 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
1514 align = align || "normal";
1515 stagger = stagger || 0;
1518 for (i = 0; i < l; i++) {
1519 if (_isArray(child = value[i])) {
1520 child = new TimelineLite({tweens:child});
1522 this.add(child, curTime);
1523 if (typeof(child) !== "string" && typeof(child) !== "function") {
1524 if (align === "sequence") {
1525 curTime = child._startTime + (child.totalDuration() / child._timeScale);
1526 } else if (align === "start") {
1527 child._startTime -= child.delay();
1532 return this._uncache(true);
1533 } else if (typeof(value) === "string") {
1534 return this.addLabel(value, position);
1535 } else if (typeof(value) === "function") {
1536 value = TweenLite.delayedCall(0, value);
1538 throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
1542 SimpleTimeline.prototype.add.call(this, value, position);
1544 //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.
1545 if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
1546 //in case any of the ancestors had completed but should now be enabled...
1548 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.
1549 while (tl._timeline) {
1550 if (beforeRawTime && tl._timeline.smoothChildTiming) {
1551 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
1552 } else if (tl._gc) {
1553 tl._enabled(true, false);
1562 p.remove = function(value) {
1563 if (value instanceof Animation) {
1564 return this._remove(value, false);
1565 } else if (value instanceof Array || (value && value.push && _isArray(value))) {
1566 var i = value.length;
1568 this.remove(value[i]);
1571 } else if (typeof(value) === "string") {
1572 return this.removeLabel(value);
1574 return this.kill(null, value);
1577 p._remove = function(tween, skipDisable) {
1578 SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
1579 var last = this._last;
1581 this._time = this._totalTime = this._duration = this._totalDuration = 0;
1582 } else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
1583 this._time = this.duration();
1584 this._totalTime = this._totalDuration;
1589 p.append = function(value, offsetOrLabel) {
1590 return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
1593 p.insert = p.insertMultiple = function(value, position, align, stagger) {
1594 return this.add(value, position || 0, align, stagger);
1597 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
1598 return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
1601 p.addLabel = function(label, position) {
1602 this._labels[label] = this._parseTimeOrLabel(position);
1606 p.addPause = function(position, callback, params, scope) {
1607 return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position);
1610 p.removeLabel = function(label) {
1611 delete this._labels[label];
1615 p.getLabelTime = function(label) {
1616 return (this._labels[label] != null) ? this._labels[label] : -1;
1619 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
1621 //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().
1622 if (ignore instanceof Animation && ignore.timeline === this) {
1623 this.remove(ignore);
1624 } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
1627 if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
1628 this.remove(ignore[i]);
1632 if (typeof(offsetOrLabel) === "string") {
1633 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
1635 offsetOrLabel = offsetOrLabel || 0;
1636 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).
1637 i = timeOrLabel.indexOf("=");
1639 if (this._labels[timeOrLabel] == null) {
1640 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
1642 return this._labels[timeOrLabel] + offsetOrLabel;
1644 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
1645 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
1646 } else if (timeOrLabel == null) {
1647 timeOrLabel = this.duration();
1649 return Number(timeOrLabel) + offsetOrLabel;
1652 p.seek = function(position, suppressEvents) {
1653 return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
1656 p.stop = function() {
1657 return this.paused(true);
1660 p.gotoAndPlay = function(position, suppressEvents) {
1661 return this.play(position, suppressEvents);
1664 p.gotoAndStop = function(position, suppressEvents) {
1665 return this.pause(position, suppressEvents);
1668 p.render = function(time, suppressEvents, force) {
1670 this._enabled(true, false);
1672 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
1673 prevTime = this._time,
1674 prevStart = this._startTime,
1675 prevTimeScale = this._timeScale,
1676 prevPaused = this._paused,
1677 tween, isComplete, next, callback, internalForce;
1678 if (time >= totalDur) {
1679 this._totalTime = this._time = totalDur;
1680 if (!this._reversed) if (!this._hasPausedChild()) {
1682 callback = "onComplete";
1683 if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
1684 internalForce = true;
1685 if (this._rawPrevTime > _tinyNum) {
1686 callback = "onReverseComplete";
1690 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.
1691 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.
1693 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
1694 this._totalTime = this._time = 0;
1695 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
1696 callback = "onReverseComplete";
1697 isComplete = this._reversed;
1700 this._active = false;
1701 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.
1702 internalForce = true;
1704 this._rawPrevTime = time;
1706 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.
1708 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
1709 if (!this._initted) {
1710 internalForce = true;
1715 this._totalTime = this._time = this._rawPrevTime = time;
1717 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
1719 } else if (!this._initted) {
1720 this._initted = true;
1723 if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
1724 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.
1727 if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
1728 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
1731 if (this._time >= prevTime) {
1732 tween = this._first;
1734 next = tween._next; //record it here because the value could change after rendering...
1735 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1737 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
1738 if (!tween._reversed) {
1739 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1741 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1749 next = tween._prev; //record it here because the value could change after rendering...
1750 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
1752 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
1753 if (!tween._reversed) {
1754 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
1756 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
1763 if (this._onUpdate) if (!suppressEvents) {
1764 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
1767 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
1769 if (this._timeline.autoRemoveChildren) {
1770 this._enabled(false, false);
1772 this._active = false;
1774 if (!suppressEvents && this.vars[callback]) {
1775 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
1780 p._hasPausedChild = function() {
1781 var tween = this._first;
1783 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
1786 tween = tween._next;
1791 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
1792 ignoreBeforeTime = ignoreBeforeTime || -9999999999;
1794 tween = this._first,
1797 if (tween._startTime < ignoreBeforeTime) {
1799 } else if (tween instanceof TweenLite) {
1800 if (tweens !== false) {
1804 if (timelines !== false) {
1807 if (nested !== false) {
1808 a = a.concat(tween.getChildren(true, tweens, timelines));
1812 tween = tween._next;
1817 p.getTweensOf = function(target, nested) {
1818 var disabled = this._gc,
1823 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.
1825 tweens = TweenLite.getTweensOf(target);
1828 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
1829 a[cnt++] = tweens[i];
1833 this._enabled(false, true);
1838 p._contains = function(tween) {
1839 var tl = tween.timeline;
1849 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
1850 ignoreBeforeTime = ignoreBeforeTime || 0;
1851 var tween = this._first,
1852 labels = this._labels,
1855 if (tween._startTime >= ignoreBeforeTime) {
1856 tween._startTime += amount;
1858 tween = tween._next;
1862 if (labels[p] >= ignoreBeforeTime) {
1863 labels[p] += amount;
1867 return this._uncache(true);
1870 p._kill = function(vars, target) {
1871 if (!vars && !target) {
1872 return this._enabled(false, false);
1874 var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
1878 if (tweens[i]._kill(vars, target)) {
1885 p.clear = function(labels) {
1886 var tweens = this.getChildren(false, true, true),
1888 this._time = this._totalTime = 0;
1890 tweens[i]._enabled(false, false);
1892 if (labels !== false) {
1895 return this._uncache(true);
1898 p.invalidate = function() {
1899 var tween = this._first;
1902 tween = tween._next;
1907 p._enabled = function(enabled, ignoreTimeline) {
1908 if (enabled === this._gc) {
1909 var tween = this._first;
1911 tween._enabled(enabled, true);
1912 tween = tween._next;
1915 return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
1918 p.duration = function(value) {
1919 if (!arguments.length) {
1921 this.totalDuration(); //just triggers recalculation
1923 return this._duration;
1925 if (this.duration() !== 0 && value !== 0) {
1926 this.timeScale(this._duration / value);
1931 p.totalDuration = function(value) {
1932 if (!arguments.length) {
1936 prevStart = 999999999999,
1939 prev = tween._prev; //record it here in case the tween changes position in the sequence...
1941 tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
1943 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
1944 this.add(tween, tween._startTime - tween._delay);
1946 prevStart = tween._startTime;
1948 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.
1949 max -= tween._startTime;
1950 if (this._timeline.smoothChildTiming) {
1951 this._startTime += tween._startTime / this._timeScale;
1953 this.shiftChildren(-tween._startTime, false, -9999999999);
1956 end = tween._startTime + (tween._totalDuration / tween._timeScale);
1962 this._duration = this._totalDuration = max;
1963 this._dirty = false;
1965 return this._totalDuration;
1967 if (this.totalDuration() !== 0) if (value !== 0) {
1968 this.timeScale(this._totalDuration / value);
1973 p.usesFrames = function() {
1974 var tl = this._timeline;
1975 while (tl._timeline) {
1978 return (tl === Animation._rootFramesTimeline);
1981 p.rawTime = function() {
1982 return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
1985 return TimelineLite;
2002 * ----------------------------------------------------------------
2004 * ----------------------------------------------------------------
2006 window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
2008 var TimelineMax = function(vars) {
2009 TimelineLite.call(this, vars);
2010 this._repeat = this.vars.repeat || 0;
2011 this._repeatDelay = this.vars.repeatDelay || 0;
2013 this._yoyo = (this.vars.yoyo === true);
2016 _tinyNum = 0.0000000001,
2018 _easeNone = new Ease(null, null, 1, 0),
2019 p = TimelineMax.prototype = new TimelineLite();
2021 p.constructor = TimelineMax;
2022 p.kill()._gc = false;
2023 TimelineMax.version = "1.12.1";
2025 p.invalidate = function() {
2026 this._yoyo = (this.vars.yoyo === true);
2027 this._repeat = this.vars.repeat || 0;
2028 this._repeatDelay = this.vars.repeatDelay || 0;
2029 this._uncache(true);
2030 return TimelineLite.prototype.invalidate.call(this);
2033 p.addCallback = function(callback, position, params, scope) {
2034 return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
2037 p.removeCallback = function(callback, position) {
2039 if (position == null) {
2040 this._kill(null, callback);
2042 var a = this.getTweensOf(callback, false),
2044 time = this._parseTimeOrLabel(position);
2046 if (a[i]._startTime === time) {
2047 a[i]._enabled(false, false);
2055 p.tweenTo = function(position, vars) {
2057 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.
2062 copy.time = this._parseTimeOrLabel(position);
2063 duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001;
2064 t = new TweenLite(this, duration, copy);
2065 copy.onStart = function() {
2066 t.target.paused(true);
2067 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.
2068 t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
2070 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
2071 vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
2077 p.tweenFromTo = function(fromPosition, toPosition, vars) {
2079 fromPosition = this._parseTimeOrLabel(fromPosition);
2080 vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
2081 vars.immediateRender = (vars.immediateRender !== false);
2082 var t = this.tweenTo(toPosition, vars);
2083 return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
2086 p.render = function(time, suppressEvents, force) {
2088 this._enabled(true, false);
2090 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
2091 dur = this._duration,
2092 prevTime = this._time,
2093 prevTotalTime = this._totalTime,
2094 prevStart = this._startTime,
2095 prevTimeScale = this._timeScale,
2096 prevRawPrevTime = this._rawPrevTime,
2097 prevPaused = this._paused,
2098 prevCycle = this._cycle,
2099 tween, isComplete, next, callback, internalForce, cycleDuration;
2100 if (time >= totalDur) {
2101 if (!this._locked) {
2102 this._totalTime = totalDur;
2103 this._cycle = this._repeat;
2105 if (!this._reversed) if (!this._hasPausedChild()) {
2107 callback = "onComplete";
2108 if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) {
2109 internalForce = true;
2110 if (prevRawPrevTime > _tinyNum) {
2111 callback = "onReverseComplete";
2115 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.
2116 if (this._yoyo && (this._cycle & 1) !== 0) {
2117 this._time = time = 0;
2120 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.
2123 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
2124 if (!this._locked) {
2125 this._totalTime = this._cycle = 0;
2128 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)
2129 callback = "onReverseComplete";
2130 isComplete = this._reversed;
2133 this._active = false;
2134 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.
2135 internalForce = true;
2137 this._rawPrevTime = time;
2139 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.
2140 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
2141 if (!this._initted) {
2142 internalForce = true;
2147 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.
2148 internalForce = true;
2150 this._time = this._rawPrevTime = time;
2151 if (!this._locked) {
2152 this._totalTime = time;
2153 if (this._repeat !== 0) {
2154 cycleDuration = dur + this._repeatDelay;
2155 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!)
2156 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
2157 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
2159 this._time = this._totalTime - (this._cycle * cycleDuration);
2160 if (this._yoyo) if ((this._cycle & 1) !== 0) {
2161 this._time = dur - this._time;
2163 if (this._time > dur) {
2165 time = dur + 0.0001; //to avoid occasional floating point rounding error
2166 } else if (this._time < 0) {
2167 this._time = time = 0;
2175 if (this._cycle !== prevCycle) if (!this._locked) {
2177 make sure children at the end/beginning of the timeline are rendered properly. If, for example,
2178 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
2179 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
2180 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
2181 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
2182 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
2184 var backwards = (this._yoyo && (prevCycle & 1) !== 0),
2185 wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
2186 recTotalTime = this._totalTime,
2187 recCycle = this._cycle,
2188 recRawPrevTime = this._rawPrevTime,
2189 recTime = this._time;
2191 this._totalTime = prevCycle * dur;
2192 if (this._cycle < prevCycle) {
2193 backwards = !backwards;
2195 this._totalTime += dur;
2197 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.
2199 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime;
2200 this._cycle = prevCycle;
2201 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
2202 prevTime = (backwards) ? 0 : dur;
2203 this.render(prevTime, suppressEvents, (dur === 0));
2204 if (!suppressEvents) if (!this._gc) {
2205 if (this.vars.onRepeat) {
2206 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
2210 prevTime = (backwards) ? dur + 0.0001 : -0.0001;
2211 this.render(prevTime, true, false);
2213 this._locked = false;
2214 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
2217 this._time = recTime;
2218 this._totalTime = recTotalTime;
2219 this._cycle = recCycle;
2220 this._rawPrevTime = recRawPrevTime;
2223 if ((this._time === prevTime || !this._first) && !force && !internalForce) {
2224 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.
2225 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
2228 } else if (!this._initted) {
2229 this._initted = true;
2232 if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) {
2233 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.
2236 if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
2237 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
2240 if (this._time >= prevTime) {
2241 tween = this._first;
2243 next = tween._next; //record it here because the value could change after rendering...
2244 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
2246 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
2247 if (!tween._reversed) {
2248 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
2250 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
2259 next = tween._prev; //record it here because the value could change after rendering...
2260 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
2262 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
2263 if (!tween._reversed) {
2264 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
2266 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
2273 if (this._onUpdate) if (!suppressEvents) {
2274 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
2276 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
2278 if (this._timeline.autoRemoveChildren) {
2279 this._enabled(false, false);
2281 this._active = false;
2283 if (!suppressEvents && this.vars[callback]) {
2284 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
2289 p.getActive = function(nested, tweens, timelines) {
2290 if (nested == null) {
2293 if (tweens == null) {
2296 if (timelines == null) {
2300 all = this.getChildren(nested, tweens, timelines),
2304 for (i = 0; i < l; i++) {
2306 if (tween.isActive()) {
2314 p.getLabelAfter = function(time) {
2315 if (!time) if (time !== 0) { //faster than isNan()
2318 var labels = this.getLabelsArray(),
2321 for (i = 0; i < l; i++) {
2322 if (labels[i].time > time) {
2323 return labels[i].name;
2329 p.getLabelBefore = function(time) {
2333 var labels = this.getLabelsArray(),
2336 if (labels[i].time < time) {
2337 return labels[i].name;
2343 p.getLabelsArray = function() {
2347 for (p in this._labels) {
2348 a[cnt++] = {time:this._labels[p], name:p};
2350 a.sort(function(a,b) {
2351 return a.time - b.time;
2357 //---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
2359 p.progress = function(value) {
2360 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);
2363 p.totalProgress = function(value) {
2364 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
2367 p.totalDuration = function(value) {
2368 if (!arguments.length) {
2370 TimelineLite.prototype.totalDuration.call(this); //just forces refresh
2371 //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
2372 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
2374 return this._totalDuration;
2376 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
2379 p.time = function(value, suppressEvents) {
2380 if (!arguments.length) {
2384 this.totalDuration();
2386 if (value > this._duration) {
2387 value = this._duration;
2389 if (this._yoyo && (this._cycle & 1) !== 0) {
2390 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
2391 } else if (this._repeat !== 0) {
2392 value += this._cycle * (this._duration + this._repeatDelay);
2394 return this.totalTime(value, suppressEvents);
2397 p.repeat = function(value) {
2398 if (!arguments.length) {
2399 return this._repeat;
2401 this._repeat = value;
2402 return this._uncache(true);
2405 p.repeatDelay = function(value) {
2406 if (!arguments.length) {
2407 return this._repeatDelay;
2409 this._repeatDelay = value;
2410 return this._uncache(true);
2413 p.yoyo = function(value) {
2414 if (!arguments.length) {
2421 p.currentLabel = function(value) {
2422 if (!arguments.length) {
2423 return this.getLabelBefore(this._time + 0.00000001);
2425 return this.seek(value, true);
2444 * ----------------------------------------------------------------
2446 * ----------------------------------------------------------------
2450 var _RAD2DEG = 180 / Math.PI,
2455 Segment = function(a, b, c, d) {
2464 _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
2465 cubicToQuadratic = function(a, b, c, d) {
2473 mabc = (mab + mbc) / 2,
2474 mbcd = (mbc + mcd) / 2,
2475 m8 = (mbcd - mabc) / 8;
2476 q1.b = mab + (a - mab) / 4;
2478 q1.c = q2.a = (q1.b + q2.b) / 2;
2479 q2.c = q3.a = (mabc + mbcd) / 2;
2481 q4.b = mcd + (d - mcd) / 4;
2482 q3.c = q4.a = (q3.b + q4.b) / 2;
2483 return [q1, q2, q3, q4];
2485 _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
2486 var l = a.length - 1,
2489 i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
2490 for (i = 0; i < l; i++) {
2499 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
2500 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
2501 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
2502 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
2504 m1 = p2 - (p2 - p1) * curviness * 0.5;
2505 m2 = p2 + (p3 - p2) * curviness * 0.5;
2506 mm = p2 - (m1 + m2) / 2;
2515 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.
2523 qb = cubicToQuadratic(p1, cp1, cp2, p2);
2524 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
2534 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.
2535 seg.da = seg.d - seg.a;
2536 seg.ca = seg.c - seg.a;
2537 seg.ba = cp1 - seg.a;
2539 qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
2540 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
2543 _parseAnchors = function(values, p, correlate, prepend) {
2545 l, i, p1, p2, p3, tmp;
2547 values = [prepend].concat(values);
2550 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
2551 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
2555 l = values.length - 2;
2557 a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
2560 for (i = 0; i < l; i++) {
2562 p2 = values[i+1][p];
2563 a[i] = new Segment(p1, 0, 0, p2);
2565 p3 = values[i+2][p];
2566 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
2567 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
2570 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
2573 bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
2576 first = prepend || values[0],
2577 i, p, a, j, r, l, seamless, last;
2578 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
2579 if (curviness == null) {
2582 for (p in values[0]) {
2585 //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)
2586 if (values.length > 1) {
2587 last = values[values.length - 1];
2592 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
2598 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
2600 values.unshift(prepend);
2602 values.push(values[1]);
2603 prepend = values[values.length - 3];
2606 _r1.length = _r2.length = _r3.length = 0;
2610 _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
2611 obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
2615 _r1[i] = Math.sqrt(_r1[i]);
2616 _r2[i] = Math.sqrt(_r2[i]);
2624 for (j = 0; j < l; j++) {
2625 r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
2626 _r3[j] = (_r3[j] || 0) + r * r;
2632 _r3[i] = Math.sqrt(_r3[i]);
2636 j = quadratic ? 4 : 1;
2640 _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
2643 a.splice(a.length - j, j);
2648 _parseBezierData = function(values, type, prepend) {
2649 type = type || "soft";
2651 inc = (type === "cubic") ? 3 : 2,
2652 soft = (type === "soft"),
2654 a, b, c, d, cur, i, j, l, p, cnt, tmp;
2655 if (soft && prepend) {
2656 values = [prepend].concat(values);
2658 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
2659 for (p in values[0]) {
2668 for (j = 0; j < l; j++) {
2669 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);
2670 if (soft) if (j > 1) if (j < l - 1) {
2671 cur[cnt++] = (a + cur[cnt-2]) / 2;
2677 for (j = 0; j < l; j += inc) {
2681 d = (inc === 2) ? 0 : cur[j+3];
2682 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2688 _addCubicLengths = function(a, steps, resolution) {
2689 var inc = 1 / resolution,
2691 d, d1, s, da, ca, ba, p, i, inv, bez, index;
2699 for (i = 1; i <= resolution; i++) {
2702 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
2703 index = j * resolution + i - 1;
2704 steps[index] = (steps[index] || 0) + d * d;
2708 _parseLengthData = function(obj, resolution) {
2709 resolution = resolution >> 0 || 6;
2714 threshold = resolution - 1,
2716 curLS = [], //current length segments array
2719 _addCubicLengths(obj[p], a, resolution);
2722 for (i = 0; i < l; i++) {
2723 d += Math.sqrt(a[i]);
2724 index = i % resolution;
2726 if (index === threshold) {
2728 index = (i / resolution) >> 0;
2729 segments[index] = curLS;
2730 lengths[index] = total;
2735 return {length:total, lengths:lengths, segments:segments};
2740 BezierPlugin = window._gsDefine.plugin({
2747 //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
2748 init: function(target, vars, tween) {
2749 this._target = target;
2750 if (vars instanceof Array) {
2751 vars = {values:vars};
2756 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
2757 var values = vars.values || [],
2760 autoRotate = vars.autoRotate || tween.vars.orientToBezier,
2761 p, isFunc, i, j, prepend;
2763 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
2765 this._props.push(p);
2768 i = this._props.length;
2772 this._overwriteProps.push(p);
2773 isFunc = this._func[p] = (typeof(target[p]) === "function");
2774 first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
2775 if (!prepend) if (first[p] !== values[0][p]) {
2779 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);
2780 this._segCount = this._beziers[p].length;
2782 if (this._timeRes) {
2783 var ld = _parseLengthData(this._beziers, this._timeRes);
2784 this._length = ld.length;
2785 this._lengths = ld.lengths;
2786 this._segments = ld.segments;
2787 this._l1 = this._li = this._s1 = this._si = 0;
2788 this._l2 = this._lengths[0];
2789 this._curSeg = this._segments[0];
2790 this._s2 = this._curSeg[0];
2791 this._prec = 1 / this._curSeg.length;
2794 if ((autoRotate = this._autoRotate)) {
2795 this._initialRotations = [];
2796 if (!(autoRotate[0] instanceof Array)) {
2797 this._autoRotate = autoRotate = [autoRotate];
2799 i = autoRotate.length;
2801 for (j = 0; j < 3; j++) {
2802 p = autoRotate[i][j];
2803 this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
2805 p = autoRotate[i][2];
2806 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p];
2809 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.
2813 //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.)
2815 var segments = this._segCount,
2817 target = this._target,
2818 notStart = (v !== this._startRatio),
2819 curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
2820 if (!this._timeRes) {
2821 curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
2822 t = (v - (curIndex * (1 / segments))) * segments;
2824 lengths = this._lengths;
2825 curSeg = this._curSeg;
2828 //find the appropriate segment (if the currently cached one isn't correct)
2829 if (v > this._l2 && i < segments - 1) {
2831 while (i < l && (this._l2 = lengths[++i]) <= v) { }
2832 this._l1 = lengths[i-1];
2834 this._curSeg = curSeg = this._segments[i];
2835 this._s2 = curSeg[(this._s1 = this._si = 0)];
2836 } else if (v < this._l1 && i > 0) {
2837 while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
2838 if (i === 0 && v < this._l1) {
2843 this._l2 = lengths[i];
2845 this._curSeg = curSeg = this._segments[i];
2846 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
2847 this._s2 = curSeg[this._si];
2850 //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
2853 if (v > this._s2 && i < curSeg.length - 1) {
2854 l = curSeg.length - 1;
2855 while (i < l && (this._s2 = curSeg[++i]) <= v) { }
2856 this._s1 = curSeg[i-1];
2858 } else if (v < this._s1 && i > 0) {
2859 while (i > 0 && (this._s1 = curSeg[--i]) >= v) { }
2860 if (i === 0 && v < this._s1) {
2865 this._s2 = curSeg[i];
2868 t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
2872 i = this._props.length;
2875 b = this._beziers[p][curIndex];
2876 val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
2877 if (this._round[p]) {
2878 val = Math.round(val);
2887 if (this._autoRotate) {
2888 var ar = this._autoRotate,
2889 b2, x1, y1, x2, y2, add, conv;
2893 add = ar[i][3] || 0;
2894 conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
2895 b = this._beziers[ar[i][0]];
2896 b2 = this._beziers[ar[i][1]];
2898 if (b && b2) { //in case one of the properties got overwritten.
2902 x1 = b.a + (b.b - b.a) * t;
2903 x2 = b.b + (b.c - b.b) * t;
2904 x1 += (x2 - x1) * t;
2905 x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
2907 y1 = b2.a + (b2.b - b2.a) * t;
2908 y2 = b2.b + (b2.c - b2.b) * t;
2909 y1 += (y2 - y1) * t;
2910 y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
2912 val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i];
2924 p = BezierPlugin.prototype;
2927 BezierPlugin.bezierThrough = bezierThrough;
2928 BezierPlugin.cubicToQuadratic = cubicToQuadratic;
2929 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
2930 BezierPlugin.quadraticToCubic = function(a, b, c) {
2931 return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
2934 BezierPlugin._cssRegister = function() {
2935 var CSSPlugin = window._gsDefine.globals.CSSPlugin;
2939 var _internals = CSSPlugin._internals,
2940 _parseToProxy = _internals._parseToProxy,
2941 _setPluginRatio = _internals._setPluginRatio,
2942 CSSPropTween = _internals.CSSPropTween;
2943 _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
2944 if (e instanceof Array) {
2947 plugin = new BezierPlugin();
2948 var values = e.values,
2949 l = values.length - 1,
2956 for (i = 0; i <= l; i++) {
2957 data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
2958 pluginValues[i] = data.end;
2961 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.
2963 v.values = pluginValues;
2964 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
2967 pt.setRatio = _setPluginRatio;
2968 if (v.autoRotate === 0) {
2969 v.autoRotate = true;
2971 if (v.autoRotate && !(v.autoRotate instanceof Array)) {
2972 i = (v.autoRotate === true) ? 0 : Number(v.autoRotate);
2973 v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false;
2976 if (!cssp._transform) {
2977 cssp._enableTransforms(false);
2979 data.autoRotate = cssp._target._gsTransform;
2981 plugin._onInitTween(data.proxy, v, cssp._tween);
2986 p._roundProps = function(lookup, value) {
2987 var op = this._overwriteProps,
2990 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
2991 this._round[op[i]] = value;
2996 p._kill = function(lookup) {
2997 var a = this._props,
2999 for (p in this._beziers) {
3001 delete this._beziers[p];
3002 delete this._func[p];
3011 return this._super._kill.call(this, lookup);
3030 * ----------------------------------------------------------------
3032 * ----------------------------------------------------------------
3034 window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
3036 /** @constructor **/
3037 var CSSPlugin = function() {
3038 TweenPlugin.call(this, "css");
3039 this._overwriteProps.length = 0;
3040 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
3042 _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.
3043 _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
3044 _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
3045 _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.
3047 p = CSSPlugin.prototype = new TweenPlugin("css");
3049 p.constructor = CSSPlugin;
3050 CSSPlugin.version = "1.12.1";
3052 CSSPlugin.defaultTransformPerspective = 0;
3053 CSSPlugin.defaultSkewType = "compensated";
3054 p = "px"; //we'll reuse the "p" variable to keep file size down
3055 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
3058 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
3059 _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
3060 _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)"
3061 _NaNExp = /[^\d\-\.]/g,
3062 _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
3063 _opacityExp = /opacity *= *([^)]*)/i,
3064 _opacityValExp = /opacity:([^;]*)/i,
3065 _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
3066 _rgbhslExp = /^(rgb|hsl)/,
3067 _capsExp = /([A-Z])/g,
3068 _camelExp = /-([a-z])/gi,
3069 _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)
3070 _camelFunc = function(s, g) { return g.toUpperCase(); },
3071 _horizExp = /(?:Left|Right|Width)/i,
3072 _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
3073 _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
3074 _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
3075 _DEG2RAD = Math.PI / 180,
3076 _RAD2DEG = 180 / Math.PI,
3079 _tempDiv = _doc.createElement("div"),
3080 _tempImg = _doc.createElement("img"),
3081 _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
3082 _agent = navigator.userAgent,
3084 _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).
3087 _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
3088 _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!)
3090 _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
3091 var i = _agent.indexOf("Android"),
3092 d = _doc.createElement("div"), a;
3094 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
3095 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
3096 _isFirefox = (_agent.indexOf("Firefox") !== -1);
3098 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
3099 _ieVers = parseFloat( RegExp.$1 );
3102 d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>";
3103 a = d.getElementsByTagName("a")[0];
3104 return a ? /^0.55/.test(a.style.opacity) : false;
3106 _getIEOpacity = function(v) {
3107 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
3109 _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
3110 if (window.console) {
3114 _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
3115 _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
3117 // @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)
3118 _checkPropPrefix = function(p, e) {
3122 if (s[p] !== undefined) {
3125 p = p.charAt(0).toUpperCase() + p.substr(1);
3126 a = ["O","Moz","ms","Ms","Webkit"];
3128 while (--i > -1 && s[a[i]+p] === undefined) { }
3130 _prefix = (i === 3) ? "ms" : a[i];
3131 _prefixCSS = "-" + _prefix.toLowerCase() + "-";
3137 _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
3140 * @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:
3141 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
3143 * @param {!Object} t Target element whose style property you want to query
3144 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
3145 * @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.
3146 * @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.
3147 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
3148 * @return {?string} The current property value
3150 _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
3152 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.
3153 return _getIEOpacity(t);
3155 if (!calc && t.style[p]) {
3157 } else if ((cs = cs || _getComputedStyle(t))) {
3158 rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
3159 } else if (t.currentStyle) {
3160 rv = t.currentStyle[p];
3162 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
3166 * @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.
3167 * @param {!Object} t Target element
3168 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
3169 * @param {!number} v Value
3170 * @param {string=} sfx Suffix (like "px" or "%" or "em")
3171 * @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.
3172 * @return {number} value in pixels
3174 _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
3175 if (sfx === "px" || !sfx) { return v; }
3176 if (sfx === "auto" || !v) { return 0; }
3177 var horiz = _horizExp.test(p),
3179 style = _tempDiv.style,
3185 if (sfx === "%" && p.indexOf("border") !== -1) {
3186 pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
3188 style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
3189 if (sfx === "%" || !node.appendChild) {
3190 node = t.parentNode || _doc.body;
3191 cache = node._gsCache;
3192 time = TweenLite.ticker.frame;
3193 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)
3194 return cache.width * v / 100;
3196 style[(horiz ? "width" : "height")] = v + sfx;
3198 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
3200 node.appendChild(_tempDiv);
3201 pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
3202 node.removeChild(_tempDiv);
3203 if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
3204 cache = node._gsCache = node._gsCache || {};
3206 cache.width = pix / v * 100;
3208 if (pix === 0 && !recurse) {
3209 pix = _convertToPixels(t, p, v, sfx, true);
3212 return neg ? -pix : pix;
3214 _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
3215 if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
3216 var dim = ((p === "left") ? "Left" : "Top"),
3217 v = _getStyle(t, "margin" + dim, cs);
3218 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
3221 // @private returns at object containing ALL of the style properties in camelCase and their associated values.
3222 _getAllStyles = function(t, cs) {
3225 if ((cs = cs || _getComputedStyle(t, null))) {
3226 if ((i = cs.length)) {
3228 s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
3230 } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
3235 } else if ((cs = t.currentStyle || t.style)) {
3237 if (typeof(i) === "string" && s[i] === undefined) {
3238 s[i.replace(_camelExp, _camelFunc)] = cs[i];
3242 if (!_supportsOpacity) {
3243 s.opacity = _getIEOpacity(t);
3245 tr = _getTransform(t, cs, false);
3246 s.rotation = tr.rotation;
3248 s.scaleX = tr.scaleX;
3249 s.scaleY = tr.scaleY;
3254 s.rotationX = tr.rotationX;
3255 s.rotationY = tr.rotationY;
3256 s.scaleZ = tr.scaleZ;
3264 // @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.
3265 _cssDif = function(t, s1, s2, vars, forceLookup) {
3270 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") {
3271 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.
3272 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.
3273 mpt = new MiniPropTween(style, p, style[p], mpt);
3278 for (p in vars) { //copy properties (except className)
3279 if (p !== "className") {
3284 return {difs:difs, firstMPT:mpt};
3286 _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
3287 _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
3290 * @private Gets the width or height of an element
3291 * @param {!Object} t Target element
3292 * @param {!string} p Property name ("width" or "height")
3293 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
3294 * @return {number} Dimension (in pixels)
3296 _getDimension = function(t, p, cs) {
3297 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
3300 cs = cs || _getComputedStyle(t, null);
3302 v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
3303 v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
3308 // @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)
3309 _parsePosition = function(v, recObj) {
3310 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
3313 var a = v.split(" "),
3314 x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
3315 y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
3318 } else if (y === "center") {
3321 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.
3325 recObj.oxp = (x.indexOf("%") !== -1);
3326 recObj.oyp = (y.indexOf("%") !== -1);
3327 recObj.oxr = (x.charAt(1) === "=");
3328 recObj.oyr = (y.charAt(1) === "=");
3329 recObj.ox = parseFloat(x.replace(_NaNExp, ""));
3330 recObj.oy = parseFloat(y.replace(_NaNExp, ""));
3332 return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
3336 * @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!)
3337 * @param {(number|string)} e End value which is typically a string, but could be a number
3338 * @param {(number|string)} b Beginning value which is typically a string but could be a number
3339 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
3341 _parseChange = function(e, b) {
3342 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
3346 * @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.
3347 * @param {Object} v Value to be parsed
3348 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
3349 * @return {number} Parsed value
3351 _parseVal = function(v, d) {
3352 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
3356 * @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.
3357 * @param {Object} v Value to be parsed
3358 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
3359 * @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"
3360 * @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.
3361 * @return {number} parsed angle in radians
3363 _parseAngle = function(v, d, p, directionalEnd) {
3365 cap, split, dif, result;
3368 } else if (typeof(v) === "number") {
3372 split = v.split("_");
3373 dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d);
3375 if (directionalEnd) {
3376 directionalEnd[p] = d + dif;
3378 if (v.indexOf("short") !== -1) {
3380 if (dif !== dif % (cap / 2)) {
3381 dif = (dif < 0) ? dif + cap : dif - cap;
3384 if (v.indexOf("_cw") !== -1 && dif < 0) {
3385 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
3386 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
3387 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
3392 if (result < min && result > -min) {
3398 _colorLookup = {aqua:[0,255,255],
3400 silver:[192,192,192],
3406 white:[255,255,255],
3407 fuchsia:[255,0,255],
3417 transparent:[255,255,255,0]},
3419 _hue = function(h, m1, m2) {
3420 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
3421 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;
3425 * @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)
3426 * @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.
3427 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
3429 _parseColor = function(v) {
3430 var c1, c2, c3, h, s, l;
3431 if (!v || v === "") {
3432 return _colorLookup.black;
3434 if (typeof(v) === "number") {
3435 return [v >> 16, (v >> 8) & 255, v & 255];
3437 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.
3438 v = v.substr(0, v.length - 1);
3440 if (_colorLookup[v]) {
3441 return _colorLookup[v];
3443 if (v.charAt(0) === "#") {
3444 if (v.length === 4) { //for shorthand like #9F0
3448 v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
3450 v = parseInt(v.substr(1), 16);
3451 return [v >> 16, (v >> 8) & 255, v & 255];
3453 if (v.substr(0, 3) === "hsl") {
3454 v = v.match(_numExp);
3455 h = (Number(v[0]) % 360) / 360;
3456 s = Number(v[1]) / 100;
3457 l = Number(v[2]) / 100;
3458 c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
3461 v[3] = Number(v[3]);
3463 v[0] = _hue(h + 1 / 3, c1, c2);
3464 v[1] = _hue(h, c1, c2);
3465 v[2] = _hue(h - 1 / 3, c1, c2);
3468 v = v.match(_numExp) || _colorLookup.transparent;
3469 v[0] = Number(v[0]);
3470 v[1] = Number(v[1]);
3471 v[2] = Number(v[2]);
3473 v[3] = Number(v[3]);
3477 _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.
3479 for (p in _colorLookup) {
3480 _colorExp += "|" + p + "\\b";
3482 _colorExp = new RegExp(_colorExp+")", "gi");
3485 * @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.
3486 * @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.
3487 * @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.
3488 * @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.
3489 * @return {Function} formatter function
3491 var _getFormatter = function(dflt, clr, collapsible, multi) {
3493 return function(v) {return v;};
3495 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
3496 dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
3497 pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
3498 sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
3499 delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
3500 numVals = dVals.length,
3501 dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
3504 return function(v) {return v;};
3507 formatter = function(v) {
3508 var color, vals, i, a;
3509 if (typeof(v) === "number") {
3511 } else if (multi && _commasOutsideParenExp.test(v)) {
3512 a = v.replace(_commasOutsideParenExp, "|").split("|");
3513 for (i = 0; i < a.length; i++) {
3514 a[i] = formatter(a[i]);
3518 color = (v.match(_colorExp) || [dColor])[0];
3519 vals = v.split(color).join("").match(_valuesExp) || [];
3521 if (numVals > i--) {
3522 while (++i < numVals) {
3523 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
3526 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
3531 formatter = function(v) {
3533 if (typeof(v) === "number") {
3535 } else if (multi && _commasOutsideParenExp.test(v)) {
3536 a = v.replace(_commasOutsideParenExp, "|").split("|");
3537 for (i = 0; i < a.length; i++) {
3538 a[i] = formatter(a[i]);
3542 vals = v.match(_valuesExp) || [];
3544 if (numVals > i--) {
3545 while (++i < numVals) {
3546 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
3549 return pfx + vals.join(delim) + sfx;
3555 * @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.
3556 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
3557 * @return {Function} a formatter function
3559 _getEdgeParser = function(props) {
3560 props = props.split(",");
3561 return function(t, e, p, cssp, pt, plugin, vars) {
3562 var a = (e + "").split(" "),
3565 for (i = 0; i < 4; i++) {
3566 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
3568 return cssp.parse(t, vars, pt, plugin);
3572 // @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.
3573 _setPluginRatio = _internals._setPluginRatio = function(v) {
3574 this.plugin.setRatio(v);
3583 val = Math.round(val);
3584 } else if (val < min && val > -min) {
3591 d.autoRotate.rotation = proxy.rotation;
3593 //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.
3599 pt.e = pt.s + pt.xs0;
3600 } else if (pt.type === 1) {
3601 str = pt.xs0 + pt.s + pt.xs1;
3602 for (i = 1; i < pt.l; i++) {
3603 str += pt["xn"+i] + pt["xs"+(i+1)];
3613 * @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.
3614 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
3615 * @param {!string} p property name
3616 * @param {(number|string|object)} v value
3617 * @param {MiniPropTween=} next next MiniPropTween in the linked list
3618 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
3620 MiniPropTween = function(t, p, v, next, r) {
3632 * @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.
3633 * This method returns an object that has the following properties:
3634 * - 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
3635 * - 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
3636 * - firstMPT: the first MiniPropTween in the linked list
3637 * - 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.
3638 * @param {!Object} t target object to be tweened
3639 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
3640 * @param {!CSSPlugin} cssp The CSSPlugin instance
3641 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
3642 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
3643 * @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.
3644 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
3646 _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
3650 transform = cssp._transform,
3651 oldForce = _forcePT,
3652 i, p, xp, mpt, firstPT;
3653 cssp._transform = null;
3655 pt = firstPT = cssp.parse(t, vars, pt, plugin);
3656 _forcePT = oldForce;
3657 //break off from the linked list so the new ones are isolated.
3659 cssp._transform = transform;
3663 bpt._prev._next = null;
3667 while (pt && pt !== bpt) {
3670 end[p] = pt.s + pt.c;
3673 mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
3676 if (pt.type === 1) {
3680 p = pt.p + "_" + xp;
3681 end[p] = pt.data[xp];
3684 mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
3691 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
3697 * @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.
3698 * CSSPropTweens have the following optional properties as well (not defined through the constructor):
3699 * - 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.
3700 * - 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)
3701 * - 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.
3702 * - 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.
3703 * - 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.
3704 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
3705 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
3706 * @param {number} s Starting numeric value
3707 * @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.
3708 * @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.
3709 * @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.
3710 * @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"
3711 * @param {boolean=} r If true, the value(s) should be rounded
3712 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
3713 * @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.
3714 * @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.
3716 CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
3717 this.t = t; //target
3718 this.p = p; //property
3719 this.s = s; //starting value
3720 this.c = c; //change value
3721 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)
3722 if (!(t instanceof CSSPropTween)) {
3723 _overwriteProps.push(this.n);
3725 this.r = r; //round (boolean)
3726 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
3729 _hasPriority = true;
3731 this.b = (b === undefined) ? s : b;
3732 this.e = (e === undefined) ? s + c : e;
3740 * 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:
3741 * 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);
3742 * 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().
3743 * 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.
3745 * @param {!Object} t Target whose property will be tweened
3746 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
3747 * @param {string} b Beginning value
3748 * @param {string} e Ending value
3749 * @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)
3750 * @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
3751 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
3752 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
3753 * @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}
3754 * @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.
3755 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
3757 _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
3758 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
3759 b = b || dflt || "";
3760 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
3761 e += ""; //ensures it's a string
3762 var ba = b.split(", ").join(",").split(" "), //beginning array
3763 ea = e.split(", ").join(",").split(" "), //ending array
3765 autoRound = (_autoRound !== false),
3766 i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
3767 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
3768 ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3769 ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
3772 if (l !== ea.length) {
3773 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3774 ba = (dflt || "").split(" ");
3778 pt.setRatio = setRatio;
3779 for (i = 0; i < l; i++) {
3782 bn = parseFloat(bv);
3784 //if the value begins with a number (most common). It's fine if it has a suffix like px
3785 if (bn || bn === 0) {
3786 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
3788 //if the value is a color
3789 } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
3790 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
3791 bv = _parseColor(bv);
3792 ev = _parseColor(ev);
3793 rgba = (bv.length + ev.length > 6);
3794 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
3795 pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
3796 pt.e = pt.e.split(ea[i]).join("transparent");
3798 if (!_supportsOpacity) { //old versions of IE don't support rgba().
3801 pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
3802 .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
3803 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
3805 bv = (bv.length < 4) ? 1 : bv[3];
3806 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
3811 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
3813 //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
3815 pt["xs" + pt.l] += pt.l ? " " + bv : bv;
3817 //loop through all the numbers that are found and construct the extra values on the pt.
3819 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
3820 if (!enums || enums.length !== bnums.length) {
3821 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
3825 for (xi = 0; xi < bnums.length; xi++) {
3827 temp = bv.indexOf(cv, ni);
3828 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
3829 ni = temp + cv.length;
3831 pt["xs" + pt.l] += bv.substr(ni);
3835 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
3836 if (e.indexOf("=") !== -1) if (pt.data) {
3837 str = pt.xs0 + pt.data.s;
3838 for (i = 1; i < pt.l; i++) {
3839 str += pt["xs" + i] + pt.data["xn" + i];
3841 pt.e = str + pt["xs" + i];
3847 return pt.xfirst || pt;
3852 p = CSSPropTween.prototype;
3853 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
3859 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
3863 * 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:
3864 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
3865 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
3866 * @param {string=} pfx Prefix (if any)
3867 * @param {!number} s Starting value
3868 * @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.
3869 * @param {string=} sfx Suffix (if any)
3870 * @param {boolean=} r Round (if true).
3871 * @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.
3872 * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
3874 p.appendXtra = function(pfx, s, c, sfx, r, pad) {
3877 pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
3878 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!
3879 pt["xs" + l] += s + (sfx || "");
3883 pt.type = pt.setRatio ? 2 : 1;
3884 pt["xs" + pt.l] = sfx || "";
3886 pt.data["xn" + l] = s + c;
3887 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
3890 pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
3891 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.
3895 pt.data = {s:s + c};
3904 * @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.
3905 * @param {!string} p Property name (like "boxShadow" or "throwProps")
3906 * @param {Object=} options An object containing any of the following configuration options:
3907 * - defaultValue: the default value
3908 * - 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)
3909 * - 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.)
3910 * - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
3911 * - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
3912 * - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
3913 * - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
3914 * - 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.
3915 * - 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).
3917 var SpecialProp = function(p, options) {
3918 options = options || {};
3919 this.p = options.prefix ? _checkPropPrefix(p) || p : p;
3920 _specialProps[p] = _specialProps[this.p] = this;
3921 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
3922 if (options.parser) {
3923 this.parse = options.parser;
3925 this.clrs = options.color;
3926 this.multi = options.multi;
3927 this.keyword = options.keyword;
3928 this.dflt = options.defaultValue;
3929 this.pr = options.priority || 0;
3932 //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.
3933 _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
3934 if (typeof(options) !== "object") {
3935 options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
3937 var a = p.split(","),
3938 d = options.defaultValue,
3940 defaults = defaults || [d];
3941 for (i = 0; i < a.length; i++) {
3942 options.prefix = (i === 0 && options.prefix);
3943 options.defaultValue = defaults[i] || d;
3944 temp = new SpecialProp(a[i], options);
3948 //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.
3949 _registerPluginProp = function(p) {
3950 if (!_specialProps[p]) {
3951 var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
3952 _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
3953 var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
3955 _log("Error: " + pluginName + " js file not loaded.");
3958 pluginClass._cssRegister();
3959 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
3965 p = SpecialProp.prototype;
3968 * 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)
3969 * @param {!Object} t target element
3970 * @param {(string|number|object)} b beginning value
3971 * @param {(string|number|object)} e ending (destination) value
3972 * @param {CSSPropTween=} pt next CSSPropTween in the linked list
3973 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
3974 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
3975 * @return {CSSPropTween=} First CSSPropTween in the linked list
3977 p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
3978 var kwd = this.keyword,
3979 i, ba, ea, l, bi, ei;
3980 //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)
3981 if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
3982 ba = b.replace(_commasOutsideParenExp, "|").split("|");
3983 ea = e.replace(_commasOutsideParenExp, "|").split("|");
3989 l = (ea.length > ba.length) ? ea.length : ba.length;
3990 for (i = 0; i < l; i++) {
3991 b = ba[i] = ba[i] || this.dflt;
3992 e = ea[i] = ea[i] || this.dflt;
3994 bi = b.indexOf(kwd);
3995 ei = e.indexOf(kwd);
3997 e = (ei === -1) ? ea : ba;
4005 return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
4009 * 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:
4010 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
4011 * 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).
4012 * @param {!Object} t Target object whose property is being tweened
4013 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
4014 * @param {!string} p Property name
4015 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
4016 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
4017 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
4018 * @param {Object=} vars Original vars object that contains the data for parsing.
4019 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
4021 p.parse = function(t, e, p, cssp, pt, plugin, vars) {
4022 return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
4026 * 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:
4027 * 1) Target object whose property should be tweened (typically a DOM element)
4028 * 2) The end/destination value (could be a string, number, object, or whatever you want)
4029 * 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)
4031 * 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:
4033 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
4034 * var start = target.style.width;
4035 * return function(ratio) {
4036 * target.style.width = (start + value * ratio) + "px";
4037 * console.log("set width to " + target.style.width);
4041 * Then, when I do this tween, it will trigger my special property:
4043 * TweenLite.to(element, 1, {css:{myCustomProp:100}});
4045 * In the example, of course, we're just changing the width, but you can do anything you want.
4047 * @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}})
4048 * @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.
4049 * @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.
4051 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
4052 _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
4053 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
4055 rv.setRatio = onInitTween(t, e, cssp._tween, p);
4057 }, priority:priority});
4067 //transform-related methods and properties
4068 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective").split(","),
4069 _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
4070 _transformPropCSS = _prefixCSS + "transform",
4071 _transformOriginProp = _checkPropPrefix("transformOrigin"),
4072 _supports3D = (_checkPropPrefix("perspective") !== null),
4073 Transform = _internals.Transform = function() {
4078 * 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.
4079 * @param {!Object} t target element
4080 * @param {Object=} cs computed style object (optional)
4081 * @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...}
4082 * @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)
4083 * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
4085 _getTransform = _internals.getTransform = function(t, cs, rec, parse) {
4086 if (t._gsTransform && rec && !parse) {
4087 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.
4089 var tm = rec ? t._gsTransform || new Transform() : new Transform(),
4090 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.
4094 minPI = minAngle * _DEG2RAD,
4095 zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0,
4096 s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
4097 if (_transformProp) {
4098 s = _getStyle(t, _transformPropCSS, cs, true);
4099 } else if (t.currentStyle) {
4100 //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.
4101 s = t.currentStyle.filter.match(_ieGetMatrixExp);
4102 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(",") : "";
4104 //split the matrix values out into an array (m for matrix)
4105 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
4109 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).
4111 if (m.length === 16) {
4113 //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)
4114 var a13 = m[8], a23 = m[9], a33 = m[10],
4115 a14 = m[12], a24 = m[13], a34 = m[14];
4117 //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
4120 a14 = a13*a34-m[12];
4121 a24 = a23*a34-m[13];
4122 a34 = a33*a34+tm.zOrigin-m[14];
4125 //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.
4126 if (!rec || parse || tm.rotationX == null) {
4127 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
4128 a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
4130 angle = Math.atan2(a32, a33),
4131 xFlip = (angle < -minPI || angle > minPI),
4132 t1, t2, t3, cos, sin, yFlip, zFlip;
4133 tm.rotationX = angle * _RAD2DEG;
4136 cos = Math.cos(-angle);
4137 sin = Math.sin(-angle);
4138 t1 = a12*cos+a13*sin;
4139 t2 = a22*cos+a23*sin;
4140 t3 = a32*cos+a33*sin;
4141 a13 = a12*-sin+a13*cos;
4142 a23 = a22*-sin+a23*cos;
4143 a33 = a32*-sin+a33*cos;
4144 a43 = a42*-sin+a43*cos;
4150 angle = Math.atan2(a13, a11);
4151 tm.rotationY = angle * _RAD2DEG;
4153 yFlip = (angle < -minPI || angle > minPI);
4154 cos = Math.cos(-angle);
4155 sin = Math.sin(-angle);
4156 t1 = a11*cos-a13*sin;
4157 t2 = a21*cos-a23*sin;
4158 t3 = a31*cos-a33*sin;
4159 a23 = a21*sin+a23*cos;
4160 a33 = a31*sin+a33*cos;
4161 a43 = a41*sin+a43*cos;
4167 angle = Math.atan2(a21, a22);
4168 tm.rotation = angle * _RAD2DEG;
4170 zFlip = (angle < -minPI || angle > minPI);
4171 cos = Math.cos(-angle);
4172 sin = Math.sin(-angle);
4173 a11 = a11*cos+a12*sin;
4174 t2 = a21*cos+a22*sin;
4175 a22 = a21*-sin+a22*cos;
4176 a32 = a31*-sin+a32*cos;
4180 if (zFlip && xFlip) {
4181 tm.rotation = tm.rotationX = 0;
4182 } else if (zFlip && yFlip) {
4183 tm.rotation = tm.rotationY = 0;
4184 } else if (yFlip && xFlip) {
4185 tm.rotationY = tm.rotationX = 0;
4188 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
4189 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
4190 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
4192 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
4198 } 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.
4199 var k = (m.length >= 6),
4206 scaleX = Math.sqrt(a * a + b * b);
4207 scaleY = Math.sqrt(d * d + c * c);
4208 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).
4209 skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
4210 difX = scaleX - Math.abs(tm.scaleX || 0);
4211 difY = scaleY - Math.abs(tm.scaleY || 0);
4212 if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
4215 skewX += (rotation <= 0) ? 180 : -180;
4216 rotation += (rotation <= 0) ? 180 : -180;
4219 skewX += (skewX <= 0) ? 180 : -180;
4222 difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180.
4223 difS = (skewX - tm.skewX) % 180;
4224 //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.
4225 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)) {
4228 tm.rotation = rotation;
4232 tm.rotationX = tm.rotationY = tm.z = 0;
4233 tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
4237 tm.zOrigin = zOrigin;
4239 //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.
4241 if (tm[i] < min) if (tm[i] > -min) {
4245 //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);
4247 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)
4252 //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
4253 _setIETransformRatio = function(v) {
4254 var t = this.data, //refers to the element's _gsTransform object
4255 ang = -t.rotation * _DEG2RAD,
4256 skew = ang + t.skewX * _DEG2RAD,
4258 a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
4259 b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
4260 c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
4261 d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
4262 style = this.t.style,
4263 cs = this.t.currentStyle,
4268 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)
4271 filters = cs.filter;
4272 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
4273 var w = this.t.offsetWidth,
4274 h = this.t.offsetHeight,
4275 clip = (cs.position !== "absolute"),
4276 m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
4281 //if transformOrigin is being used, adjust the offset x and y
4283 dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
4284 dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
4285 ox += dx - (dx * a + dy * b);
4286 oy += dy - (dx * c + dy * d);
4290 m += ", sizingMethod='auto expand')";
4294 //translate to ensure that transformations occur around the correct origin (default is center).
4295 m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
4297 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
4298 style.filter = filters.replace(_ieSetMatrixExp, m);
4300 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.
4303 //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.
4304 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) {
4305 style.removeAttribute("filter");
4308 //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).
4310 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
4312 dx = t.ieOffsetX || 0;
4313 dy = t.ieOffsetY || 0;
4314 t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
4315 t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
4316 for (i = 0; i < 4; i++) {
4319 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
4320 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
4321 if (val !== t[prop]) {
4322 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.
4324 dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
4326 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
4331 _set3DTransformRatio = _internals.set3DTransformRatio = function(v) {
4332 var t = this.data, //refers to the element's _gsTransform object
4333 style = this.t.style,
4334 angle = t.rotation * _DEG2RAD,
4338 perspective = t.perspective,
4339 a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43,
4340 zOrigin, rnd, cos, sin, t1, t2, t3, t4;
4341 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
4342 _set2DTransformRatio.call(this, v);
4347 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.
4350 if (sy < n && sy > -n) {
4353 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).
4357 if (angle || t.skewX) {
4358 cos = Math.cos(angle);
4359 sin = Math.sin(angle);
4363 angle -= t.skewX * _DEG2RAD;
4364 cos = Math.cos(angle);
4365 sin = Math.sin(angle);
4366 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
4367 t1 = Math.tan(t.skewX * _DEG2RAD);
4368 t1 = Math.sqrt(1 + t1 * t1);
4376 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective) { //if we're only translating and/or 2D scaling, this is faster...
4377 style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
4384 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0;
4385 a43 = (perspective) ? -1 / perspective : 0;
4386 zOrigin = t.zOrigin;
4388 angle = t.rotationY * _DEG2RAD;
4390 cos = Math.cos(angle);
4391 sin = Math.sin(angle);
4401 angle = t.rotationX * _DEG2RAD;
4403 cos = Math.cos(angle);
4404 sin = Math.sin(angle);
4405 t1 = a12*cos+a13*sin;
4406 t2 = a22*cos+a23*sin;
4407 t3 = a32*cos+a33*sin;
4408 t4 = a42*cos+a43*sin;
4409 a13 = a12*-sin+a13*cos;
4410 a23 = a22*-sin+a23*cos;
4411 a33 = a32*-sin+a33*cos;
4412 a43 = a42*-sin+a43*cos;
4440 a34 = a33*a34+zOrigin;
4442 //we round the x, y, and z slightly differently to allow even larger values.
4443 a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
4444 a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
4445 a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
4446 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(",") + ")";
4449 _set2DTransformRatio = _internals.set2DTransformRatio = function(v) {
4450 var t = this.data, //refers to the element's _gsTransform object
4453 ang, skew, rnd, sx, sy;
4454 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.
4455 this.setRatio = _set3DTransformRatio;
4456 _set3DTransformRatio.call(this, v);
4459 if (!t.rotation && !t.skewX) {
4460 style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
4462 ang = t.rotation * _DEG2RAD;
4463 skew = ang - t.skewX * _DEG2RAD;
4465 sx = t.scaleX * rnd;
4466 sy = t.scaleY * rnd;
4467 //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.
4468 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 + ")";
4472 _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) {
4473 if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
4474 var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
4477 i = _transformProps.length,
4480 m2, skewY, copy, orig, has3D, hasChange, dr;
4481 if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
4482 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.
4483 copy[_transformProp] = v.transform;
4484 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
4485 copy.position = "absolute";
4486 _doc.body.appendChild(_tempDiv);
4487 m2 = _getTransform(_tempDiv, null, false);
4488 _doc.body.removeChild(_tempDiv);
4489 } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
4490 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
4491 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
4492 scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
4493 x:_parseVal(v.x, m1.x),
4494 y:_parseVal(v.y, m1.y),
4495 z:_parseVal(v.z, m1.z),
4496 perspective:_parseVal(v.transformPerspective, m1.perspective)};
4497 dr = v.directionalRotation;
4499 if (typeof(dr) === "object") {
4507 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);
4509 m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
4510 m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
4512 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
4514 //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.
4515 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
4516 if ((skewY = m2.skewY - m1.skewY)) {
4518 m2.rotation += skewY;
4522 if (_supports3D && v.force3D != null) {
4523 m1.force3D = v.force3D;
4527 m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
4529 has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
4530 if (!has3D && v.scale != null) {
4531 m2.scaleZ = 1; //no need to tween scaleZ.
4535 p = _transformProps[i];
4536 orig = m2[p] - m1[p];
4537 if (orig > min || orig < -min || _forcePT[p] != null) {
4539 pt = new CSSPropTween(m1, p, m1[p], orig, pt);
4540 if (p in endRotations) {
4541 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
4543 pt.xs0 = 0; //ensures the value stays numeric in setRatio()
4545 cssp._overwriteProps.push(pt.n);
4549 orig = v.transformOrigin;
4550 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).
4551 if (_transformProp) {
4553 p = _transformOriginProp;
4554 orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
4555 pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
4560 orig = orig.split(" ");
4561 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.
4562 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)!
4563 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)
4565 pt.xs0 = pt.e = m1.zOrigin;
4567 pt.xs0 = pt.e = orig;
4570 //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).
4572 _parsePosition(orig + "", m1);
4577 cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
4582 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
4584 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
4586 var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
4588 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
4589 w = parseFloat(t.offsetWidth);
4590 h = parseFloat(t.offsetHeight);
4592 for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
4593 if (this.p.indexOf("border")) { //older browsers used a prefix
4594 props[i] = _checkPropPrefix(props[i]);
4596 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
4597 if (bs.indexOf(" ") !== -1) {
4598 bs2 = bs.split(" ");
4603 bn = parseFloat(bs);
4604 bsfx = bs.substr((bn + "").length);
4605 rel = (es.charAt(1) === "=");
4607 en = parseInt(es.charAt(0)+"1", 10);
4609 en *= parseFloat(es);
4610 esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
4612 en = parseFloat(es);
4613 esfx = es.substr((en + "").length);
4616 esfx = _suffixMap[p] || bsfx;
4618 if (esfx !== bsfx) {
4619 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.
4620 vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
4622 bs = (hn / w * 100) + "%";
4623 bs2 = (vn / h * 100) + "%";
4624 } else if (esfx === "em") {
4625 em = _convertToPixels(t, "borderLeft", 1, "em");
4626 bs = (hn / em) + "em";
4627 bs2 = (vn / em) + "em";
4633 es = (parseFloat(bs) + en) + esfx;
4634 es2 = (parseFloat(bs2) + en) + esfx;
4637 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
4640 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
4641 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
4642 var bp = "background-position",
4643 cs = (_cs || _getComputedStyle(t, null)),
4644 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
4645 es = this.format(e),
4646 ba, ea, i, pct, overlap, src;
4647 if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
4648 src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
4649 if (src && src !== "none") {
4652 _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
4656 pct = (bs.indexOf("%") !== -1);
4657 if (pct !== (ea[i].indexOf("%") !== -1)) {
4658 overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
4659 ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
4665 return this.parseComplex(t.style, bs, es, pt, plugin);
4666 }, formatter:_parsePosition});
4667 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
4668 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
4669 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
4670 _registerComplexSpecialProp("transformStyle", {prefix:true});
4671 _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
4672 _registerComplexSpecialProp("userSelect", {prefix:true});
4673 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
4674 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
4675 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
4677 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.
4678 cs = t.currentStyle;
4679 delim = _ieVers < 8 ? " " : ",";
4680 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
4681 e = this.format(e).split(",").join(delim);
4683 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
4686 return this.parseComplex(t.style, b, e, pt, plugin);
4688 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
4689 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
4690 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
4691 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);
4692 }, color:true, formatter:function(v) {
4693 var a = v.split(" ");
4694 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
4696 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
4697 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
4699 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
4700 return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
4704 var _setIEOpacityRatio = function(v) {
4705 var t = this.t, //refers to the element's style property
4706 filters = t.filter || _getStyle(this.data, "filter"),
4707 val = (this.s + this.c * v) | 0,
4709 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.
4710 if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
4711 t.removeAttribute("filter");
4712 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.
4714 t.filter = filters.replace(_alphaFilterExp, "");
4720 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.
4722 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
4723 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)
4724 t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
4727 t.filter = filters.replace(_opacityExp, "opacity=" + val);
4731 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
4732 var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
4734 isAutoAlpha = (p === "autoAlpha");
4735 if (typeof(e) === "string" && e.charAt(1) === "=") {
4736 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
4738 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)
4741 if (_supportsOpacity) {
4742 pt = new CSSPropTween(style, "opacity", b, e - b, pt);
4744 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
4745 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.
4746 style.zoom = 1; //helps correct an IE issue.
4748 pt.b = "alpha(opacity=" + pt.s + ")";
4749 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
4752 pt.setRatio = _setIEOpacityRatio;
4754 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
4755 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
4757 cssp._overwriteProps.push(pt.n);
4758 cssp._overwriteProps.push(p);
4764 var _removeProp = function(s, p) {
4766 if (s.removeProperty) {
4767 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)
4768 p = "M" + p.substr(1);
4770 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
4771 } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
4772 s.removeAttribute(p);
4776 _setClassNameRatio = function(v) {
4777 this.t._gsClassPT = this;
4778 if (v === 1 || v === 0) {
4779 this.t.setAttribute("class", (v === 0) ? this.b : this.e);
4780 var mpt = this.data, //first MiniPropTween
4784 _removeProp(s, mpt.p);
4790 if (v === 1 && this.t._gsClassPT === this) {
4791 this.t._gsClassPT = null;
4793 } else if (this.t.getAttribute("class") !== this.e) {
4794 this.t.setAttribute("class", this.e);
4797 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
4798 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.
4799 cssText = t.style.cssText,
4800 difData, bs, cnpt, cnptLookup, mpt;
4801 pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
4802 pt.setRatio = _setClassNameRatio;
4804 _hasPriority = true;
4806 bs = _getAllStyles(t, _cs);
4807 //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)
4808 cnpt = t._gsClassPT;
4811 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.
4813 cnptLookup[mpt.p] = 1;
4819 pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
4820 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.
4821 t.setAttribute("class", pt.e);
4822 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
4823 t.setAttribute("class", b);
4824 pt.data = difData.firstMPT;
4825 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).
4826 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)
4832 var _setClearPropsRatio = function(v) {
4833 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).
4834 var s = this.t.style,
4835 transformParse = _specialProps.transform.parse,
4836 a, p, i, clearTransform;
4837 if (this.e === "all") {
4839 clearTransform = true;
4841 a = this.e.split(",");
4845 if (_specialProps[p]) {
4846 if (_specialProps[p].parse === transformParse) {
4847 clearTransform = true;
4849 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"
4855 if (clearTransform) {
4856 _removeProp(s, _transformProp);
4857 if (this.t._gsTransform) {
4858 delete this.t._gsTransform;
4864 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
4865 pt = new CSSPropTween(t, p, 0, 0, pt, 2);
4866 pt.setRatio = _setClearPropsRatio;
4869 pt.data = cssp._tween;
4870 _hasPriority = true;
4874 p = "bezier,throwProps,physicsProps,physics2D".split(",");
4877 _registerPluginProp(p[i]);
4887 p = CSSPlugin.prototype;
4890 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
4891 p._onInitTween = function(target, vars, tween) {
4892 if (!target.nodeType) { //css is only for dom elements
4895 this._target = target;
4896 this._tween = tween;
4898 _autoRound = vars.autoRound;
4899 _hasPriority = false;
4900 _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
4901 _cs = _getComputedStyle(target, "");
4902 _overwriteProps = this._overwriteProps;
4903 var style = target.style,
4904 v, pt, pt2, first, last, next, zIndex, tpt, threeD;
4905 if (_reqSafariFix) if (style.zIndex === "") {
4906 v = _getStyle(target, "zIndex", _cs);
4907 if (v === "auto" || v === "") {
4908 //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.
4909 this._addLazySet(style, "zIndex", 0);
4913 if (typeof(vars) === "string") {
4914 first = style.cssText;
4915 v = _getAllStyles(target, _cs);
4916 style.cssText = first + ";" + vars;
4917 v = _cssDif(target, v, _getAllStyles(target)).difs;
4918 if (!_supportsOpacity && _opacityValExp.test(vars)) {
4919 v.opacity = parseFloat( RegExp.$1 );
4922 style.cssText = first;
4924 this._firstPT = pt = this.parse(target, vars, null);
4926 if (this._transformType) {
4927 threeD = (this._transformType === 3);
4928 if (!_transformProp) {
4929 style.zoom = 1; //helps correct an IE issue.
4930 } else if (_isSafari) {
4931 _reqSafariFix = true;
4932 //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
4933 if (style.zIndex === "") {
4934 zIndex = _getStyle(target, "zIndex", _cs);
4935 if (zIndex === "auto" || zIndex === "") {
4936 this._addLazySet(style, "zIndex", 0);
4939 //Setting WebkitBackfaceVisibility corrects 3 bugs:
4940 // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
4941 // 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.
4942 // 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.
4943 //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
4945 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
4949 while (pt2 && pt2._next) {
4952 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
4953 this._linkCSSP(tpt, null, pt2);
4954 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
4955 tpt.data = this._transform || _getTransform(target, _cs, true);
4956 _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.
4960 //reorders the linked list in order of pr (priority)
4964 while (pt2 && pt2.pr > pt.pr) {
4967 if ((pt._prev = pt2 ? pt2._prev : last)) {
4968 pt._prev._next = pt;
4972 if ((pt._next = pt2)) {
4979 this._firstPT = first;
4985 p.parse = function(target, vars, pt, plugin) {
4986 var style = target.style,
4987 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
4989 es = vars[p]; //ending value string
4990 sp = _specialProps[p]; //SpecialProp lookup.
4992 pt = sp.parse(target, es, p, this, pt, plugin, vars);
4995 bs = _getStyle(target, p, _cs) + "";
4996 isStr = (typeof(es) === "string");
4997 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:
4999 es = _parseColor(es);
5000 es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
5002 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
5004 } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
5005 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
5008 bn = parseFloat(bs);
5009 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.
5011 if (bs === "" || bs === "auto") {
5012 if (p === "width" || p === "height") {
5013 bn = _getDimension(target, p, _cs);
5015 } else if (p === "left" || p === "top") {
5016 bn = _calculateOffset(target, p, _cs);
5019 bn = (p !== "opacity") ? 0 : 1;
5024 rel = (isStr && es.charAt(1) === "=");
5026 en = parseInt(es.charAt(0) + "1", 10);
5028 en *= parseFloat(es);
5029 esfx = es.replace(_suffixExp, "");
5031 en = parseFloat(es);
5032 esfx = isStr ? es.substr((en + "").length) || "" : "";
5036 esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
5039 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.
5041 //if the beginning/ending suffixes don't match, normalize them...
5042 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!
5043 bn = _convertToPixels(target, p, bn, bsfx);
5045 bn /= _convertToPixels(target, p, 100, "%") / 100;
5046 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.
5050 } else if (esfx === "em") {
5051 bn /= _convertToPixels(target, p, 1, "em");
5053 //otherwise convert to pixels.
5054 } else if (esfx !== "px") {
5055 en = _convertToPixels(target, p, en, esfx);
5056 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
5058 if (rel) if (en || en === 0) {
5059 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
5067 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.
5068 pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
5070 //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
5071 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
5072 _log("invalid " + p + " tween value: " + vars[p]);
5074 pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
5075 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.
5076 //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
5080 if (plugin) if (pt && !pt.plugin) {
5088 //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.
5089 p.setRatio = function(v) {
5090 var pt = this._firstPT,
5094 //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).
5095 if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
5097 if (pt.type !== 2) {
5105 } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
5107 val = pt.c * v + pt.s;
5109 val = Math.round(val);
5110 } else if (val < min) if (val > -min) {
5114 pt.t[pt.p] = val + pt.xs0;
5115 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
5118 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
5119 } else if (i === 3) {
5120 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
5121 } else if (i === 4) {
5122 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
5123 } else if (i === 5) {
5124 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;
5126 str = pt.xs0 + val + pt.xs1;
5127 for (i = 1; i < pt.l; i++) {
5128 str += pt["xn"+i] + pt["xs"+(i+1)];
5133 } else if (pt.type === -1) { //non-tweening value
5134 pt.t[pt.p] = pt.xs0;
5136 } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
5142 //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).
5145 if (pt.type !== 2) {
5157 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
5158 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
5159 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
5160 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
5161 * doesn't have any transform-related properties of its own. You can call this method as many times as you
5162 * want and it won't create duplicate CSSPropTweens.
5164 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
5166 p._enableTransforms = function(threeD) {
5167 this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
5168 this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
5171 var lazySet = function(v) {
5172 this.t[this.p] = this.e;
5173 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.
5175 /** @private Gives us a way to set a value on the first render (and only the first render). **/
5176 p._addLazySet = function(t, p, v) {
5177 var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
5179 pt.setRatio = lazySet;
5184 p._linkCSSP = function(pt, next, prev, remove) {
5190 pt._next._prev = pt._prev;
5193 pt._prev._next = pt._next;
5194 } else if (this._firstPT === pt) {
5195 this._firstPT = pt._next;
5196 remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
5200 } else if (!remove && this._firstPT === null) {
5209 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
5210 p._kill = function(lookup) {
5213 if (lookup.autoAlpha || lookup.alpha) {
5215 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
5216 copy[p] = lookup[p];
5219 if (copy.autoAlpha) {
5220 copy.visibility = 1;
5223 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".
5225 if (xfirst && xfirst._prev) {
5226 this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
5227 } else if (xfirst === this._firstPT) {
5228 this._firstPT = pt._next;
5231 this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
5233 this._classNamePT = null;
5235 return TweenPlugin.prototype._kill.call(this, copy);
5240 //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
5241 var _getChildStyles = function(e, props, targets) {
5242 var children, i, child, type;
5246 _getChildStyles(e[i], props, targets);
5250 children = e.childNodes;
5251 i = children.length;
5253 child = children[i];
5256 props.push(_getAllStyles(child));
5258 targets.push(child);
5261 if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
5262 _getChildStyles(child, props, targets);
5268 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
5269 * and then compares the style properties of all the target's child elements at the tween's start and end, and
5270 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
5271 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
5272 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
5273 * is because it creates entirely new tweens that may have completely different targets than the original tween,
5274 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
5275 * and it would create other problems. For example:
5276 * - 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)
5277 * - 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.
5278 * - 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.
5280 * @param {Object} target object to be tweened
5281 * @param {number} Duration in seconds (or frames for frames-based tweens)
5282 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
5283 * @return {Array} An array of TweenLite instances
5285 CSSPlugin.cascadeTo = function(target, duration, vars) {
5286 var tween = TweenLite.to(target, duration, vars),
5291 _reservedProps = TweenLite._internals.reservedProps,
5293 target = tween._targets || tween.target;
5294 _getChildStyles(target, b, targets);
5295 tween.render(duration, true);
5296 _getChildStyles(target, e);
5297 tween.render(0, true);
5298 tween._enabled(true);
5301 difs = _cssDif(targets[i], b[i], e[i]);
5302 if (difs.firstMPT) {
5305 if (_reservedProps[p]) {
5309 results.push( TweenLite.to(targets[i], duration, difs) );
5315 TweenPlugin.activate([CSSPlugin]);
5331 * ----------------------------------------------------------------
5333 * ----------------------------------------------------------------
5337 var RoundPropsPlugin = window._gsDefine.plugin({
5338 propName: "roundProps",
5342 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
5343 init: function(target, value, tween) {
5344 this._tween = tween;
5349 p = RoundPropsPlugin.prototype;
5351 p._onInitAllProps = function() {
5352 var tween = this._tween,
5353 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
5356 rpt = tween._propLookup.roundProps,
5364 pt = tween._firstPT;
5366 next = pt._next; //record here, because it may get removed
5368 pt.t._roundProps(lookup, true);
5369 } else if (pt.n === prop) {
5370 this._add(pt.t, prop, pt.s, pt.c);
5371 //remove from linked list
5373 next._prev = pt._prev;
5376 pt._prev._next = next;
5377 } else if (tween._firstPT === pt) {
5378 tween._firstPT = next;
5380 pt._next = pt._prev = null;
5381 tween._propLookup[prop] = rpt;
5389 p._add = function(target, p, s, c) {
5390 this._addTween(target, p, s, s + c, p, true);
5391 this._overwriteProps.push(p);
5406 * ----------------------------------------------------------------
5408 * ----------------------------------------------------------------
5410 window._gsDefine.plugin({
5415 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
5416 init: function(target, value, tween) {
5418 if (typeof(target.setAttribute) !== "function") {
5421 this._target = target;
5423 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.
5426 this._start[p] = this._proxy[p] = start = target.getAttribute(p);
5427 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
5428 this._end[p] = end ? end.s + end.c : value[p];
5429 this._overwriteProps.push(p);
5434 //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.)
5435 set: function(ratio) {
5436 this._super.setRatio.call(this, ratio);
5437 var props = this._overwriteProps,
5439 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
5443 this._target.setAttribute(p, lookup[p] + "");
5459 * ----------------------------------------------------------------
5460 * DirectionalRotationPlugin
5461 * ----------------------------------------------------------------
5463 window._gsDefine.plugin({
5464 propName: "directionalRotation",
5468 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
5469 init: function(target, value, tween) {
5470 if (typeof(value) !== "object") {
5471 value = {rotation:value};
5474 var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
5476 p, v, start, end, dif, split;
5478 if (p !== "useRadians") {
5479 split = (value[p] + "").split("_");
5481 start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
5482 end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
5485 v = split.join("_");
5486 if (v.indexOf("short") !== -1) {
5488 if (dif !== dif % (cap / 2)) {
5489 dif = (dif < 0) ? dif + cap : dif - cap;
5492 if (v.indexOf("_cw") !== -1 && dif < 0) {
5493 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
5494 } else if (v.indexOf("ccw") !== -1 && dif > 0) {
5495 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
5498 if (dif > min || dif < -min) {
5499 this._addTween(target, p, start, start + dif, p);
5500 this._overwriteProps.push(p);
5507 //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.)
5508 set: function(ratio) {
5511 this._super.setRatio.call(this, ratio);
5516 pt.t[pt.p](this.finals[pt.p]);
5518 pt.t[pt.p] = this.finals[pt.p];
5538 * ----------------------------------------------------------------
5540 * ----------------------------------------------------------------
5542 window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
5544 var w = (window.GreenSockGlobals || window),
5545 gs = w.com.greensock,
5547 _HALF_PI = Math.PI / 2,
5549 _create = function(n, f) {
5550 var C = _class("easing." + n, function(){}, true),
5551 p = C.prototype = new Ease();
5556 _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.
5557 _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
5558 var C = _class("easing."+name, {
5559 easeOut:new EaseOut(),
5560 easeIn:new EaseIn(),
5561 easeInOut:new EaseInOut()
5566 EasePoint = function(time, value, next) {
5572 this.c = next.v - value;
5573 this.gap = next.t - time;
5578 _createBack = function(n, f) {
5579 var C = _class("easing." + n, function(overshoot) {
5580 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
5581 this._p2 = this._p1 * 1.525;
5583 p = C.prototype = new Ease();
5586 p.config = function(overshoot) {
5587 return new C(overshoot);
5592 Back = _wrap("Back",
5593 _createBack("BackOut", function(p) {
5594 return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
5596 _createBack("BackIn", function(p) {
5597 return p * p * ((this._p1 + 1) * p - this._p1);
5599 _createBack("BackInOut", function(p) {
5600 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);
5606 SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
5607 power = (power || power === 0) ? power : 0.7;
5608 if (linearRatio == null) {
5610 } else if (linearRatio > 1) {
5613 this._p = (linearRatio !== 1) ? power : 0;
5614 this._p1 = (1 - linearRatio) / 2;
5615 this._p2 = linearRatio;
5616 this._p3 = this._p1 + this._p2;
5617 this._calcEnd = (yoyoMode === true);
5619 p = SlowMo.prototype = new Ease(),
5620 SteppedEase, RoughEase, _createElastic;
5622 p.constructor = SlowMo;
5623 p.getRatio = function(p) {
5624 var r = p + (0.5 - p) * this._p;
5626 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
5627 } else if (p > this._p3) {
5628 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
5630 return this._calcEnd ? 1 : r;
5632 SlowMo.ease = new SlowMo(0.7, 0.7);
5634 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
5635 return new SlowMo(linearRatio, power, yoyoMode);
5640 SteppedEase = _class("easing.SteppedEase", function(steps) {
5642 this._p1 = 1 / steps;
5643 this._p2 = steps + 1;
5645 p = SteppedEase.prototype = new Ease();
5646 p.constructor = SteppedEase;
5647 p.getRatio = function(p) {
5650 } else if (p >= 1) {
5653 return ((this._p2 * p) >> 0) * this._p1;
5655 p.config = SteppedEase.config = function(steps) {
5656 return new SteppedEase(steps);
5661 RoughEase = _class("easing.RoughEase", function(vars) {
5663 var taper = vars.taper || "none",
5666 points = (vars.points || 20) | 0,
5668 randomize = (vars.randomize !== false),
5669 clamp = (vars.clamp === true),
5670 template = (vars.template instanceof Ease) ? vars.template : null,
5671 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
5672 x, y, bump, invX, obj, pnt;
5674 x = randomize ? Math.random() : (1 / points) * i;
5675 y = template ? template.getRatio(x) : x;
5676 if (taper === "none") {
5678 } else if (taper === "out") {
5680 bump = invX * invX * strength;
5681 } else if (taper === "in") {
5682 bump = x * x * strength;
5683 } else if (x < 0.5) { //"both" (start)
5685 bump = invX * invX * 0.5 * strength;
5686 } else { //"both" (end)
5688 bump = invX * invX * 0.5 * strength;
5691 y += (Math.random() * bump) - (bump * 0.5);
5704 a[cnt++] = {x:x, y:y};
5706 a.sort(function(a, b) {
5710 pnt = new EasePoint(1, 1, null);
5714 pnt = new EasePoint(obj.x, obj.y, pnt);
5717 this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
5719 p = RoughEase.prototype = new Ease();
5720 p.constructor = RoughEase;
5721 p.getRatio = function(p) {
5722 var pnt = this._prev;
5724 while (pnt.next && p >= pnt.t) {
5729 while (pnt.prev && p <= pnt.t) {
5734 return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
5736 p.config = function(vars) {
5737 return new RoughEase(vars);
5739 RoughEase.ease = new RoughEase();
5744 _create("BounceOut", function(p) {
5746 return 7.5625 * p * p;
5747 } else if (p < 2 / 2.75) {
5748 return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5749 } else if (p < 2.5 / 2.75) {
5750 return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5752 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5754 _create("BounceIn", function(p) {
5755 if ((p = 1 - p) < 1 / 2.75) {
5756 return 1 - (7.5625 * p * p);
5757 } else if (p < 2 / 2.75) {
5758 return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
5759 } else if (p < 2.5 / 2.75) {
5760 return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
5762 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
5764 _create("BounceInOut", function(p) {
5765 var invert = (p < 0.5);
5773 } else if (p < 2 / 2.75) {
5774 p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5775 } else if (p < 2.5 / 2.75) {
5776 p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5778 p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5780 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
5787 _create("CircOut", function(p) {
5788 return Math.sqrt(1 - (p = p - 1) * p);
5790 _create("CircIn", function(p) {
5791 return -(Math.sqrt(1 - (p * p)) - 1);
5793 _create("CircInOut", function(p) {
5794 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
5800 _createElastic = function(n, f, def) {
5801 var C = _class("easing." + n, function(amplitude, period) {
5802 this._p1 = amplitude || 1;
5803 this._p2 = period || def;
5804 this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
5806 p = C.prototype = new Ease();
5809 p.config = function(amplitude, period) {
5810 return new C(amplitude, period);
5815 _createElastic("ElasticOut", function(p) {
5816 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
5818 _createElastic("ElasticIn", function(p) {
5819 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
5821 _createElastic("ElasticInOut", function(p) {
5822 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;
5829 _create("ExpoOut", function(p) {
5830 return 1 - Math.pow(2, -10 * p);
5832 _create("ExpoIn", function(p) {
5833 return Math.pow(2, 10 * (p - 1)) - 0.001;
5835 _create("ExpoInOut", function(p) {
5836 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
5843 _create("SineOut", function(p) {
5844 return Math.sin(p * _HALF_PI);
5846 _create("SineIn", function(p) {
5847 return -Math.cos(p * _HALF_PI) + 1;
5849 _create("SineInOut", function(p) {
5850 return -0.5 * (Math.cos(Math.PI * p) - 1);
5854 _class("easing.EaseLookup", {
5860 //register the non-standard eases
5861 _easeReg(w.SlowMo, "SlowMo", "ease,");
5862 _easeReg(RoughEase, "RoughEase", "ease,");
5863 _easeReg(SteppedEase, "SteppedEase", "ease,");
5883 * ----------------------------------------------------------------
5884 * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
5885 * ----------------------------------------------------------------
5890 var _globals = window.GreenSockGlobals || window;
5891 if (_globals.TweenLite) {
5892 return; //in case the core set of classes is already loaded, don't instantiate twice.
5894 var _namespace = function(ns) {
5895 var a = ns.split("."),
5897 for (i = 0; i < a.length; i++) {
5898 p[a[i]] = p = p[a[i]] || {};
5902 gs = _namespace("com.greensock"),
5903 _tinyNum = 0.0000000001,
5905 _emptyFunc = function() {},
5906 _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)
5907 var toString = Object.prototype.toString,
5908 array = toString.call([]);
5909 return function(obj) {
5910 return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
5913 a, i, p, _ticker, _tickerActive,
5918 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
5919 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
5920 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
5921 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
5923 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
5924 * 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,
5925 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
5926 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
5927 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
5928 * 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
5929 * sandbox the banner one like:
5932 * 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.
5934 * <script src="js/greensock/v1.7/TweenMax.js"></script>
5936 * 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(...)
5938 * <script src="js/greensock/v1.6/TweenMax.js"></script>
5940 * gs.TweenLite.to(...); //would use v1.7
5941 * TweenLite.to(...); //would use v1.6
5944 * @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".
5945 * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
5946 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
5947 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
5949 Definition = function(ns, dependencies, func, global) {
5950 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
5951 _defLookup[ns] = this;
5952 this.gsClass = null;
5955 this.check = function(init) {
5956 var i = dependencies.length,
5960 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
5961 _classes[i] = cur.gsClass;
5967 if (missing === 0 && func) {
5968 a = ("com.greensock." + ns).split(".");
5970 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
5972 //exports to multiple environments
5974 _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.)
5975 if (typeof(define) === "function" && define.amd){ //AMD
5976 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
5977 } else if (typeof(module) !== "undefined" && module.exports){ //node
5978 module.exports = cl;
5981 for (i = 0; i < this.sc.length; i++) {
5989 //used to create Definition instances (which basically registers a class that has dependencies).
5990 _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
5991 return new Definition(ns, dependencies, func, global);
5994 //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).
5995 _class = gs._class = function(ns, func, global) {
5996 func = func || function() {};
5997 _gsDefine(ns, [], function(){ return func; }, global);
6001 _gsDefine.globals = _globals;
6006 * ----------------------------------------------------------------
6008 * ----------------------------------------------------------------
6010 var _baseParams = [0, 0, 1, 1],
6012 Ease = _class("easing.Ease", function(func, extraParams, type, power) {
6014 this._type = type || 0;
6015 this._power = power || 0;
6016 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
6018 _easeMap = Ease.map = {},
6019 _easeReg = Ease.register = function(ease, names, types, create) {
6020 var na = names.split(","),
6022 ta = (types || "easeIn,easeOut,easeInOut").split(","),
6026 e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
6030 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
6037 p.getRatio = function(p) {
6039 this._params[0] = p;
6040 return this._func.apply(null, this._params);
6044 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
6047 } else if (pw === 2) {
6049 } else if (pw === 3) {
6051 } else if (pw === 4) {
6054 return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
6057 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
6058 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
6061 p = a[i]+",Power"+i;
6062 _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
6063 _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
6064 _easeReg(new Ease(null,null,3,i), p, "easeInOut");
6066 _easeMap.linear = gs.easing.Linear.easeIn;
6067 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
6071 * ----------------------------------------------------------------
6073 * ----------------------------------------------------------------
6075 var EventDispatcher = _class("events.EventDispatcher", function(target) {
6076 this._listeners = {};
6077 this._eventTarget = target || this;
6079 p = EventDispatcher.prototype;
6081 p.addEventListener = function(type, callback, scope, useParam, priority) {
6082 priority = priority || 0;
6083 var list = this._listeners[type],
6087 this._listeners[type] = list = [];
6092 if (listener.c === callback && listener.s === scope) {
6094 } else if (index === 0 && listener.pr < priority) {
6098 list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
6099 if (this === _ticker && !_tickerActive) {
6104 p.removeEventListener = function(type, callback) {
6105 var list = this._listeners[type], i;
6109 if (list[i].c === callback) {
6117 p.dispatchEvent = function(type) {
6118 var list = this._listeners[type],
6122 t = this._eventTarget;
6126 listener.c.call(listener.s || t, {type:type, target:t});
6128 listener.c.call(listener.s || t);
6136 * ----------------------------------------------------------------
6138 * ----------------------------------------------------------------
6140 var _reqAnimFrame = window.requestAnimationFrame,
6141 _cancelAnimFrame = window.cancelAnimationFrame,
6142 _getTime = Date.now || function() {return new Date().getTime();},
6143 _lastUpdate = _getTime();
6145 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
6146 a = ["ms","moz","webkit","o"];
6148 while (--i > -1 && !_reqAnimFrame) {
6149 _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
6150 _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
6153 _class("Ticker", function(fps, useRAF) {
6155 _startTime = _getTime(),
6156 _useRAF = (useRAF !== false && _reqAnimFrame),
6157 _lagThreshold = 500,
6159 _fps, _req, _id, _gap, _nextTime,
6160 _tick = function(manual) {
6161 var elapsed = _getTime() - _lastUpdate,
6163 if (elapsed > _lagThreshold) {
6164 _startTime += elapsed - _adjustedLag;
6166 _lastUpdate += elapsed;
6167 _self.time = (_lastUpdate - _startTime) / 1000;
6168 overlap = _self.time - _nextTime;
6169 if (!_fps || overlap > 0 || manual === true) {
6171 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
6174 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.
6178 _self.dispatchEvent("tick");
6182 EventDispatcher.call(_self);
6183 _self.time = _self.frame = 0;
6184 _self.tick = function() {
6188 _self.lagSmoothing = function(threshold, adjustedLag) {
6189 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
6190 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
6193 _self.sleep = function() {
6197 if (!_useRAF || !_cancelAnimFrame) {
6200 _cancelAnimFrame(_id);
6204 if (_self === _ticker) {
6205 _tickerActive = false;
6209 _self.wake = function() {
6212 } 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().
6213 _lastUpdate = _getTime() - _lagThreshold + 5;
6215 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
6216 if (_self === _ticker) {
6217 _tickerActive = true;
6222 _self.fps = function(value) {
6223 if (!arguments.length) {
6227 _gap = 1 / (_fps || 60);
6228 _nextTime = this.time + _gap;
6232 _self.useRAF = function(value) {
6233 if (!arguments.length) {
6242 //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.
6243 setTimeout(function() {
6244 if (_useRAF && (!_id || _self.frame < 5)) {
6245 _self.useRAF(false);
6250 p = gs.Ticker.prototype = new gs.events.EventDispatcher();
6251 p.constructor = gs.Ticker;
6255 * ----------------------------------------------------------------
6257 * ----------------------------------------------------------------
6259 var Animation = _class("core.Animation", function(duration, vars) {
6260 this.vars = vars = vars || {};
6261 this._duration = this._totalDuration = duration || 0;
6262 this._delay = Number(vars.delay) || 0;
6263 this._timeScale = 1;
6264 this._active = (vars.immediateRender === true);
6265 this.data = vars.data;
6266 this._reversed = (vars.reversed === true);
6268 if (!_rootTimeline) {
6271 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.
6275 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
6276 tl.add(this, tl._time);
6278 if (this.vars.paused) {
6283 _ticker = Animation.ticker = new gs.Ticker();
6284 p = Animation.prototype;
6285 p._dirty = p._gc = p._initted = p._paused = false;
6286 p._totalTime = p._time = 0;
6287 p._rawPrevTime = -1;
6288 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
6292 //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.
6293 var _checkTimeout = function() {
6294 if (_tickerActive && _getTime() - _lastUpdate > 2000) {
6297 setTimeout(_checkTimeout, 2000);
6302 p.play = function(from, suppressEvents) {
6304 this.seek(from, suppressEvents);
6306 return this.reversed(false).paused(false);
6309 p.pause = function(atTime, suppressEvents) {
6310 if (atTime != null) {
6311 this.seek(atTime, suppressEvents);
6313 return this.paused(true);
6316 p.resume = function(from, suppressEvents) {
6318 this.seek(from, suppressEvents);
6320 return this.paused(false);
6323 p.seek = function(time, suppressEvents) {
6324 return this.totalTime(Number(time), suppressEvents !== false);
6327 p.restart = function(includeDelay, suppressEvents) {
6328 return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
6331 p.reverse = function(from, suppressEvents) {
6333 this.seek((from || this.totalDuration()), suppressEvents);
6335 return this.reversed(true).paused(false);
6338 p.render = function(time, suppressEvents, force) {
6339 //stub - we override this method in subclasses.
6342 p.invalidate = function() {
6346 p.isActive = function() {
6347 var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
6348 startTime = this._startTime,
6350 return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
6353 p._enabled = function (enabled, ignoreTimeline) {
6354 if (!_tickerActive) {
6357 this._gc = !enabled;
6358 this._active = this.isActive();
6359 if (ignoreTimeline !== true) {
6360 if (enabled && !this.timeline) {
6361 this._timeline.add(this, this._startTime - this._delay);
6362 } else if (!enabled && this.timeline) {
6363 this._timeline._remove(this, true);
6370 p._kill = function(vars, target) {
6371 return this._enabled(false, false);
6374 p.kill = function(vars, target) {
6375 this._kill(vars, target);
6379 p._uncache = function(includeSelf) {
6380 var tween = includeSelf ? this : this.timeline;
6382 tween._dirty = true;
6383 tween = tween.timeline;
6388 p._swapSelfInParams = function(params) {
6389 var i = params.length,
6390 copy = params.concat();
6392 if (params[i] === "{self}") {
6399 //----Animation getters/setters --------------------------------------------------------
6401 p.eventCallback = function(type, callback, params, scope) {
6402 if ((type || "").substr(0,2) === "on") {
6404 if (arguments.length === 1) {
6407 if (callback == null) {
6411 v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
6412 v[type + "Scope"] = scope;
6414 if (type === "onUpdate") {
6415 this._onUpdate = callback;
6421 p.delay = function(value) {
6422 if (!arguments.length) {
6425 if (this._timeline.smoothChildTiming) {
6426 this.startTime( this._startTime + value - this._delay );
6428 this._delay = value;
6432 p.duration = function(value) {
6433 if (!arguments.length) {
6434 this._dirty = false;
6435 return this._duration;
6437 this._duration = this._totalDuration = value;
6438 this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
6439 if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
6440 this.totalTime(this._totalTime * (value / this._duration), true);
6445 p.totalDuration = function(value) {
6446 this._dirty = false;
6447 return (!arguments.length) ? this._totalDuration : this.duration(value);
6450 p.time = function(value, suppressEvents) {
6451 if (!arguments.length) {
6455 this.totalDuration();
6457 return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
6460 p.totalTime = function(time, suppressEvents, uncapped) {
6461 if (!_tickerActive) {
6464 if (!arguments.length) {
6465 return this._totalTime;
6467 if (this._timeline) {
6468 if (time < 0 && !uncapped) {
6469 time += this.totalDuration();
6471 if (this._timeline.smoothChildTiming) {
6473 this.totalDuration();
6475 var totalDuration = this._totalDuration,
6476 tl = this._timeline;
6477 if (time > totalDuration && !uncapped) {
6478 time = totalDuration;
6480 this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
6481 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.
6482 this._uncache(false);
6484 //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.
6486 while (tl._timeline) {
6487 if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
6488 tl.totalTime(tl._totalTime, true);
6495 this._enabled(true, false);
6497 if (this._totalTime !== time || this._duration === 0) {
6498 this.render(time, suppressEvents, false);
6499 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.
6507 p.progress = p.totalProgress = function(value, suppressEvents) {
6508 return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents);
6511 p.startTime = function(value) {
6512 if (!arguments.length) {
6513 return this._startTime;
6515 if (value !== this._startTime) {
6516 this._startTime = value;
6517 if (this.timeline) if (this.timeline._sortChildren) {
6518 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.
6524 p.timeScale = function(value) {
6525 if (!arguments.length) {
6526 return this._timeScale;
6528 value = value || _tinyNum; //can't allow zero because it'll throw the math off
6529 if (this._timeline && this._timeline.smoothChildTiming) {
6530 var pauseTime = this._pauseTime,
6531 t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
6532 this._startTime = t - ((t - this._startTime) * this._timeScale / value);
6534 this._timeScale = value;
6535 return this._uncache(false);
6538 p.reversed = function(value) {
6539 if (!arguments.length) {
6540 return this._reversed;
6542 if (value != this._reversed) {
6543 this._reversed = value;
6544 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
6549 p.paused = function(value) {
6550 if (!arguments.length) {
6551 return this._paused;
6553 if (value != this._paused) if (this._timeline) {
6554 if (!_tickerActive && !value) {
6557 var tl = this._timeline,
6559 elapsed = raw - this._pauseTime;
6560 if (!value && tl.smoothChildTiming) {
6561 this._startTime += elapsed;
6562 this._uncache(false);
6564 this._pauseTime = value ? raw : null;
6565 this._paused = value;
6566 this._active = this.isActive();
6567 if (!value && elapsed !== 0 && this._initted && this.duration()) {
6568 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.
6571 if (this._gc && !value) {
6572 this._enabled(true, false);
6579 * ----------------------------------------------------------------
6581 * ----------------------------------------------------------------
6583 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
6584 Animation.call(this, 0, vars);
6585 this.autoRemoveChildren = this.smoothChildTiming = true;
6588 p = SimpleTimeline.prototype = new Animation();
6589 p.constructor = SimpleTimeline;
6590 p.kill()._gc = false;
6591 p._first = p._last = null;
6592 p._sortChildren = false;
6594 p.add = p.insert = function(child, position, align, stagger) {
6596 child._startTime = Number(position || 0) + child._delay;
6597 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).
6598 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
6600 if (child.timeline) {
6601 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
6603 child.timeline = child._timeline = this;
6605 child._enabled(true, true);
6607 prevTween = this._last;
6608 if (this._sortChildren) {
6609 st = child._startTime;
6610 while (prevTween && prevTween._startTime > st) {
6611 prevTween = prevTween._prev;
6615 child._next = prevTween._next;
6616 prevTween._next = child;
6618 child._next = this._first;
6619 this._first = child;
6622 child._next._prev = child;
6626 child._prev = prevTween;
6627 if (this._timeline) {
6628 this._uncache(true);
6633 p._remove = function(tween, skipDisable) {
6634 if (tween.timeline === this) {
6636 tween._enabled(false, true);
6638 tween.timeline = null;
6641 tween._prev._next = tween._next;
6642 } else if (this._first === tween) {
6643 this._first = tween._next;
6646 tween._next._prev = tween._prev;
6647 } else if (this._last === tween) {
6648 this._last = tween._prev;
6651 if (this._timeline) {
6652 this._uncache(true);
6658 p.render = function(time, suppressEvents, force) {
6659 var tween = this._first,
6661 this._totalTime = this._time = this._rawPrevTime = time;
6663 next = tween._next; //record it here because the value could change after rendering...
6664 if (tween._active || (time >= tween._startTime && !tween._paused)) {
6665 if (!tween._reversed) {
6666 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
6668 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
6675 p.rawTime = function() {
6676 if (!_tickerActive) {
6679 return this._totalTime;
6683 * ----------------------------------------------------------------
6685 * ----------------------------------------------------------------
6687 var TweenLite = _class("TweenLite", function(target, duration, vars) {
6688 Animation.call(this, duration, vars);
6689 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
6691 if (target == null) {
6692 throw "Cannot tween a null target.";
6695 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
6697 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
6698 overwrite = this.vars.overwrite,
6701 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
6703 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
6704 this._targets = targets = _slice.call(target, 0);
6705 this._propLookup = [];
6706 this._siblings = [];
6707 for (i = 0; i < targets.length; i++) {
6710 targets.splice(i--, 1);
6712 } else if (typeof(targ) === "string") {
6713 targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
6714 if (typeof(targ) === "string") {
6715 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
6718 } 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.
6719 targets.splice(i--, 1);
6720 this._targets = targets = targets.concat(_slice.call(targ, 0));
6723 this._siblings[i] = _register(targ, this, false);
6724 if (overwrite === 1) if (this._siblings[i].length > 1) {
6725 _applyOverwrite(targ, this, null, 1, this._siblings[i]);
6730 this._propLookup = {};
6731 this._siblings = _register(target, this, false);
6732 if (overwrite === 1) if (this._siblings.length > 1) {
6733 _applyOverwrite(target, this, null, 1, this._siblings);
6736 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
6737 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)
6738 this.render(-this._delay);
6741 _isSelector = function(v) {
6742 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.
6744 _autoCSS = function(vars, target) {
6748 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.
6756 p = TweenLite.prototype = new Animation();
6757 p.constructor = TweenLite;
6758 p.kill()._gc = false;
6760 //----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
6763 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
6764 p._notifyPluginsOfEnabled = p._lazy = false;
6766 TweenLite.version = "1.12.1";
6767 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
6768 TweenLite.defaultOverwrite = "auto";
6769 TweenLite.ticker = _ticker;
6770 TweenLite.autoSleep = true;
6771 TweenLite.lagSmoothing = function(threshold, adjustedLag) {
6772 _ticker.lagSmoothing(threshold, adjustedLag);
6774 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; };
6776 var _lazyTweens = [],
6778 _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.
6779 _plugins = TweenLite._plugins = {},
6780 _tweenLookup = _internals.tweenLookup = {},
6781 _tweenLookupNum = 0,
6782 _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},
6783 _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
6784 _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
6785 _rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
6786 _lazyRender = function() {
6787 var i = _lazyTweens.length;
6791 if (a && a._lazy !== false) {
6792 a.render(a._lazy, false, true);
6796 _lazyTweens.length = 0;
6799 _rootTimeline._startTime = _ticker.time;
6800 _rootFramesTimeline._startTime = _ticker.frame;
6801 _rootTimeline._active = _rootFramesTimeline._active = true;
6802 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".
6804 Animation._updateRoot = TweenLite.render = function() {
6806 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.
6809 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
6810 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
6811 if (_lazyTweens.length) {
6814 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
6815 for (p in _tweenLookup) {
6816 a = _tweenLookup[p].tweens;
6823 if (a.length === 0) {
6824 delete _tweenLookup[p];
6827 //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
6828 p = _rootTimeline._first;
6829 if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
6830 while (p && p._paused) {
6840 _ticker.addEventListener("tick", Animation._updateRoot);
6842 var _register = function(target, tween, scrub) {
6843 var id = target._gsTweenID, a, i;
6844 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
6845 _tweenLookup[id] = {target:target, tweens:[]};
6848 a = _tweenLookup[id].tweens;
6849 a[(i = a.length)] = tween;
6852 if (a[i] === tween) {
6858 return _tweenLookup[id].tweens;
6861 _applyOverwrite = function(target, tween, props, mode, siblings) {
6862 var i, changed, curTween, l;
6863 if (mode === 1 || mode >= 4) {
6864 l = siblings.length;
6865 for (i = 0; i < l; i++) {
6866 if ((curTween = siblings[i]) !== tween) {
6867 if (!curTween._gc) if (curTween._enabled(false, false)) {
6870 } else if (mode === 5) {
6876 //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)
6877 var startTime = tween._startTime + _tinyNum,
6880 zeroDur = (tween._duration === 0),
6882 i = siblings.length;
6884 if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
6886 } else if (curTween._timeline !== tween._timeline) {
6887 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
6888 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
6889 overlaps[oCount++] = curTween;
6891 } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
6892 overlaps[oCount++] = curTween;
6898 curTween = overlaps[i];
6899 if (mode === 2) if (curTween._kill(props, target)) {
6902 if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
6903 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
6911 _checkOverlap = function(tween, reference, zeroDur) {
6912 var tl = tween._timeline,
6914 t = tween._startTime;
6915 while (tl._timeline) {
6917 ts *= tl._timeScale;
6924 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;
6928 //---- TweenLite instance methods -----------------------------------------------------------------------------
6930 p._init = function() {
6932 op = this._overwrittenProps,
6933 dur = this._duration,
6934 immediate = !!v.immediateRender,
6936 i, initPlugins, pt, p, startVars;
6938 if (this._startAt) {
6939 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.
6940 this._startAt.kill();
6943 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);
6944 startVars[p] = v.startAt[p];
6946 startVars.overwrite = false;
6947 startVars.immediateRender = true;
6948 startVars.lazy = (immediate && v.lazy !== false);
6949 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
6950 this._startAt = TweenLite.to(this.target, 0, startVars);
6952 if (this._time > 0) {
6953 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()).
6954 } else if (dur !== 0) {
6955 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.
6958 } else if (v.runBackwards && dur !== 0) {
6959 //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)
6960 if (this._startAt) {
6961 this._startAt.render(-1, true);
6962 this._startAt.kill();
6963 this._startAt = null;
6966 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.
6967 if (!_reservedProps[p] || p === "autoCSS") {
6972 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.
6973 pt.lazy = (immediate && v.lazy !== false);
6974 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)
6975 this._startAt = TweenLite.to(this.target, 0, pt);
6977 this._startAt._init(); //ensures that the initial values are recorded
6978 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.
6979 } else if (this._time === 0) {
6985 this._ease = TweenLite.defaultEase;
6986 } else if (ease instanceof Ease) {
6987 this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
6989 this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
6991 this._easeType = this._ease._type;
6992 this._easePower = this._ease._power;
6993 this._firstPT = null;
6995 if (this._targets) {
6996 i = this._targets.length;
6998 if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
7003 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
7007 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
7009 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.
7010 this._enabled(false, false);
7012 if (v.runBackwards) {
7020 this._onUpdate = v.onUpdate;
7021 this._initted = true;
7024 p._initProps = function(target, propLookup, siblings, overwrittenProps) {
7025 var p, i, initPlugins, plugin, pt, v;
7026 if (target == null) {
7030 if (_lazyLookup[target._gsTweenID]) {
7031 _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)
7034 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.
7035 _autoCSS(this.vars, target);
7037 for (p in this.vars) {
7039 if (_reservedProps[p]) {
7040 if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
7041 this.vars[p] = v = this._swapSelfInParams(v, this);
7044 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
7046 //t - target [object]
7047 //p - property [string]
7048 //s - start [number]
7049 //c - change [number]
7050 //f - isFunction [boolean]
7052 //pg - isPlugin [boolean]
7053 //pr - priority [number]
7054 this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
7055 i = plugin._overwriteProps.length;
7057 propLookup[plugin._overwriteProps[i]] = this._firstPT;
7059 if (plugin._priority || plugin._onInitAllProps) {
7062 if (plugin._onDisable || plugin._onEnable) {
7063 this._notifyPluginsOfEnabled = true;
7067 this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
7068 pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
7069 pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
7071 if (pt) if (pt._next) {
7072 pt._next._prev = pt;
7076 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)
7077 return this._initProps(target, propLookup, siblings, overwrittenProps);
7079 if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
7080 this._kill(propLookup, target);
7081 return this._initProps(target, propLookup, siblings, overwrittenProps);
7083 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.
7084 _lazyLookup[target._gsTweenID] = true;
7089 p.render = function(time, suppressEvents, force) {
7090 var prevTime = this._time,
7091 duration = this._duration,
7092 prevRawPrevTime = this._rawPrevTime,
7093 isComplete, callback, pt, rawPrevTime;
7094 if (time >= duration) {
7095 this._totalTime = this._time = duration;
7096 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
7097 if (!this._reversed ) {
7099 callback = "onComplete";
7101 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.
7102 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.
7105 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
7107 if (prevRawPrevTime > _tinyNum) {
7108 callback = "onReverseComplete";
7111 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.
7114 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
7115 this._totalTime = this._time = 0;
7116 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
7117 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) {
7118 callback = "onReverseComplete";
7119 isComplete = this._reversed;
7122 this._active = false;
7123 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.
7124 if (prevRawPrevTime >= 0) {
7127 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.
7129 } 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.
7133 this._totalTime = this._time = time;
7135 if (this._easeType) {
7136 var r = time / duration, type = this._easeType, pow = this._easePower;
7137 if (type === 1 || (type === 3 && r >= 0.5)) {
7145 } else if (pow === 2) {
7147 } else if (pow === 3) {
7149 } else if (pow === 4) {
7155 } else if (type === 2) {
7157 } else if (time / duration < 0.5) {
7160 this.ratio = 1 - (r / 2);
7164 this.ratio = this._ease.getRatio(time / duration);
7168 if (this._time === prevTime && !force) {
7170 } else if (!this._initted) {
7172 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.
7174 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
7175 this._time = this._totalTime = prevTime;
7176 this._rawPrevTime = prevRawPrevTime;
7177 _lazyTweens.push(this);
7181 //_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.
7182 if (this._time && !isComplete) {
7183 this.ratio = this._ease.getRatio(this._time / duration);
7184 } else if (isComplete && this._ease._calcEnd) {
7185 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
7188 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.
7191 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
7192 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.
7194 if (prevTime === 0) {
7195 if (this._startAt) {
7197 this._startAt.render(time, suppressEvents, force);
7198 } else if (!callback) {
7199 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.
7202 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
7203 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
7210 pt.t[pt.p](pt.c * this.ratio + pt.s);
7212 pt.t[pt.p] = pt.c * this.ratio + pt.s;
7217 if (this._onUpdate) {
7218 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.
7219 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.
7221 if (!suppressEvents) if (this._time !== prevTime || isComplete) {
7222 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
7226 if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
7227 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.
7228 this._startAt.render(time, suppressEvents, force);
7231 if (this._timeline.autoRemoveChildren) {
7232 this._enabled(false, false);
7234 this._active = false;
7236 if (!suppressEvents && this.vars[callback]) {
7237 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
7239 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.
7240 this._rawPrevTime = 0;
7246 p._kill = function(vars, target) {
7247 if (vars === "all") {
7250 if (vars == null) if (target == null || target === this.target) {
7252 return this._enabled(false, false);
7254 target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
7255 var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
7256 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
7259 if (this._kill(vars, target[i])) {
7264 if (this._targets) {
7265 i = this._targets.length;
7267 if (target === this._targets[i]) {
7268 propLookup = this._propLookup[i] || {};
7269 this._overwrittenProps = this._overwrittenProps || [];
7270 overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
7274 } else if (target !== this.target) {
7277 propLookup = this._propLookup;
7278 overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
7282 killProps = vars || propLookup;
7283 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)
7284 for (p in killProps) {
7285 if ((pt = propLookup[p])) {
7286 if (pt.pg && pt.t._kill(killProps)) {
7287 changed = true; //some plugins need to be notified so they can perform cleanup tasks first
7289 if (!pt.pg || pt.t._overwriteProps.length === 0) {
7291 pt._prev._next = pt._next;
7292 } else if (pt === this._firstPT) {
7293 this._firstPT = pt._next;
7296 pt._next._prev = pt._prev;
7298 pt._next = pt._prev = null;
7300 delete propLookup[p];
7303 overwrittenProps[p] = 1;
7306 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.
7307 this._enabled(false, false);
7314 p.invalidate = function() {
7315 if (this._notifyPluginsOfEnabled) {
7316 TweenLite._onPluginEvent("_onDisable", this);
7318 this._firstPT = null;
7319 this._overwrittenProps = null;
7320 this._onUpdate = null;
7321 this._startAt = null;
7322 this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = false;
7323 this._propLookup = (this._targets) ? {} : [];
7327 p._enabled = function(enabled, ignoreTimeline) {
7328 if (!_tickerActive) {
7331 if (enabled && this._gc) {
7332 var targets = this._targets,
7337 this._siblings[i] = _register(targets[i], this, true);
7340 this._siblings = _register(this.target, this, true);
7343 Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
7344 if (this._notifyPluginsOfEnabled) if (this._firstPT) {
7345 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
7351 //----TweenLite static methods -----------------------------------------------------
7353 TweenLite.to = function(target, duration, vars) {
7354 return new TweenLite(target, duration, vars);
7357 TweenLite.from = function(target, duration, vars) {
7358 vars.runBackwards = true;
7359 vars.immediateRender = (vars.immediateRender != false);
7360 return new TweenLite(target, duration, vars);
7363 TweenLite.fromTo = function(target, duration, fromVars, toVars) {
7364 toVars.startAt = fromVars;
7365 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
7366 return new TweenLite(target, duration, toVars);
7369 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
7370 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});
7373 TweenLite.set = function(target, vars) {
7374 return new TweenLite(target, 0, vars);
7377 TweenLite.getTweensOf = function(target, onlyActive) {
7378 if (target == null) { return []; }
7379 target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
7381 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
7385 a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
7388 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
7399 a = _register(target).concat();
7402 if (a[i]._gc || (onlyActive && !a[i].isActive())) {
7410 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
7411 if (typeof(onlyActive) === "object") {
7412 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
7415 var a = TweenLite.getTweensOf(target, onlyActive),
7418 a[i]._kill(vars, target);
7425 * ----------------------------------------------------------------
7426 * 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)
7427 * ----------------------------------------------------------------
7429 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
7430 this._overwriteProps = (props || "").split(",");
7431 this._propName = this._overwriteProps[0];
7432 this._priority = priority || 0;
7433 this._super = TweenPlugin.prototype;
7436 p = TweenPlugin.prototype;
7437 TweenPlugin.version = "1.10.1";
7438 TweenPlugin.API = 2;
7441 p._addTween = function(target, prop, start, end, overwriteProp, round) {
7443 if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) {
7444 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
7446 pt._next._prev = pt;
7452 p.setRatio = function(v) {
7453 var pt = this._firstPT,
7457 val = pt.c * v + pt.s;
7459 val = Math.round(val);
7460 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
7472 p._kill = function(lookup) {
7473 var a = this._overwriteProps,
7476 if (lookup[this._propName] != null) {
7477 this._overwriteProps = [];
7481 if (lookup[a[i]] != null) {
7487 if (lookup[pt.n] != null) {
7489 pt._next._prev = pt._prev;
7492 pt._prev._next = pt._next;
7494 } else if (this._firstPT === pt) {
7495 this._firstPT = pt._next;
7503 p._roundProps = function(lookup, value) {
7504 var pt = this._firstPT;
7506 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.
7513 TweenLite._onPluginEvent = function(type, tween) {
7514 var pt = tween._firstPT,
7515 changed, pt2, first, last, next;
7516 if (type === "_onInitAllProps") {
7517 //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.
7521 while (pt2 && pt2.pr > pt.pr) {
7524 if ((pt._prev = pt2 ? pt2._prev : last)) {
7525 pt._prev._next = pt;
7529 if ((pt._next = pt2)) {
7536 pt = tween._firstPT = first;
7539 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
7547 TweenPlugin.activate = function(plugins) {
7548 var i = plugins.length;
7550 if (plugins[i].API === TweenPlugin.API) {
7551 _plugins[(new plugins[i]())._propName] = plugins[i];
7557 //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.
7558 _gsDefine.plugin = function(config) {
7559 if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
7560 var propName = config.propName,
7561 priority = config.priority || 0,
7562 overwriteProps = config.overwriteProps,
7563 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
7564 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
7566 TweenPlugin.call(this, propName, priority);
7567 this._overwriteProps = overwriteProps || [];
7568 }, (config.global === true)),
7569 p = Plugin.prototype = new TweenPlugin(propName),
7571 p.constructor = Plugin;
7572 Plugin.API = config.API;
7574 if (typeof(config[prop]) === "function") {
7575 p[map[prop]] = config[prop];
7578 Plugin.version = config.version;
7579 TweenPlugin.activate([Plugin]);
7584 //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.
7585 a = window._gsQueue;
7587 for (i = 0; i < a.length; i++) {
7590 for (p in _defLookup) {
7591 if (!_defLookup[p].func) {
7592 //window.console.log("GSAP encountered missing dependency: com.greensock." + p);
7597 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
7601 angular.module('att.abs.transition', [])
7603 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
7605 var $transition = function(element, trigger, options) {
7606 options = options || {};
7607 var deferred = $q.defer();
7608 var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
7610 var transitionEndHandler = function() {
7611 $rootScope.$apply(function() {
7612 element.unbind(endEventName, transitionEndHandler);
7613 deferred.resolve(element);
7618 element.bind(endEventName, transitionEndHandler);
7621 // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
7622 $timeout(function() {
7623 if ( angular.isString(trigger) ) {
7624 element.addClass(trigger);
7625 } else if ( angular.isFunction(trigger) ) {
7627 } else if ( angular.isObject(trigger) ) {
7628 element.css(trigger);
7630 //If browser does not support transitions, instantly resolve
7631 if ( !endEventName ) {
7632 deferred.resolve(element);
7636 // Add our custom cancel function to the promise that is returned
7637 // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
7638 // i.e. it will therefore never raise a transitionEnd event for that transition
7639 deferred.promise.cancel = function() {
7640 if ( endEventName ) {
7641 element.unbind(endEventName, transitionEndHandler);
7643 deferred.reject('Transition cancelled');
7646 return deferred.promise;
7649 // Work out the name of the transitionEnd event
7650 var transElement = document.createElement('trans');
7651 var transitionEndEventNames = {
7652 'WebkitTransition': 'webkitTransitionEnd',
7653 'MozTransition': 'transitionend',
7654 'OTransition': 'oTransitionEnd',
7655 'transition': 'transitionend'
7657 var animationEndEventNames = {
7658 'WebkitTransition': 'webkitAnimationEnd',
7659 'MozTransition': 'animationend',
7660 'OTransition': 'oAnimationEnd',
7661 'transition': 'animationend'
7663 function findEndEventName(endEventNames) {
7664 for (var name in endEventNames){
7665 if (transElement.style[name] !== undefined) {
7666 return endEventNames[name];
7670 $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
7671 $transition.animationEndEventName = findEndEventName(animationEndEventNames);
7675 .factory('$scrollTo', ['$window', function($window) {
7676 var $scrollTo = function(offsetLeft, offsetTop, duration) {
7677 TweenMax.to($window, duration || 1, {scrollTo: {y: offsetTop, x: offsetLeft}, ease: Power4.easeOut});
7681 .factory('animation', function(){
7684 .factory('$progressBar', function(){
7686 //Provides a function to pass in code for closure purposes
7687 var loadingAnimationCreator = function(onUpdateCallback){
7689 //Use closure to setup some resuable code
7690 var loadingAnimation = function(callback, duration){
7691 TweenMax.to({}, duration, {
7692 onUpdateParams: ["{self}"],
7693 onUpdate: onUpdateCallback,
7694 onComplete: callback
7697 //Returns a function that takes a callback function and a duration for the animation
7699 return loadingAnimation;
7703 return loadingAnimationCreator;
7705 .factory('$height', function(){
7706 var heightAnimation = function(element,duration,height,alpha){
7707 TweenMax.to(element,
7709 {height:height, autoAlpha:alpha},
7712 return heightAnimation;
7714 angular.module('att.abs.accordion', ['att.abs.utilities', 'att.abs.position', 'att.abs.transition'])
7715 .constant('accordionConfig', {
7717 }).controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', '$log',
7718 function ($scope, $attrs, accordionConfig, $log) {
7719 // This array keeps track of the accordion groups
7722 // Keep reference to user's scope to properly assign `is-open`
7723 this.scope = $scope;
7724 $scope.forceExpand = false;
7725 // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
7726 this.closeOthers = function (openGroup) {
7727 var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
7728 if (closeOthers && !$scope.forceExpand) {
7729 angular.forEach(this.groups, function (group) {
7730 if (group !== openGroup) {
7731 group.isOpen = false;
7735 if (this.groups.indexOf(openGroup) === (this.groups.length - 1) && $scope.forceExpand) {
7736 $scope.forceExpand = false;
7739 this.expandAll = function () {
7740 $scope.forceExpand = true;
7741 angular.forEach(this.groups, function (group) {
7742 group.isOpen = true;
7745 this.collapseAll = function () {
7746 angular.forEach(this.groups, function (group) {
7747 group.isOpen = false;
7750 /**function focus @param focusGroup */
7751 this.focus = function (focusGroup) {
7753 angular.forEach(this.groups, function (group, index) {
7754 if (group !== focusGroup) {
7755 group.focused = false;
7758 group.focused = true;
7762 /** @param blurGroup*/
7763 this.blur = function (blurGroup) {
7764 blurGroup.focused = false;
7766 $log.log("accordion.blur()", blurGroup);
7768 /** @param group - the group in current focus @param down - cycling down */
7769 this.cycle = function (group, down, noRecycle) {
7771 if (this.index <= 0 && !noRecycle) {
7772 this.index = this.groups.length - 1;
7777 if (this.index === (this.groups.length - 1))
7781 group.focused = false;
7794 group.focused = false;
7795 this.groups[this.index].setFocus = true;
7796 this.groups[this.index].focused = true;
7799 // This is called from the accordion-group directive to add itself to the accordion
7800 this.addGroup = function (groupScope) {
7802 groupScope.index = this.groups.length;
7803 groupScope.focused = false;
7804 this.groups.push(groupScope);
7806 if(this.groups.length > 0){
7810 groupScope.$on('$destroy', function () {
7811 that.removeGroup(groupScope);
7814 // This is called from the accordion-group directive when to remove itself
7815 this.removeGroup = function (group) {
7816 var index = this.groups.indexOf(group);
7818 this.groups.splice(this.groups.indexOf(group), 1);
7822 //The accordion directive simply sets up the directive controller and adds an accordion CSS class to itself element.
7823 .directive('accordion', function () {
7826 controller: 'AccordionController',
7834 template: '<div class="{{cClass}}" ng-transclude></div>',
7835 link: function (scope, elem, attribute, ctrl) {
7836 scope.$watch("expandAll", function (value) {
7839 scope.expandAll = false;
7842 scope.$watch("collapseAll", function (value) {
7845 scope.collapseAll = false;
7851 //The accordion-group directive indicates a block of html that will expand and collapse in an accordion
7852 .directive('accordionGroup', [ function () {
7854 // We need this directive to be inside an accordion
7855 require: ['^accordion', 'accordionGroup'],
7857 // It transcludes the contents of the directive into the template
7859 // The element containing the directive will be replaced with the template
7861 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/accordion.html',
7863 // Create an isolated scope and interpolate the heading attribute onto this scope
7867 controller: ['$scope', function ($scope)
7869 $scope.showicon = true;
7870 this.setHeading = function (element)
7872 this.heading = element;
7873 $scope.showicon = false;
7875 this.isIsOpen = function ()
7877 return $scope.isOpen;
7880 link: function (scope, element, attrs, ctrl) {
7881 var accordionCtrl = ctrl[0];
7882 var accordionGroupCtrl = ctrl[1];
7883 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};
7885 var tab = element.children().eq(0);
7886 var parentHyperLink=attrs.parentLink;
7887 scope.setFocus = false;
7888 scope.childLength = attrs.childLength;
7889 scope.headingIconClass = attrs.imageSource;
7891 var handleKeydown = function (ev) {
7892 var boolFlag = true;
7896 ev.preventDefault();
7902 ev.preventDefault();
7903 accordionCtrl.cycle(scope, false);
7907 ev.preventDefault();
7908 accordionCtrl.cycle(scope, true);
7914 ev.stopPropagation();
7918 if (angular.isUndefined(scope.isOpen)) {
7919 scope.isOpen = false;
7922 tab.bind("keydown", handleKeydown);
7924 accordionCtrl.addGroup(scope);
7926 if (scope.index === 0) {
7927 scope.focused = true;
7930 accordionGroupCtrl.toggle = scope.toggle = function () {
7931 /* if the menu item has children, toggle/expand child menu of this item */
7932 if (scope.childLength>0) {
7933 scope.isOpen = !scope.isOpen;
7934 accordionCtrl.focus(scope);
7935 return scope.isOpen;
7937 /* if the menu item does not have children, redirect to parent action URL*/
7939 window.location.href = parentHyperLink;
7944 scope.$watch('isOpen', function (value) {
7946 accordionCtrl.closeOthers(scope);
7950 scope.$watch("focused", function (value) {
7952 tab.attr("tabindex", "0");
7958 scope.setFocus = false;
7959 tab.attr("tabindex", "-1");
7965 //Use accordion-heading below an accordion-group to provide a heading containing HTML
7967 //<accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
7968 //</accordion-group>
7969 .directive('accordionToggle', function () {
7972 require: '^accordionGroup',
7977 link: function (scope, element, attr, accordionCtrl)
7979 var setIcon = function (isOpen) {
7980 if (scope.expandIcon && scope.collapseIcon)
7983 element.removeClass(scope.expandIcon);
7984 element.addClass(scope.collapseIcon);
7987 element.removeClass(scope.collapseIcon);
7988 element.addClass(scope.expandIcon);
7992 element.bind('click', function ()
7994 accordionCtrl.toggle();
7997 scope.$watch(function () {
7998 return accordionCtrl.isIsOpen();
7999 }, function (value) {
8004 }).directive('accordionHeading', function () {
8009 require: '^accordionGroup',
8010 compile: function (element, attr, transclude) {
8011 var link = function (scope, element, attr, accordionGroupCtrl) {
8012 // Pass the heading to the accordion-group controller
8013 // so that it can be transcluded into the right place in the template
8014 // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
8015 transclude(scope, function (clone) {
8016 element.append(clone);
8017 accordionGroupCtrl.setHeading(element);
8024 // Use in the accordion-group template to indicate where you want the heading to be transcluded
8025 // You must provide the property on the accordion-group controller that will hold the transcluded element
8026 .directive('accordionTransclude', function () {
8028 require: '^accordionGroup',
8029 link: function (scope, element, attr, controller) {
8030 scope.$watch(function () {
8031 return controller[attr.accordionTransclude];
8032 }, function (heading) {
8034 element.find("span").eq(0).prepend(heading);
8040 .directive('attGoTop', ['$scrollTo', function ($scrollTo) {
8044 link: function (scope, elem, attrs)
8046 elem.bind('click', function ()
8048 $scrollTo(0, attrs["attGoTop"]);
8053 .directive('attGoTo', ['$anchorScroll', '$location', function ($anchorScroll, $location) {
8057 link: function (scope, elem, attrs)
8059 elem.bind('click', function ()
8061 var newHash = attrs["attGoTo"];
8062 if ($location.hash() !== newHash)
8064 $location.hash(attrs["attGoTo"]);
8074 .directive('freeStanding', function () {
8080 template: "<div><span class='att-accordion__freestanding' ng-show='showAccordion'></span>\n" +
8081 "<div class='section-toggle'>\n" +
8082 "<button class='section-toggle__button' ng-click='fsToggle()'>\n" +
8083 " {{btnText}}<i style='font-size:0.875rem' ng-class='{\"ion-ios-arrow-up\": showAccordion,\"ion-ios-arrow-down\": !showAccordion, }'></i> \n" +
8086 compile: function (element, attr, transclude)
8088 var link = function (scope, elem, attrs) {
8090 transclude(scope, function (clone)
8092 elem.find("span").append(clone);
8094 scope.showAccordion = false;
8095 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
8096 scope.fsToggle = function ()
8098 scope.showAccordion = !scope.showAccordion;
8099 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
8105 }).directive('expanders', function () {
8110 template: "<div ng-transclude></div>",
8111 controller: ['$scope', function ($scope){
8112 var bodyScope = null;
8113 this.setScope = function (scope) {
8116 this.toggle = function () {
8117 $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;
8118 return bodyScope.isOpen;
8121 link: function (scope)
8123 scope.isOpen = false;
8126 }).directive('expanderHeading', function () {
8128 require: "^expanders",
8133 template: "<div style='padding:10px !important' ng-transclude></div>"
8135 }).directive('expanderBody', function () {
8138 require: "^expanders",
8142 template: "<div collapse='!isOpen'><div ng-transclude></div></div>",
8143 link: function (scope, elem, attr, myCtrl) {
8144 scope.isOpen = false;
8145 myCtrl.setScope(scope);
8148 }).directive('expanderToggle', function () {
8151 require: "^expanders",
8156 link: function (scope, element, attr, myCtrl)
8159 var setIcon = function () {
8160 if (scope.expandIcon && scope.collapseIcon)
8163 element.removeClass(scope.expandIcon);
8164 element.addClass(scope.collapseIcon);
8167 element.removeClass(scope.collapseIcon);
8168 element.addClass(scope.expandIcon);
8172 element.bind("keydown", function (e) {
8173 if (e.keyCode === 13)
8178 element.bind('click', function ()
8182 scope.toggleit = function ()
8184 isOpen = myCtrl.toggle();
8191 }).directive('collapse', ['$transition', function ($transition) {
8192 // CSS transitions don't work with height: auto, so we have to manually change the height to a
8193 // specific value and then once the animation completes, we can reset the height to auto.
8194 // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
8195 // "collapse") then you trigger a change to height 0 in between.
8196 // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
8202 paddingBottom: null,
8213 var fixUpHeight = function (scope, element, height) {
8214 // We remove the collapse CSS class to prevent a transition when we change to height: auto
8215 element.removeClass('collapse');
8216 element.css({height: height});
8217 //adjusting for any margin or padding
8219 element.css(props.closed);
8221 element.css(props.open);
8223 // It appears that reading offsetWidth makes the browser realise that we have changed the
8224 // height already :-/
8225 element.addClass('collapse');
8228 link: function (scope, element, attrs) {
8230 var initialAnimSkip = true;
8231 scope.$watch(function () {
8232 return element[0].scrollHeight;
8234 //The listener is called when scrollHeight changes
8235 //It actually does on 2 scenarios:
8236 // 1. Parent is set to display none
8237 // 2. angular bindings inside are resolved
8238 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
8239 if (element[0].scrollHeight !== 0 && !isCollapsed) {
8240 if (initialAnimSkip) {
8241 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
8243 fixUpHeight(scope, element, 'auto');
8247 var currentTransition;
8248 var doTransition = function (change) {
8249 if (currentTransition) {
8250 currentTransition.cancel();
8252 currentTransition = $transition(element, change);
8253 currentTransition.then(
8255 currentTransition = undefined;
8258 currentTransition = undefined;
8261 return currentTransition;
8263 var expand = function () {
8264 scope.postTransition = true;
8265 if (initialAnimSkip) {
8266 initialAnimSkip = false;
8268 fixUpHeight(scope, element, 'auto');
8271 doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
8273 // This check ensures that we don't accidentally update the height if the user has closed
8274 // the group while the animation was still running
8277 fixUpHeight(scope, element, 'auto');
8281 isCollapsed = false;
8283 var collapse = function () {
8285 if (initialAnimSkip) {
8286 initialAnimSkip = false;
8287 fixUpHeight(scope, element, 0);
8289 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
8290 doTransition(angular.extend({height: 0}, props.closed)).then(function () {
8291 scope.postTransition = false;
8295 scope.$watch(attrs.collapse, function (value) {
8305 .directive('attAccord', function () {
8311 controller: 'AttAccordCtrl',
8312 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html'
8315 .controller('AttAccordCtrl', [function () {
8316 this.type = 'attAccord';
8320 this.toggleBody = function () {
8325 this.collapseBody();
8329 this.expandBody = function () {
8330 this.bodyCtrl.expand();
8332 this.collapseBody = function () {
8333 this.bodyCtrl.collapse();
8336 .controller('AttAccordHeaderCtrl', [function () {
8337 this.type = 'header';
8339 .directive('attAccordHeader', ['keymap', 'events', function (keymap, events) {
8344 require: ['^attAccord', 'attAccordHeader'],
8345 controller: 'AttAccordHeaderCtrl',
8346 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html',
8347 link: function (scope, element, attr, ctrls) {
8348 var attAccordCtrl = ctrls[0];
8349 var attAccordHeaderCtrl = ctrls[1];
8350 attAccordCtrl.headerCtrl = attAccordHeaderCtrl;
8351 var tab = element.children().eq(0);
8353 scope.clickFunc = function () {
8354 attAccordCtrl.toggleBody();
8357 var handleKeydown = function (ev) {
8358 var boolFlag = true;
8361 case keymap.KEY.ENTER:
8362 ev.preventDefault();
8370 ev.stopPropagation();
8374 if (angular.isUndefined(scope.isOpen)) {
8375 scope.isOpen = false;
8378 tab.bind("keydown", handleKeydown);
8382 .controller('AttAccordBodyCtrl', ['$scope', function ($scope) {
8384 this.expand = function () {
8387 this.collapse = function () {
8391 .directive('attAccordBody', ['$timeout', '$height', function ($timeout, $height) {
8396 require: ['^attAccord', 'attAccordBody'],
8397 controller: 'AttAccordBodyCtrl',
8398 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordBody.html',
8399 link: function (scope, element, attr, ctrls) {
8400 var attAccordCtrl = ctrls[0];
8401 var attAccordBodyCtrl = ctrls[1];
8402 attAccordCtrl.bodyCtrl = attAccordBodyCtrl;
8404 $timeout(function () {
8405 originalHeight = element[0].offsetHeight;
8406 $height(element, 0, 0, 0);
8408 scope.expand = function () {
8409 $height(element, 0.05, originalHeight, 1);
8411 scope.collapse = function () {
8412 $height(element, 0.25, 0, 0);
8417 angular.module('att.abs.alert', [])
8418 .directive('attAlert', [function()
8425 alertType : "@type",
8426 showTop : "@topPos",
8429 templateUrl : 'app/scripts/ng_js_att_tpls/alert/alert.html',
8430 link: function(scope)
8432 if(scope.showTop === 'true'){
8433 scope.cssStyle = {'top':'50px'};
8436 scope.cssStyle = {'top':'0px'};
8438 scope.close = function(){
8439 scope.showAlert = false;
8445 angular.module('att.abs.boardStrip', ['att.abs.utilities'])
8446 .constant('BoardStripConfig', {
8447 'maxVisibleBoards': 4,
8448 'boardsToScroll': 1,
8449 /* These parameters are non-configurable and remain unaltered, until there is a change in corresponding SCSS */
8453 .directive('attBoard', [function() {
8458 require: '^attBoardStrip',
8463 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attBoard.html',
8464 link: function(scope, element, attrs, ctrls) {
8466 var parentCtrl = ctrls;
8468 scope.getCurrentIndex = function() {
8469 return parentCtrl.getCurrentIndex();
8471 scope.selectBoard = function(boardIndex) {
8472 if (!isNaN(boardIndex)) {
8473 parentCtrl.setCurrentIndex(boardIndex);
8476 scope.isInView = function(boardIndex) {
8477 return parentCtrl.isInView(boardIndex);
8482 .directive('attBoardStrip', ['BoardStripConfig', '$timeout', '$ieVersion', function(BoardStripConfig, $timeout, $ieVersion) {
8488 currentIndex: '=selectedIndex',
8489 boardsMasterArray : '=',
8492 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html',
8493 controller: function($scope) {
8494 if(!angular.isDefined($scope.boardsMasterArray)){
8495 $scope.boardsMasterArray = [];
8498 this.rectifyMaxVisibleBoards = function() {
8499 if (this.maxVisibleIndex >= $scope.boardsMasterArray.length) {
8500 this.maxVisibleIndex = $scope.boardsMasterArray.length - 1;
8503 if (this.maxVisibleIndex < 0) {
8504 this.maxVisibleIndex = 0;
8508 this.resetBoardStrip = function(){
8509 $scope.currentIndex = 0;
8511 this.maxVisibleIndex = BoardStripConfig.maxVisibleBoards-1;
8512 this.minVisibleIndex = 0;
8514 this.rectifyMaxVisibleBoards();
8518 if ($scope.currentIndex > 0) {
8519 var index = $scope.currentIndex;
8520 this.resetBoardStrip();
8521 if (index > $scope.boardsMasterArray.length) {
8522 $scope.currentIndex = $scope.boardsMasterArray.length-1;
8524 $scope.currentIndex = index;
8527 this.resetBoardStrip();
8531 this.getCurrentIndex = function() {
8532 return $scope.currentIndex;
8534 this.setCurrentIndex = function(indx) {
8535 $scope.currentIndex = indx;
8538 this.isInView = function(index) {
8539 return (index <= this.maxVisibleIndex && index >= this.minVisibleIndex);
8542 this.getBoardsMasterArrayLength = function() {
8543 return $scope.boardsMasterArray.length;
8546 link: function(scope, element, attrs, ctrl) {
8547 var ieVersion = $ieVersion();
8550 var animationTimeout = 1000;
8552 if(ieVersion && ieVersion < 10) {
8553 animationTimeout = 0;
8556 var getBoardViewportWidth = function (numberOfVisibleBoards) {
8557 return numberOfVisibleBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
8559 if(element[0].querySelector(".board-viewport")) {
8560 angular.element(element[0].querySelector(".board-viewport")).css({"width": getBoardViewportWidth(BoardStripConfig.maxVisibleBoards) + "px"});
8563 var getBoardstripContainerWidth = function (totalNumberOfBoards) {
8564 return totalNumberOfBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
8566 if(element[0].querySelector(".boardstrip-container")) {
8567 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8568 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": "0px"});
8571 var calculateAndGetBoardstripContainerAdjustment = function () {
8573 var calculatedAdjustmentValue;
8575 if(ctrl.getBoardsMasterArrayLength() <= BoardStripConfig.maxVisibleBoards) {
8576 calculatedAdjustmentValue = 0;
8579 calculatedAdjustmentValue = (ctrl.minVisibleIndex * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin))* -1;
8582 return calculatedAdjustmentValue;
8585 var updateBoardsTabIndex = function(boardArray, minViewIndex, maxViewIndex) {
8586 for (var i = 0; i < boardArray.length; i++) {
8587 angular.element(boardArray[i]).attr('tabindex', '-1');
8589 for (var i = minViewIndex; i <= maxViewIndex; i++) {
8590 angular.element(boardArray[i]).attr('tabindex', '0');
8594 scope.$watchCollection('boardsMasterArray', function(newVal, oldVal){
8595 if(newVal !== oldVal){
8596 /* When a board is removed */
8597 if(newVal.length < oldVal.length){
8598 ctrl.resetBoardStrip();
8599 $timeout(function(){
8601 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8602 if(currentBoardArray.length !== 0) {
8604 var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
8605 var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
8606 if(oldContainerAdjustment !== containerAdjustment+'px') {
8607 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": containerAdjustment + "px"});
8609 $timeout.cancel(oldTimeout);
8610 oldTimeout = $timeout(function(){
8611 currentBoardArray[0].focus();
8612 }, animationTimeout);
8615 currentBoardArray[0].focus();
8619 element[0].querySelector('div.boardstrip-item--add').focus();
8622 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8625 /* When a board is added */
8627 ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength()-1;
8628 ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
8630 ctrl.setCurrentIndex(ctrl.maxVisibleIndex);
8632 $timeout(function(){
8633 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8635 var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
8636 var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
8637 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8638 if(oldContainerAdjustment !== containerAdjustment+'px') {
8639 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": containerAdjustment + "px"});
8641 $timeout.cancel(oldTimeout);
8642 oldTimeout = $timeout(function(){
8643 currentBoardArray[currentBoardArray.length-1].focus();
8644 }, animationTimeout);
8647 currentBoardArray[currentBoardArray.length-1].focus();
8649 /* Update tabindecies to ensure keyboard navigation behaves correctly */
8650 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8656 scope.nextBoard = function() {
8657 ctrl.maxVisibleIndex += BoardStripConfig.boardsToScroll;
8658 ctrl.rectifyMaxVisibleBoards();
8659 ctrl.minVisibleIndex = ctrl.maxVisibleIndex - (BoardStripConfig.maxVisibleBoards-1);
8661 $timeout.cancel(oldTimeout);
8662 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": calculateAndGetBoardstripContainerAdjustment() + "px"});
8664 $timeout(function(){
8665 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8667 /* Remove tabindex from non-visible boards */
8668 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8670 if (!(scope.isNextBoard())) {
8672 currentBoardArray[currentBoardArray.length-1].focus();
8675 }, animationTimeout);
8677 scope.prevBoard = function() {
8679 ctrl.minVisibleIndex -= BoardStripConfig.boardsToScroll;
8680 if (ctrl.minVisibleIndex < 0) {
8681 ctrl.minVisibleIndex = 0;
8684 ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards-1;
8685 ctrl.rectifyMaxVisibleBoards();
8687 $timeout.cancel(oldTimeout);
8688 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": calculateAndGetBoardstripContainerAdjustment() + "px"});
8690 $timeout(function(){
8691 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8693 /* Remove tabindex from non-visible boards */
8694 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8696 if (ctrl.minVisibleIndex === 0) {
8698 element[0].querySelector('div.boardstrip-item--add').focus();
8699 } catch (e) {} /* IE8 may throw exception */
8704 scope.isPrevBoard = function() {
8705 return (ctrl.minVisibleIndex > 0);
8707 scope.isNextBoard = function() {
8708 return (ctrl.getBoardsMasterArrayLength()-1 > ctrl.maxVisibleIndex);
8713 .directive('attAddBoard', ['BoardStripConfig', '$parse', '$timeout', function(BoardStripConfig, $parse, $timeout) {
8717 require: '^attBoardStrip',
8721 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html',
8722 link: function(scope, element, attrs, ctrls) {
8723 var parentCtrl = ctrls;
8724 scope.addBoard = function() {
8725 if (attrs['onAddBoard'] ) {
8726 scope.onAddBoard = $parse(scope.onAddBoard);
8733 .directive('attBoardNavigation', ['keymap', 'events', function(keymap, events) {
8736 link: function(scope, elem) {
8738 var prevElem = keymap.KEY.LEFT;
8739 var nextElem = keymap.KEY.RIGHT;
8741 elem.bind('keydown', function (ev) {
8743 if (!(ev.keyCode)) {
8744 ev.keyCode = ev.which;
8747 switch (ev.keyCode) {
8749 events.preventDefault(ev);
8750 events.stopPropagation(ev);
8752 if (elem[0].nextElementSibling && parseInt(angular.element(elem[0].nextElementSibling).attr('tabindex')) >= 0) {
8753 angular.element(elem[0])[0].nextElementSibling.focus();
8756 var el = angular.element(elem[0])[0];
8758 if (el.nextSibling){
8759 el = el.nextSibling;
8764 } while (el && el.tagName !== 'LI');
8766 if (el.tagName && el.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0){
8773 events.preventDefault(ev);
8774 events.stopPropagation(ev);
8776 if (elem[0].previousElementSibling && parseInt(angular.element(elem[0].previousElementSibling).attr('tabindex')) >= 0) {
8777 angular.element(elem[0])[0].previousElementSibling.focus();
8780 var el1 = angular.element(elem[0])[0];
8782 if (el1.previousSibling){
8783 el1 = el1.previousSibling;
8788 } while (el1 && el1.tagName !== 'LI');
8790 if (el1.tagName && el1.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0){
8803 angular.module('att.abs.breadCrumbs', [])
8804 .constant("classConstant",{
8805 "defaultClass" : "breadcrumbs__link",
8806 "activeClass": "breadcrumbs__link--active"
8808 .directive('attCrumb', ['classConstant', function(classConstant) {
8811 link: function(scope, elem, attr) {
8812 elem.addClass(classConstant.defaultClass);
8813 if(attr.attCrumb === 'active'){
8814 elem.addClass(classConstant.activeClass);
8816 if(!elem.hasClass('last')){
8817 elem.after('<i class="breadcrumbs__item"></i>');
8823 angular.module('att.abs.buttons', ['att.abs.position', 'att.abs.utilities'])
8824 .constant('btnConfig', {
8826 btnPrimaryClass: 'button--primary',
8827 btnSecondaryClass: 'button--secondary',
8828 btnDisabledClass: 'button--inactive',
8829 btnSmallClass: 'button--small'
8831 .directive('attButton', ['btnConfig', function (btnConfig) {
8834 link: function (scope, element, attrs) {
8835 element.addClass(btnConfig.btnClass);
8836 if (attrs.size === 'small') {
8837 element.addClass(btnConfig.btnSmallClass);
8839 attrs.$observe('btnType', function (value) {
8840 if (value === 'primary') {
8841 element.addClass(btnConfig.btnPrimaryClass);
8842 element.removeClass(btnConfig.btnSecondaryClass);
8843 element.removeClass(btnConfig.btnDisabledClass);
8844 element.removeAttr('disabled');
8845 } else if (value === 'secondary') {
8846 element.addClass(btnConfig.btnSecondaryClass);
8847 element.removeClass(btnConfig.btnPrimaryClass);
8848 element.removeClass(btnConfig.btnDisabledClass);
8849 element.removeAttr('disabled');
8850 } else if (value === 'disabled') {
8851 element.addClass(btnConfig.btnDisabledClass);
8852 element.removeClass(btnConfig.btnPrimaryClass);
8853 element.removeClass(btnConfig.btnSecondaryClass);
8854 element.attr('disabled', 'disabled');
8860 .directive('attButtonLoader', [function () {
8867 template: '<div ng-class="{\'button--loading\': size === \'large\',\'button--loading__small\': size === \'small\'}"><i></i><i class="second__loader"></i><i></i></div>',
8868 link: function (scope, element) {
8869 element.addClass('button button--inactive');
8873 .directive('attButtonHero', [function () {
8881 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>',
8882 link: function (scope, element) {
8883 element.addClass('button button--hero');
8884 element.attr("tabindex", "0");
8888 .directive('attBtnDropdown', ['$document', '$timeout', '$isElement', '$documentBind', 'keymap', 'events', function ($document, $timeout, $isElement, $documentBind, keymap, events) {
8892 type: "@dropdowntype"
8896 templateUrl: 'app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html',
8897 link: function (scope, element) {
8898 scope.isOpen = false;
8899 var currentIndex = -1;
8900 // Capture all the li elements after compilation
8901 var list = [], button = undefined;
8902 $timeout(function() {
8903 list = element.find('li');
8904 button = element.find('button')[0];
8906 var toggle = scope.toggle = function (show) {
8907 if (angular.isUndefined(show) || show === '') {
8908 scope.isOpen = !scope.isOpen;
8911 scope.isOpen = show;
8914 var selectNext = function() {
8915 if (currentIndex+1 < list.length) {
8917 list[currentIndex].focus();
8920 var selectPrev = function() {
8921 if (currentIndex-1 >= 0) {
8923 list[currentIndex].focus();
8926 element.bind("keydown", function($event) {
8927 var keyCode = $event.keyCode;
8928 if (keymap.isAllowedKey(keyCode) || keymap.isControl($event) || keymap.isFunctionKey($event)) {
8930 case keymap.KEY.ENTER:
8931 if (currentIndex > 0) {
8936 case keymap.KEY.ESC:
8942 case keymap.KEY.DOWN:
8945 events.preventDefault($event);
8946 events.stopPropagation($event);
8951 events.preventDefault($event);
8952 events.stopPropagation($event);
8957 } else if (keyCode === keymap.KEY.TAB) {
8963 var outsideClick = function (e) {
8964 var isElement = $isElement(angular.element(e.target), element, $document);
8968 for (var i = 0; i < list.length; i++) {
8969 angular.element(list[i]).removeClass('selected');
8975 $documentBind.click('isOpen', outsideClick, scope);
8979 angular.module('att.abs.checkbox', [])
8980 .constant("attCheckboxConfig", {
8981 activeClass : "att-checkbox--on",
8982 disabledClass : "att-checkbox--disabled"
8984 .directive('checkboxLimit', function () {
8992 require:'checkboxLimit',
8993 controller: ['$scope',function($scope)
8996 this.getMaxLimits=function(){
8997 return $scope.limit;
8999 this.setMaxLimits=function(value){
9002 this.maxCheckboxSelected=function(){
9003 $scope.maxSelected();
9006 link: function (scope, element, attribute, ctrl) {
9007 scope.$watch('checkboxLimit', function()
9010 for (var keys in scope.checkboxLimit) {
9011 if (scope.checkboxLimit.hasOwnProperty(keys) && scope.checkboxLimit[keys]) {
9012 countTrue = countTrue + 1;
9015 if(countTrue>=parseInt(scope.selectLimit)){
9016 ctrl.setMaxLimits(false);
9019 ctrl.setMaxLimits(true);
9025 .directive('attCheckbox', ['$compile', "attCheckboxConfig", function ($compile, attCheckboxConfig) {
9029 require: ['ngModel','^?checkboxLimit'],
9030 link: function (scope, element, attribute, ctrl) {
9031 var ngCtrl = ctrl[0];
9032 var checkboxLimitCtrl = ctrl[1];
9033 var parentDiv = $compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" aria-label="Checkbox" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope);
9034 element.css({display:'none'});
9035 element.wrap(parentDiv);
9036 element.parent().append('<div class="att-checkbox__indicator"></div>');
9037 element.parent().attr("title", attribute.title);
9038 element.parent().attr("aria-label", attribute.title);
9039 element.parent().attr("id", attribute.id);
9040 element.removeAttr("id");
9041 //element.removeAttr("title");
9043 ngCtrl.$render = function () {
9044 var selected = ngCtrl.$modelValue ? true : false;
9045 element.parent().toggleClass(attCheckboxConfig.activeClass, selected);
9046 element.parent().attr("aria-checked", selected);
9050 scope.updateModel = function (evt) {
9051 if (!scope.disabled) {
9052 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? false : true);
9053 if(checkboxLimitCtrl && !(checkboxLimitCtrl.getMaxLimits())){
9054 if(!ngCtrl.$modelValue){
9058 checkboxLimitCtrl.maxCheckboxSelected();
9059 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? true : false);
9066 evt.preventDefault();
9069 attribute.$observe('disabled', function(val) {
9070 scope.disabled = (val || val === "disabled" || val === "true");
9071 element.parent().toggleClass(attCheckboxConfig.disabledClass, scope.disabled);
9072 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
9077 .directive('checkboxGroup', ['$compile',function($compile) {
9081 checkboxGroupValue: "=?"
9084 link: function(scope, element, attribute){
9085 scope.checkboxState = 'none';
9086 if (scope.checkboxGroupValue === undefined) {
9087 scope.checkboxGroupValue = "indeterminate";
9089 element.css({display:'none'});
9090 element.wrap($compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope));
9091 element.parent().append('<div class="att-checkbox__indicator"></div>');
9092 element.parent().attr("title", attribute.title);
9093 element.parent().attr("aria-label", attribute.title);
9094 scope.$watch('checkboxState', function(val) {
9095 if (val === 'all') {
9096 element.parent().addClass('att-checkbox--on');
9097 element.parent().removeClass('att-checkbox--indeterminate');
9098 element.parent().attr("aria-checked", true);
9100 else if (val === 'none') {
9101 element.parent().removeClass('att-checkbox--on');
9102 element.parent().removeClass('att-checkbox--indeterminate');
9103 element.parent().attr("aria-checked", false);
9105 else if (val === 'indeterminate') {
9106 element.parent().removeClass('att-checkbox--on');
9107 element.parent().addClass('att-checkbox--indeterminate');
9108 element.parent().attr("aria-checked", true);
9111 scope.updateModel = function(evt){
9112 if (element.parent().hasClass('att-checkbox--on')) {
9113 element.parent().removeClass('att-checkbox--on');
9114 for (var keys in scope.checkboxGroup) {
9115 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9116 scope.checkboxGroup[keys] = false;
9121 element.parent().addClass('att-checkbox--on');
9122 for (var key in scope.checkboxGroup) {
9123 if (scope.checkboxGroup.hasOwnProperty(key)) {
9124 scope.checkboxGroup[key] = true;
9128 evt.preventDefault();
9130 scope.$watch('checkboxGroupValue', function (value) {
9131 if (value===false) {
9132 element.parent().removeClass('att-checkbox--on');
9133 for (var keys in scope.checkboxGroup) {
9134 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9135 scope.checkboxGroup[keys] = false;
9139 else if (value === true){
9140 element.parent().addClass('att-checkbox--on');
9141 for (var key in scope.checkboxGroup) {
9142 if (scope.checkboxGroup.hasOwnProperty(key)) {
9143 scope.checkboxGroup[key] = true;
9148 scope.$watch('checkboxGroup', function(){
9152 for (var keys in scope.checkboxGroup) {
9153 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9155 if (scope.checkboxGroup[keys]) {
9156 countTrue = countTrue + 1;
9158 else if (!scope.checkboxGroup[keys]) {
9159 countFalse = countFalse + 1;
9163 if (count === countTrue) {
9164 scope.checkboxState = "all";
9165 scope.checkboxGroupValue=true;
9167 else if (count === countFalse) {
9168 scope.checkboxState = "none";
9169 scope.checkboxGroupValue=false;
9172 scope.checkboxState = "indeterminate";
9173 scope.checkboxGroupValue="indeterminate";
9180 angular.module('att.abs.colorselector', [])
9181 .directive('colorSelectorWrapper', [function() {
9190 templateUrl: 'app/scripts/ng_js_att_tpls/colorselector/colorselector.html',
9191 link: function(scope) {
9192 scope.applycolor = {'background-color': scope.iconColor};
9193 scope.selectedcolor = function(iconColor) {
9194 scope.selected = iconColor;
9199 .directive('colorSelector', ['$compile', function($compile) {
9206 link: function(scope, element, attr) {
9207 element.removeAttr('color-selector');
9208 var colorTitle = attr.title;
9209 var wrapcont = angular.element('<color-selector-wrapper selected="ngModel" title="' + colorTitle + '" icon-color="{{colorSelector}}">' + element.prop('outerHTML') + '</color-selector-wrapper>');
9210 var newWrapcont = $compile(wrapcont)(scope);
9211 element.replaceWith(newWrapcont);
9215 angular.module('att.abs.datepicker', ['att.abs.position', 'att.abs.utilities'])
9217 .constant('datepickerConfig', {
9218 dateFormat: 'MM/dd/yyyy',
9220 monthFormat: 'MMMM',
9222 dayHeaderFormat: 'EEEE',
9223 dayTitleFormat: 'MMMM yyyy',
9224 disableWeekend: false,
9225 disableSunday: false,
9231 defaultText: 'Select from list'
9233 datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'mode'],
9234 datepickerWatchAttributes: ['min', 'max']
9237 .factory('datepickerService', ['datepickerConfig', 'dateFilter', function (datepickerConfig, dateFilter) {
9238 var setAttributes = function (attr, elem) {
9239 if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
9240 var attributes = datepickerConfig.datepickerEvalAttributes.concat(datepickerConfig.datepickerWatchAttributes);
9241 for (var key in attr) {
9242 var val = attr[key];
9243 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9244 elem.attr(key.toSnakeCase(), key);
9250 var bindScope = function (attr, scope) {
9251 if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
9252 var evalFunction = function (key, val) {
9253 scope[key] = scope.$parent.$eval(val);
9256 var watchFunction = function (key, val) {
9257 scope.$parent.$watch(val, function (value) {
9260 scope.$watch(key, function (value) {
9261 scope.$parent[val] = value;
9265 var evalAttributes = datepickerConfig.datepickerEvalAttributes;
9266 var watchAttributes = datepickerConfig.datepickerWatchAttributes;
9267 for (var key in attr) {
9268 var val = attr[key];
9269 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9270 evalFunction(key, val);
9271 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9272 watchFunction(key, val);
9278 var validateDateString = function (dateString, dateFormat) {
9279 if (dateString && dateFormat) {
9281 if (dateFormat.indexOf('/') !== -1) {
9283 } else if (dateFormat.indexOf('-') !== -1) {
9285 } else if (dateFormat.indexOf('.') !== -1) {
9289 var dateStringArray = dateString.split(delimiter);
9290 var dateFormatArray = dateFormat.split(delimiter);
9291 if (dateStringArray.length !== dateFormatArray.length) {
9295 for (var i = 0; i < dateStringArray.length; i++) {
9296 dateStringArray[i] = dateStringArray[i].lPad(dateFormatArray[i].length, '0');
9298 var intermediateDateString = dateStringArray.join(delimiter);
9300 var actualDateString = dateFilter(new Date(intermediateDateString), dateFormat);
9301 return intermediateDateString === actualDateString;
9306 setAttributes: setAttributes,
9307 bindScope: bindScope,
9308 validateDateString: validateDateString
9312 .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
9314 date: getValue($attrs.dateFormat, dtConfig.dateFormat),
9315 day: getValue($attrs.dayFormat, dtConfig.dayFormat),
9316 month: getValue($attrs.monthFormat, dtConfig.monthFormat),
9317 year: getValue($attrs.yearFormat, dtConfig.yearFormat),
9318 dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
9319 dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
9320 disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
9321 disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
9323 startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
9324 $scope.mode = getValue($attrs.mode, dtConfig.mode);
9326 $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
9327 $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
9329 function getValue(value, defaultValue) {
9330 return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
9333 function getDaysInMonth(year, month) {
9334 return new Date(year, month, 0).getDate();
9337 function getDates(startDate, n) {
9339 var current = startDate, i = 0;
9341 dates[i++] = new Date(current);
9342 current.setDate(current.getDate() + 1);
9347 var compare = this.compare = function(date1, date2) {
9348 return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
9351 function isSelected(dt) {
9352 if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
9358 function isFromDate(dt) {
9359 if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
9365 function isToDate(dt) {
9366 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
9372 function isDateRange(dt) {
9373 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
9379 function isWeekend(date) {
9380 if (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday") {
9386 function isToday(date) {
9387 if (compare(date, $scope.resetTime(new Date())) === 0) {
9392 function isFocused(date) {
9393 if (date && angular.isDate($scope.focusedDate) && compare(date, $scope.focusedDate) === 0) {
9399 var isDisabled = this.isDisabled = function(date) {
9400 if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
9403 if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
9406 return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0));
9410 function isMinDateAvailable(startDate, endDate) {
9411 return ($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime());
9414 function isMaxDateAvailable(startDate, endDate) {
9415 return ($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime());
9418 function getLabel(label) {
9422 pre: label.substr(0, 3),
9429 function makeDate(dateobj) {
9430 return {date: dateobj.date, label: dateFilter(dateobj.date, dateobj.formatDay), header: dateFilter(dateobj.date, dateobj.formatHeader), focused: !!dateobj.isFocused, selected: !!dateobj.isSelected, from: !!dateobj.isFromDate, to: !!dateobj.isToDate, dateRange: !!dateobj.isDateRange, oldMonth: !!dateobj.oldMonth, nextMonth: !!dateobj.newMonth, disabled: !!dateobj.isDisabled, today: !!dateobj.isToday, weekend: !!dateobj.isWeakend};
9436 getVisibleDates: function(date, calendar) {
9437 var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1), lastDayOfMonth = new Date(year, month+1, 0);
9438 var difference = startingDay - firstDayOfMonth.getDay(),
9439 numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
9440 firstDate = new Date(firstDayOfMonth), numDates = 0;
9442 if (numDisplayedFromPreviousMonth > 0) {
9443 firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
9444 numDates += numDisplayedFromPreviousMonth; // Previous
9446 numDates += getDaysInMonth(year, month + 1); // Current
9447 numDates += (7 - numDates % 7) % 7; // Next
9449 var days = getDates(firstDate, numDates), labels = [];
9450 for (var i = 0; i < numDates; i++) {
9451 var dt = new Date(days[i]);
9452 days[i] = makeDate({date:dt,
9453 formatDay:format.day,
9454 formatHeader:format.dayHeader,
9455 isFocused:isFocused(dt),
9456 isSelected:isSelected(dt),
9457 isFromDate:isFromDate(dt),
9458 isToDate:isToDate(dt),
9459 isDateRange:isDateRange(dt),
9460 oldMonth:(new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() < new Date(year, month, 1, 0, 0, 0).getTime()),
9461 newMonth:(new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() > new Date(year, month, 1, 0, 0, 0).getTime()),
9462 isDisabled:isDisabled(dt),
9463 isToday:isToday(dt),
9464 isWeakend:isWeekend(dt)});
9466 for (var j = 0; j < 7; j++) {
9467 labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
9469 if (calendar === 'top') {
9470 $scope.disablePrevTop = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9471 $scope.disableNextTop = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9472 } else if (calendar === 'bottom') {
9473 $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9474 $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9476 $scope.disablePrevTop = $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9477 $scope.disableNextTop = $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9479 $scope.disablePrev = $scope.disablePrevTop || $scope.disablePrevBottom;
9480 $scope.disableNext = $scope.disableNextTop || $scope.disableNextBottom;
9481 return {objects: days, title: dateFilter(date, format.dayTitle), labels: labels};
9488 getVisibleDates: function(date) {
9489 var months = [], labels = [], year = date.getFullYear();
9490 for (var i = 0; i < 12; i++) {
9491 var dt = new Date(year,i,1);
9492 months[i] = makeDate({date:dt,
9493 formatDay:format.month,
9494 formatHeader:format.month,
9495 isFocused:isFocused(dt),
9496 isSelected:isSelected(dt),
9497 isFromDate:isFromDate(dt),
9498 isToDate:isToDate(dt),
9499 isDateRange:isDateRange(dt),
9502 isDisabled:isDisabled(dt),
9503 isToday:isToday(dt),
9506 return {objects: months, title: dateFilter(date, format.year), labels: labels};
9515 .directive('datepicker', ['$timeout', function ($timeout) {
9520 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepicker.html',
9522 currentDate: "=?current",
9525 require: 'datepicker',
9526 controller: 'DatepickerController',
9527 link: function(scope, element, attrs, ctrl) {
9528 var datepickerCtrl = ctrl;
9529 var selected, calendarSelected = false;
9532 scope.resetTime = function(date) {
9534 if (!isNaN(new Date(date))) {
9535 dt = new Date(date);
9536 if(scope.mode === 1){
9537 dt = new Date(dt.getFullYear(), dt.getMonth());
9539 dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9548 scope.$parent.$watch(attrs.min, function(value) {
9549 scope.minDate = value ? scope.resetTime(value) : null;
9554 scope.$parent.$watch(attrs.max, function(value) {
9555 scope.maxDate = value ? scope.resetTime(value) : null;
9560 // Split array into smaller arrays
9561 function split(arr, size) {
9563 while (arr.length > 0) {
9564 arrays.push(arr.splice(0, size));
9568 var moveMonth = function(selectedDate, direction) {
9569 var step = datepickerCtrl.modes[scope.mode].step;
9570 selectedDate.setDate(1);
9571 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
9572 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
9574 return selectedDate;
9577 function refill(date) {
9578 if (angular.isDate(date) && !isNaN(date)) {
9579 selected = new Date(date);
9582 selected = new Date();
9587 var selectedCalendar;
9588 if(scope.mode === 1){
9589 selected = new Date();
9590 selectedCalendar = moveMonth(angular.copy(selected), -1);
9592 selectedCalendar = angular.copy(selected);
9595 var currentMode = datepickerCtrl.modes[scope.mode];
9596 var currentData = currentMode.getVisibleDates(selectedCalendar, 'top');
9597 scope.currentRows = split(currentData.objects, currentMode.split);
9598 scope.currentTitle = currentData.title;
9599 scope.labels = currentData.labels || [];
9601 var nextData = currentMode.getVisibleDates(moveMonth(angular.copy(selectedCalendar), 1), 'bottom');
9602 scope.nextRows = split(nextData.objects, currentMode.split);
9603 scope.nextTitle = nextData.title;
9607 var selectCurrentDate = function(date) {
9608 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
9609 scope.currentDate = dt;
9612 var selectFromDate = function(date) {
9613 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
9614 scope.fromDate = dt;
9617 scope.select = function(date) {
9618 calendarSelected = true;
9620 if(!(angular.isDate(scope.fromDate) && angular.isDate(scope.currentDate))) {
9621 if(angular.isDate(scope.fromDate)) {
9622 selectCurrentDate(date);
9623 } else if(!angular.isDate(scope.fromDate)) {
9624 selectFromDate(date);
9628 selectCurrentDate(date);
9630 scope.focusedDate = date;
9633 var swapDate = function(fromDate, currentDate) {
9634 selectFromDate(currentDate);
9635 $timeout(function () {
9636 calendarSelected = true;
9637 scope.focusedDate = currentDate;
9638 selectCurrentDate(fromDate);
9642 scope.move = function(direction) {
9643 selected = moveMonth(angular.copy(selected), direction);
9647 scope.$watch('currentDate', function (value) {
9648 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
9649 scope.currentDate = null;
9653 if (attrs.from && !isNaN(value) && !isNaN(scope.fromDate) && datepickerCtrl.compare(value, scope.fromDate) < 0) {
9654 swapDate(scope.fromDate, value);
9658 if (calendarSelected) {
9660 calendarSelected = false;
9662 if (angular.isDefined(value) && value !== null) {
9668 scope.focusedDate = undefined;
9671 scope.$watch('fromDate', function (value) {
9672 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
9673 scope.fromDate = null;
9677 if (!isNaN(scope.currentDate) && !isNaN(value) && datepickerCtrl.compare(scope.currentDate, value) < 0) {
9678 swapDate(value, scope.currentDate);
9681 if (calendarSelected) {
9683 calendarSelected = false;
9685 if (angular.isDefined(value) && value !== null) {
9692 scope.focusedDate = undefined;
9697 .directive('datepickerPopup', ['$document', 'datepickerService', '$isElement', '$documentBind', function($document, datepickerService, $isElement, $documentBind) {
9698 var link = function (scope, elem, attr) {
9699 datepickerService.bindScope(attr, scope);
9701 scope.isOpen = false;
9703 var toggle = scope.toggle = function (show) {
9704 if(show === true || show === false) {
9705 scope.isOpen = show;
9707 scope.isOpen = !scope.isOpen;
9711 scope.$watch('current', function () {
9715 var outsideClick = function (e) {
9716 var isElement = $isElement(angular.element(e.target), elem, $document);
9723 $documentBind.click('isOpen', outsideClick, scope);
9730 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html',
9734 compile: function (elem, attr) {
9735 var wrapperElement = elem.find('span').eq(1);
9736 wrapperElement.attr('current', 'current');
9737 datepickerService.setAttributes(attr, wrapperElement);
9744 .directive('attDatepicker', ['$log', function($log) {
9749 controller: ['$scope', '$element', '$attrs', '$compile', 'datepickerConfig', 'datepickerService', function($scope, $element, $attrs, $compile, datepickerConfig, datepickerService) {
9750 var dateFormatString = angular.isDefined($attrs.dateFormat) ? $scope.$parent.$eval($attrs.dateFormat) : datepickerConfig.dateFormat;
9751 var selectedDateMessage = '<div class="sr-focus hidden-spoken" tabindex="-1">the date you selected is {{$parent.current | date : \'' + dateFormatString + '\'}}</div>';
9753 $element.removeAttr('att-datepicker');
9754 $element.removeAttr('ng-model');
9755 $element.attr('ng-model', '$parent.current');
9756 $element.attr('aria-describedby', 'datepicker');
9757 $element.attr('format-date', dateFormatString);
9758 $element.attr('att-input-deny', '[^0-9\/-]');
9759 $element.attr('maxlength', 10);
9760 $element.attr('readonly', 'readonly'); //Trinity for CATO
9761 var wrapperElement = angular.element('<div></div>');
9762 wrapperElement.attr('datepicker-popup', '');
9763 wrapperElement.attr('current', 'current');
9765 datepickerService.setAttributes($attrs, wrapperElement);
9766 datepickerService.bindScope($attrs, $scope);
9768 wrapperElement.html('');
9769 wrapperElement.append($element.prop('outerHTML'));
9770 if (navigator.userAgent.match(/MSIE 8/) === null) {
9771 wrapperElement.append(selectedDateMessage);
9773 var elm = wrapperElement.prop('outerHTML');
9774 elm = $compile(elm)($scope);
9775 $element.replaceWith(elm);
9777 link: function(scope, elem, attr, ctrl) {
9779 // do nothing if no ng-model
9780 $log.error("ng-model is required.");
9784 scope.$watch('current', function(value) {
9785 ctrl.$setViewValue(value);
9787 ctrl.$render = function() {
9788 scope.current = ctrl.$viewValue;
9794 .directive('formatDate', ['dateFilter', 'datepickerService', function(dateFilter, datepickerService) {
9798 link: function(scope, elem, attr, ctrl) {
9799 var formatDate = "";
9800 attr.$observe('formatDate', function (value) {
9803 var dateToString = function(value) {
9805 ctrl.$setValidity('invalidDate', true);
9806 return dateFilter(value, formatDate);
9808 ctrl.$setValidity('invalidDate', false);
9812 var stringToDate = function(value) {
9813 if(datepickerService.validateDateString(value, formatDate)) {
9814 ctrl.$setValidity('invalidDate', true);
9815 return new Date(value);
9817 ctrl.$setValidity('invalidDate', false);
9821 ctrl.$formatters.unshift(dateToString);
9822 ctrl.$parsers.unshift(stringToDate);
9827 .directive('attDateFilter', ['$document', 'dateFilter', 'datepickerConfig', 'datepickerService', '$isElement', '$documentBind', function($document, dateFilter, datepickerConfig, datepickerService, $isElement, $documentBind) {
9829 var link = function (scope, elem, attr, ctrl) {
9830 datepickerService.bindScope(attr, scope);
9832 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9833 scope.showDropdownList = false;
9834 scope.showCalendar = false;
9835 scope.applyButtonType = "disabled";
9837 scope.currentSelection = "";
9838 var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : datepickerConfig.dateFormat;
9839 var inputChange = false;
9841 var setDropdownText = function(value) {
9846 var fromDateText = dateFormatString.toUpperCase();
9847 var currentDateText = dateFormatString.toUpperCase();
9849 if(!isNaN(new Date(scope.fromDate))) {
9850 fromDateText = dateFilter(scope.fromDate, dateFormatString);
9852 if(!isNaN(new Date(scope.currentDate))) {
9853 currentDateText = dateFilter(scope.currentDate, dateFormatString);
9856 if(value === 'Custom Single Date') {
9857 ctrl.$setValidity('invalidDate', true);
9858 scope.maxLength = 10;
9859 scope.selectedOption = currentDateText;
9860 } else if(value === 'Custom Range') {
9861 ctrl.$setValidity('invalidDate', true);
9862 ctrl.$setValidity('invalidDateRange', true);
9863 scope.maxLength = 21;
9864 scope.selectedOption = fromDateText + '-' + currentDateText;
9868 var clear = scope.clear = function(partial) {
9869 scope.fromDate = undefined;
9870 scope.currentDate = undefined;
9871 scope.applyButtonType = "disabled";
9873 ctrl.$setValidity('invalidDate', true);
9874 ctrl.$setValidity('invalidDateRange', true);
9875 setDropdownText(scope.currentSelection);
9879 var showCalendar = function() {
9880 scope.showCalendar = true;
9883 var hideCalendar = function() {
9884 scope.showCalendar = false;
9885 if(scope.currentSelection !== 'Custom Single Date' && scope.currentSelection !== 'Custom Range') {
9890 var showDropdown = scope.showDropdown = function (show) {
9891 if(show === true || show === false) {
9892 scope.showDropdownList = show;
9894 scope.showDropdownList = !scope.showDropdownList;
9897 if (!scope.showDropdownList) {
9898 scope.focusInputButton = true;
9901 if (scope.currentSelection === 'Custom Single Date' || scope.currentSelection === 'Custom Range') {
9907 scope.resetTime = function(date) {
9909 if (!isNaN(new Date(date))) {
9910 dt = new Date(date);
9914 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9917 scope.getDropdownText = function () {
9919 var dropdownText = scope.selectedOption;
9921 if (scope.currentSelection === 'Custom Single Date') {
9922 if (!isNaN(new Date(dropdownText)) && datepickerService.validateDateString(dropdownText, dateFormatString)) {
9923 ctrl.$setValidity('invalidDate', true);
9924 scope.fromDate = undefined;
9925 scope.currentDate = new Date(dropdownText);
9927 ctrl.$setValidity('invalidDate', false);
9930 } else if (scope.currentSelection === 'Custom Range') {
9931 if (dropdownText.indexOf('-') !== -1 && (dropdownText.split('-').length === 2 || dropdownText.split('-').length === 6)) {
9932 ctrl.$setValidity('invalidDateRange', true);
9933 var resultDropdownText = dropdownText.split('-');
9934 if (resultDropdownText.length === 2) {
9935 resultDropdownText[0] = resultDropdownText[0].trim();
9936 resultDropdownText[1] = resultDropdownText[1].trim();
9937 } else if (resultDropdownText.length === 6) {
9938 var firstDateString = resultDropdownText[0].trim() + '-' + resultDropdownText[1].trim() + '-' + resultDropdownText[2].trim();
9939 var secondDateString = resultDropdownText[3].trim() + '-' + resultDropdownText[4].trim() + '-' + resultDropdownText[5].trim();
9940 resultDropdownText[0] = firstDateString;
9941 resultDropdownText[1] = secondDateString;
9944 if (!isNaN(new Date(resultDropdownText[0])) && !isNaN(new Date(resultDropdownText[1])) && datepickerService.validateDateString(resultDropdownText[0], dateFormatString) && datepickerService.validateDateString(resultDropdownText[1], dateFormatString)) {
9945 ctrl.$setValidity('invalidDate', true);
9946 var fromDate = new Date(resultDropdownText[0]);
9947 var currentDate = new Date(resultDropdownText[1]);
9948 if(fromDate.getTime() < currentDate.getTime()) {
9949 ctrl.$setValidity('invalidDateRange', true);
9950 scope.fromDate = fromDate;
9951 scope.currentDate = currentDate;
9953 ctrl.$setValidity('invalidDateRange', false);
9957 ctrl.$setValidity('invalidDate', false);
9961 ctrl.$setValidity('invalidDateRange', false);
9967 scope.untrackInputChange = function() {
9968 inputChange = false;
9971 scope.selectAdvancedOption = function (value, notClearFlag) {
9972 scope.currentSelection = value;
9977 scope.$watch('currentDate', function(val) {
9978 if(!isNaN(new Date(val))) {
9979 scope.applyButtonType = "primary";
9980 setDropdownText(value);
9982 scope.focusApplyButton = true;
9986 scope.$watch('fromDate', function(val) {
9987 if(!isNaN(new Date(val))) {
9988 setDropdownText(value);
9991 if (value === 'Custom Single Date') {
9992 scope.focusSingleDateCalendar = true;
9993 } else if (value === 'Custom Range') {
9994 scope.focusRangeCalendar = true;
9998 scope.resetFocus = function () {
9999 scope.focusSingleDateCalendar = false;
10000 scope.focusRangeCalendar = false;
10001 scope.focusApplyButton = false;
10004 scope.apply = function() {
10005 scope.dateRange.selection = scope.selectedOption;
10006 if(!isNaN(new Date(scope.fromDate))) {
10007 scope.from = scope.fromDate;
10008 scope.dateRange.from = scope.fromDate;
10010 scope.from = undefined;
10011 scope.dateRange.from = undefined;
10013 if(!isNaN(new Date(scope.currentDate))) {
10014 scope.current = scope.currentDate;
10015 scope.dateRange.current = scope.currentDate;
10017 scope.current = undefined;
10018 scope.dateRange.current = undefined;
10024 scope.$watchCollection(function() {
10025 return scope.dateRange;
10026 }, function(value) {
10028 var finalDateRange = angular.copy(value);
10029 ctrl.$setViewValue(finalDateRange);
10033 ctrl.$render = function () {
10034 if (ctrl.$viewValue) {
10035 var inputRange = ctrl.$viewValue;
10036 scope.selectedOption = inputRange.selection;
10037 scope.fromDate = inputRange.from;
10038 scope.currentDate = inputRange.current;
10039 if (scope.fromDate !== undefined && scope.currentDate !== undefined) {
10040 scope.selectAdvancedOption('Custom Range', true);
10041 scope.dateRange.from = scope.fromDate;
10042 scope.dateRange.current = scope.currentDate;
10043 } else if (scope.currentDate !== undefined) {
10044 scope.selectAdvancedOption('Custom Single Date', true);
10045 scope.dateRange.from = undefined;
10046 scope.dateRange.current = scope.currentDate;
10051 scope.cancel = function() {
10052 scope.currentSelection = "";
10053 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
10057 var outsideClick = function (e) {
10058 var isElement = $isElement(angular.element(e.target), elem, $document);
10064 $documentBind.click('showDropdownList', outsideClick, scope);
10071 current: "=?current"
10074 require: '?ngModel',
10076 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/dateFilter.html',
10077 controller:['$scope', '$element', '$attrs',function($scope){
10078 $scope.dateRange = {
10079 selection: undefined,
10083 this.selectOption = function (fromDate,toDate,caption) {
10084 $scope.selectedOption = caption;
10085 $scope.currentSelection =caption;
10086 $scope.dateRange.selection = caption;
10087 $scope.dateRange.current = $scope.resetTime(toDate);
10088 $scope.dateRange.from = $scope.resetTime(fromDate);
10089 $scope.showDropdown();
10091 $scope.checkCurrentSelection=this.checkCurrentSelection = function(value) {
10092 if(value === $scope.currentSelection) {
10098 compile: function(elem, attr) {
10099 var singleDateCalendar = elem.find('span').eq(4);
10100 var rangeCalendar = elem.find('span').eq(5);
10101 rangeCalendar.attr('from', 'fromDate');
10102 singleDateCalendar.attr('current', 'currentDate');
10103 rangeCalendar.attr('current', 'currentDate');
10104 datepickerService.setAttributes(attr, singleDateCalendar);
10105 datepickerService.setAttributes(attr, rangeCalendar);
10111 .directive('attDateFilterList',function(){
10115 fromDate:'=fromDate',
10117 caption:'=caption',
10118 disabled:'=disabled'
10120 require:'^attDateFilter',
10123 templateUrl:'app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html',
10124 link:function(scope,elem,attr,ctrl){
10125 scope.selectOption=function(fromDate,toDate,caption){
10126 ctrl.selectOption(fromDate,toDate,caption);
10128 scope.checkCurrentSelection=ctrl.checkCurrentSelection;
10132 angular.module('att.abs.devNotes', [])
10134 .directive('attDevNotes', function() {
10139 controller: function($scope){
10140 var panes = $scope.panes = [];
10141 $scope.select = function(pane)
10143 angular.forEach(panes, function(pane)
10145 pane.selected = false;
10147 pane.selected = true;
10149 this.addPane = function(pane) {
10150 if (panes.length === 0) {
10151 $scope.select(pane);
10157 '<ul class="tabs">' +
10158 '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
10159 '<a href="javascript:void(0)" ng-click="select(pane)">{{pane.title}}</a>' +
10162 '<div ng-transclude></div>'+
10168 .directive('pane', function() {
10170 require: '^attDevNotes',
10176 link: function(scope, element, attrs, tabsCtrl) {
10177 tabsCtrl.addPane(scope);
10180 '<div class="tab-pane" ng-class="{active: selected}">' +
10181 '<pre ng-class="{\'language-markup\':title==\'HTML\',\'language-javascript\':title==\'JavaScript\',\'language-json\':title==\'JSON\'}" class=" line-numbers">' +
10182 '<code ng-transclude></code>' +
10189 angular.module('att.abs.dividerLines', [])
10190 .directive('attDividerLines', [function()
10194 attDividerLines: '@'
10198 templateUrl: 'app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html',
10199 link: function(scope, element, attribute)
10201 scope.lightContainer = attribute.attDividerLines;
10206 angular.module('att.abs.dragdrop', [])
10207 .directive('attFileDrop', ['$parse', function($parse) {
10215 controller: ['$scope', '$attrs', function($scope, $attrs){
10216 if($attrs.attFileDrop!==""){
10217 $scope.onDrop=$scope.attFileDrop;
10219 this.onDrop = $scope.onDrop;
10221 link: function(scope, element) {
10222 element.addClass('dragdrop');
10226 if(e.originalEvent){
10227 e.dataTransfer = e.originalEvent.dataTransfer;
10229 e.dataTransfer.dropEffect = 'move';
10230 // allows us to drop
10231 if (e.preventDefault) {
10232 e.preventDefault();
10234 element.addClass('dragdrop-over');
10241 // allows us to drop
10242 if (e.preventDefault) {
10243 e.preventDefault();
10245 element.addClass('dragdrop-over');
10252 element.removeClass('dragdrop-over');
10259 // Stops some browsers from redirecting.
10260 if(e.preventDefault) {
10261 e.preventDefault();
10263 if (e.stopPropagation) {
10264 e.stopPropagation();
10266 if(e.originalEvent){
10267 e.dataTransfer = e.originalEvent.dataTransfer;
10269 element.removeClass('dragdrop-over');
10270 if(e.dataTransfer.files && e.dataTransfer.files.length > 0){
10271 scope.fileModel = e.dataTransfer.files[0];
10273 if(typeof scope.onDrop === "function"){
10274 scope.onDrop = $parse(scope.onDrop);
10284 .directive('attFileLink', [ function() {
10287 require: '^?attFileDrop',
10290 templateUrl: 'app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html',
10293 onFileSelect : '&',
10296 controller: ['$scope', '$parse', function($scope, $parse){
10297 this.setFileModel= function(fileModel){
10298 if($scope.takeFileModelFromParent){
10299 $scope.$parent.fileModel = fileModel;
10300 $scope.$parent.$apply();
10303 $scope.fileModel = fileModel;
10307 this.callbackFunction= function(){
10308 if(typeof $scope.onFileSelect === "function"){
10309 $scope.onFileSelect = $parse($scope.onFileSelect);
10310 $scope.onFileSelect();
10315 link: function(scope, element, attr, attFileDropCtrl) {
10316 scope.takeFileModelFromParent = false;
10317 if(!(attr.fileModel) && attFileDropCtrl){
10318 scope.takeFileModelFromParent = true;
10320 if(attr.attFileLink!==""){
10321 scope.onFileSelect=scope.attFileLink;
10323 else if(!(attr.onFileSelect) && attFileDropCtrl){
10324 scope.onFileSelect = attFileDropCtrl.onDrop;
10329 .directive('attFileChange', ['$log','$rootScope',function($log,$rootScope) {
10332 require: '^attFileLink',
10333 link: function(scope, element, attr, attFileLinkCtrl) {
10334 element.bind('change',changeFileModel);
10335 function changeFileModel(e) {
10336 if (e.target.files && e.target.files.length > 0) {
10337 attFileLinkCtrl.setFileModel(e.target.files[0]);
10338 attFileLinkCtrl.callbackFunction();
10341 var strFileName = e.target.value;
10343 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
10344 attFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
10345 attFileLinkCtrl.callbackFunction();
10348 var errMsg = "Error: Please follow the guidelines of Drag and Drop component on Sandbox demo page.";
10349 $log.error(errMsg);
10350 $rootScope.$broadcast('att-file-link-failure', errMsg);
10357 angular.module("att.abs.drawer", ['att.abs.utilities'])
10358 .directive('attDrawer', ['$document', '$timeout', 'DOMHelper', function ($document, $timeout, DOMHelper) {
10365 drawerAutoClose: "&?"
10367 template: '<div><div class="att-drawer" ng-transclude></div><div ng-class="{\'drawer-backdrop\':drawerOpen}"></div></div>',
10368 link: function ($scope, element, attrs) {
10370 // First Element in Drawer component
10371 var firstElement = undefined;
10372 // Element drawer is toggled from
10373 var drawerLaunchingElement = undefined;
10374 // Override default parameters
10375 param.side = attrs.drawerSlide || 'top';
10376 param.speed = attrs.drawerSpeed || '0.25';
10377 param.size = attrs.drawerSize || '300px';
10378 param.zindex = attrs.drawerZindex || 1000;
10379 param.className = attrs.drawerClass || 'att-drawer';
10380 var slider = element.eq(0).children()[0];
10381 var content = angular.element(slider).children()[0];
10382 slider.className = param.className;
10384 slider.style.transitionDuration = param.speed + 's';
10385 slider.style.webkitTransitionDuration = param.speed + 's';
10386 slider.style.zIndex = param.zindex;
10387 slider.style.position = 'fixed';
10388 slider.style.width = 0;
10389 slider.style.height = 0;
10390 slider.style.transitionProperty = 'width, height';
10391 if(param.side==='right'){
10392 slider.style.height = attrs.drawerCustomHeight || '100%';
10393 slider.style.top = attrs.drawerCustomTop || '0px';
10394 slider.style.bottom = attrs.drawerCustomBottom || '0px';
10395 slider.style.right = attrs.drawerCustomRight || '0px';
10396 }else if(param.side==='left'){ /*Added this part for ECOM*/
10397 slider.style.height = attrs.drawerCustomHeight || '100%';
10398 slider.style.top = attrs.drawerCustomTop || '0px';
10399 slider.style.bottom = attrs.drawerCustomBottom || '0px';
10400 slider.style.left = attrs.drawerCustomRight || '0px';
10402 else if(param.side==='top' || param.side==='bottom'){
10403 slider.style.width = attrs.drawerCustomWidth || '100%';
10404 slider.style.left = attrs.drawerCustomLeft || '0px';
10405 slider.style.top = attrs.drawerCustomTop || '0px';
10406 slider.style.right = attrs.drawerCustomRight || '0px';
10408 $timeout(function() {
10409 firstElement = DOMHelper.firstTabableElement(element[0]);
10412 function drawerClose(slider, param) {
10413 if (slider && slider.style.width !== 0 && slider.style.height !== 0){
10414 content.style.display = 'none';
10415 if(param.side==='right' || param.side==='left'){
10416 slider.style.width = '0px';
10418 else if(param.side==='top' || param.side==='bottom'){
10419 slider.style.height = '0px';
10422 $scope.drawerOpen = false;
10424 if (angular.isDefined(drawerLaunchingElement) && drawerLaunchingElement != null) {
10425 drawerLaunchingElement.focus();
10429 function drawerOpen(slider, param) {
10430 // Before opening drawer, find the focused element
10431 drawerLaunchingElement = document.activeElement;
10432 if (slider.style.width !== 0 && slider.style.height !== 0){
10433 if(param.side==='right' || param.side==='left'){
10434 slider.style.width = param.size;
10436 else if(param.side==='top' || param.side==='bottom'){
10437 slider.style.height = param.size;
10439 $timeout(function() {
10440 content.style.display = 'block';
10442 if (angular.isDefined(firstElement) && firstElement != null) {
10443 firstElement.focus();
10445 },(param.speed * 1000));
10448 function isFunction(functionToCheck) {
10450 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
10455 if(attrs.drawerSize) {
10456 $scope.$watch(function() {
10457 return attrs.drawerSize;
10458 }, function(newVal) {
10459 param.size = newVal;
10460 if($scope.drawerOpen) {
10461 drawerOpen(slider,param);
10465 $scope.$watch("drawerOpen", function (value){
10468 drawerOpen(slider,param);
10471 drawerClose(slider,param);
10474 // close panel on location change
10475 if($scope.drawerAutoClose()) {
10476 $scope.$on("$locationChangeStart", function(){
10477 drawerClose(slider, param);
10478 if(isFunction($scope.drawerAutoClose())) {
10479 $scope.drawerAutoClose();
10482 $scope.$on("$stateChangeStart", function(){
10483 drawerClose(slider, param);
10484 if(isFunction($scope.drawerAutoClose)) {
10485 $scope.drawerAutoClose();
10493 angular.module('att.abs.message', [])
10495 .directive('attMessages', [function() {
10501 controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
10502 $scope.messageScope = [];
10503 this.registerScope = function(messageScope) {
10504 $scope.messageScope.push(messageScope);
10506 $scope.$parent.$watchCollection($attrs['for'], function(errors) {
10507 for (var key in errors) {
10509 $scope.error = key;
10512 $scope.error = null;
10515 for (var i = 0; i < $scope.messageScope.length; i++) {
10516 if($scope.messageScope[i].when === $scope.error) {
10517 $scope.messageScope[i].show();
10518 $scope.setMessageType($scope.messageScope[i].type);
10520 $scope.messageScope[i].hide();
10523 if($scope.error === null) {
10524 $scope.setMessageType(null);
10527 $scope.setMessageType = this.setMessageType = function(messageType) {
10528 if($attrs.messageType) {
10529 $scope.messageType = messageType;
10536 .directive('attMessage', [function() {
10540 require: '^attMessages',
10541 link: function(scope, elem, attr, ctrl) {
10542 ctrl.registerScope(scope);
10543 elem.attr('role', 'alert'); //Trinity CATO
10544 scope.when = attr.when || attr.attMessage;
10545 scope.type = attr.type;
10546 scope.show = function() {
10547 elem.css({display: 'block'});
10549 scope.hide = function() {
10550 elem.css({display: 'none'});
10557 angular.module('att.abs.formField', ['att.abs.message', 'att.abs.utilities'])
10558 .directive('attFormField', [function() {
10562 controller:function() {
10564 link: function(scope, elem, attr) {
10565 elem.wrap('<div class="form-field"></div>');
10566 elem.parent().append('<label class="form-field__label">' + attr.placeholder || attr.attFormField + '</label>');
10567 elem.wrap('<div class="form-field-input-container"></div>');
10569 elem.bind('keyup', function() {
10570 if (this.value !== '') {
10571 elem.parent().parent().find('label').addClass('form-field__label--show').removeClass('form-field__label--hide');
10573 elem.parent().parent().find('label').addClass('form-field__label--hide').removeClass('form-field__label--show');
10577 elem.bind('blur', function() {
10578 if (this.value === '') {
10579 elem.parent().parent().find('label').removeClass('form-field__label--hide');
10585 .directive('attFormFieldValidation', ['$compile', '$log', function($compile, $log) {
10590 require: ['?ngModel', '?attFormField'],
10591 link: function(scope, elem, attr, ctrl) {
10592 var ngCtrl = ctrl[0];
10593 var attFormFieldCtrl = ctrl[1];
10596 $log.error("att-form-field-validation :: ng-model directive is required.");
10599 if (!attFormFieldCtrl) {
10600 $log.error("att-form-field-validation :: att-form-field directive is required.");
10604 elem.parent().append($compile(angular.element('<i class="icon-info-alert error" ng-show="valid===false"> </i>'))(scope));
10605 elem.parent().append($compile(angular.element('<i class="icon-info-success success" ng-show="valid===true"> </i>'))(scope));
10607 scope.$watch('valid', function(value) {
10609 elem.parent().parent().addClass('success');
10610 } else if (value === false) {
10611 elem.parent().parent().addClass('error');
10613 elem.parent().parent().removeClass('success').removeClass('error');
10617 elem.bind('keyup', function() {
10618 if (ngCtrl.$valid) {
10619 scope.valid = true;
10620 } else if (ngCtrl.$invalid) {
10621 scope.valid = false;
10630 .directive('attFormFieldValidationAlert', ['$timeout', function($timeout) {
10638 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html',
10639 link: function(scope, elem, attr, ctrl) {
10640 scope.showLabel = false;
10641 scope.hideLabel = false;
10642 scope.errorMessage = false;
10643 scope.warningMessage = false;
10644 var checkMessageType = function() {
10645 var messageType = scope.messageType;
10646 if (messageType === 'error') {
10647 scope.errorMessage = true;
10648 scope.warningMessage = false;
10649 } else if (messageType === 'warning') {
10650 scope.errorMessage = false;
10651 scope.warningMessage = true;
10653 scope.errorMessage = false;
10654 scope.warningMessage = false;
10657 var oldIE = navigator.userAgent.toLowerCase().indexOf('msie 8.0') !== -1;
10658 elem.find('label').text(elem.find('input').attr('placeholder'));
10659 elem.find('input').bind('keyup', function() {
10660 if (this.value !== '') {
10661 scope.showLabel = true;
10662 scope.hideLabel = false;
10664 elem.find('label').css({top: '-20px'});
10667 scope.showLabel = false;
10668 scope.hideLabel = true;
10670 elem.find('label').css({top: '0px'});
10673 checkMessageType();
10677 elem.find('input').bind('blur', function() {
10678 if (this.value === '') {
10679 scope.showLabel = false;
10680 scope.hideLabel = false;
10684 $timeout(function() {
10685 checkMessageType();
10690 .constant("CoreFormsUiConfig", {
10691 phoneMask: '(___) ___-____'
10693 .directive('attPhoneMask', ['$parse', 'CoreFormsUiConfig', function($parse, CoreFormsUiConfig) {
10695 require: 'ngModel',
10699 link: function(scope, iElement, iAttrs, ctrl) {
10700 var B = navigator.userAgent.toLowerCase(), C = B.indexOf("android") > -1,
10701 oldIE = B.indexOf('msie 8.0') !== -1;;
10703 var validPhoneNumber = false;
10708 A = CoreFormsUiConfig.phoneMask;
10710 iElement.attr("maxlength", A.length);
10711 var checkValidity = function(unmaskedValue) {
10713 if (unmaskedValue){
10714 valid = (unmaskedValue.length === 10);}
10715 ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);
10716 ctrl.$setValidity('mask', valid);
10720 var handleKeyup = function() {
10721 var E,D = ctrl.$modelValue;
10729 L = D.substring(0, A.length);
10730 K = D.replace(/[^0-9]/g, "").split("");
10731 for (E = 0; E < I; E++) {
10732 J.push(G[E] === "_" ? K.shift() : G[E]);
10733 if (K.length === 0) {
10740 ctrl.$setViewValue(D);
10746 // since we are only allowing 0-9, why even let the keypress go forward?
10747 // also added in delete... in case they want to delete :)
10748 var handlePress = function(e) {
10750 if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {
10751 if (e.which !== 8 && e.which !== 9 && e.which !== 46 && e.which !== 13 && e.which !== 37 && e.which !== 39 &&
10753 (e.ctrlKey !== true && (e.which !== '118' || e.which !== '86'))&&
10755 (e.ctrlKey !== true && (e.which !== '99' || e.which !== '67'))&&
10757 (e.ctrlKey !== true && (e.which !== '120' || e.which !== '88')))
10759 e.preventDefault ? e.preventDefault() : e.returnValue = false;
10760 iElement.attr("aria-label","Only numbers are allowed");
10761 validPhoneNumber = false;
10764 iElement.removeAttr("aria-label");
10765 validPhoneNumber = true;
10770 // i moved this out because i thought i might need focus as well..
10771 // to handle setting the model as the view changes
10772 var parser = function(fromViewValue) {
10773 var letters = /^[A-Za-z]+$/;
10774 var numbers = /^[0-9]+$/;
10775 if(fromViewValue.match(letters))
10776 {validPhoneNumber = false;}
10777 if(fromViewValue.match(numbers))
10778 {validPhoneNumber = true;}
10780 if (fromViewValue && fromViewValue.length > 0) {
10781 clean = fromViewValue.replace(/[^0-9]/g, '');
10783 checkValidity(clean);
10787 //to handle reading the model and formatting it
10788 var formatter = function(fromModelView) {
10790 checkValidity(fromModelView);
10791 if (fromModelView){
10792 input = handleKeyup();}
10795 ctrl.$parsers.push(parser);
10796 ctrl.$formatters.push(formatter);
10797 iElement.bind('keyup', handleKeyup);
10798 iElement.bind('keydown', handlePress);
10799 iElement.bind('input', function(e){
10806 .constant('validationTypeInt', {
10807 validationNum: {'number':'1','text':'2','email':'3'}
10809 .directive('attFormFieldPrv', [ 'keyMapAc', 'validationTypeInt', function( keyMapAc, validationTypeInt ) {
10813 controller:['$scope', function($scope) {
10814 this.showHideErrorMessage = function ( booleanValue ){
10815 if( $scope.$$prevSibling != null && angular.isDefined( $scope.$$prevSibling )
10816 && angular.isDefined( $scope.$$prevSibling.hideErrorMsg ) ){
10817 $scope.$$prevSibling.hideErrorMsg = booleanValue;
10821 this.findAllowedCharactor = function( keyCode ){
10822 var keyMapSc = keyMapAc.keys;
10823 if( angular.isDefined( $scope.allowedSpecialCharacters )
10824 && angular.isDefined( $scope.allowedSpecialCharacters.length )
10825 && $scope.allowedSpecialCharacters.length > 0 ){
10826 var allowedCharList = $scope.allowedSpecialCharacters;
10827 var charFound = false;
10828 for( var i=0 ; i < allowedCharList.length ; i++){
10829 if( allowedCharList[i] === keyMapSc[keyCode] ){
10839 this.validateText = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10840 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10841 var expAlphanumeric = /^[a-zA-Z0-9]*$/i;
10842 return expAlphanumeric.test( validationInput );
10844 var expAlphanumericSpecialChar = '^[a-zA-Z0-9' + outputSpecialChars + ']*$';
10845 var regularExp = new RegExp( expAlphanumericSpecialChar, 'i' );
10846 return regularExp.test( validationInput );
10849 this.validateNumber = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10850 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10851 var expNumber = /^[0-9\.]+$/;
10852 return expNumber.test( validationInput );
10854 var expNumberSpecial = '^[0-9\.' + outputSpecialChars + ']*$';
10855 var regularExp = new RegExp( expNumberSpecial, 'i' );
10856 return regularExp.test( validationInput );
10859 this.validateEmail = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10860 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10861 var expEmail = /(([a-zA-Z0-9\-?\.?]+)@(([a-zA-Z0-9\-_]+\.)+)([a-z]{2,3}))+$/;
10862 return expEmail.test( validationInput );
10864 var expEmailSpecial = '(([a-z' + outputSpecialChars + 'A-Z0-9\-?\.?]+)@(([a-z'
10865 + outputSpecialChars + 'A-Z0-9\-_]+\.)+)([' + outputSpecialChars + 'a-z]{2,3}))+$';
10866 var regularExp = new RegExp( expEmailSpecial, 'i' );
10867 return regularExp.test( validationInput );
10870 this.validateInput = function( validationType, allowedChars, validationInput ){
10871 var outputSpecialChars = '';
10872 var result = false;
10873 if( angular.isDefined( allowedChars ) && angular.isDefined( allowedChars.length )
10874 && allowedChars.length > 0 ){
10875 for( var i = 0; i < allowedChars.length; i++){
10876 outputSpecialChars += '\\'+allowedChars[i];
10879 switch ( validationTypeInt.validationNum[ validationType ] ) {
10880 case validationTypeInt.validationNum["text"]:
10881 result = this.validateText( validationType, allowedChars, validationInput, outputSpecialChars );
10883 case validationTypeInt.validationNum["number"]:
10884 result = this.validateNumber( validationType, allowedChars, validationInput, outputSpecialChars );
10886 case validationTypeInt.validationNum["email"]:
10887 result = this.validateEmail( validationType, allowedChars, validationInput, outputSpecialChars );
10895 link: function(scope, elem, attr ) {
10896 elem.parent().prepend('<label class="form-field__label">' + attr.placeholder + '</label>');
10897 elem.wrap('<div class="form-field-input-container"></div>');
10898 elem.parent().parent().find('label').addClass('form-field__label--show');
10902 .directive('attFormFieldValidationPrv', [ 'keyMapAc','validationTypeInt' , function( keyMapAc, validationTypeInt ) {
10906 validationType: '=',
10910 require: ['?ngModel', '^attFormFieldPrv'],
10911 link: function(scope, elem, attr, ctrl) {
10912 var attFormFieldCtrl = ctrl[1];
10913 elem.bind('keyup', function() {
10914 /* email validation has tobe done on keyup */
10915 if( attFormFieldCtrl.validateInput( scope.validationType, scope.allowedChars, elem[0].value ) ){
10916 attFormFieldCtrl.showHideErrorMessage(false);
10919 attFormFieldCtrl.showHideErrorMessage(true);
10922 var keyMapSc = keyMapAc.keyRange;
10923 var allowedKeys = keyMapAc.allowedKeys;
10924 var validateTextCode = function( charFound,event ){
10925 var resultOne = (event.which < keyMapSc['startNum'] || event.which > keyMapSc['endNum'] );
10926 var resultTwo = (event.which < keyMapSc['startCapitalLetters'] || event.which > keyMapSc['endCapitalLetters'] );
10927 var resultThree = (event.which < keyMapSc['startSmallLetters'] || event.which > keyMapSc['endSmallLetters'] );
10928 var result = ( resultOne && resultTwo && resultThree );
10929 return ( result && ( !charFound ) );
10931 var validateNumberCode = function( charFound,event ){
10932 return ( ( event.which < keyMapSc['startNum'] || event.which > keyMapSc['endNum'] ) && ( !charFound ) );
10934 var validateEmailCode = function( charFound,event ){
10935 var condOne = String.fromCharCode( event.which ) !== '-' && String.fromCharCode( event.which ) !== '_';
10936 var condTwo = String.fromCharCode( event.which ) !== '@' && String.fromCharCode( event.which ) !== '.';
10937 var ifAllowedChars = condOne && condTwo;
10938 var ifCharRange = validateTextCode( charFound,event );
10939 return ( ( !charFound ) && ifAllowedChars && ifCharRange );
10941 var validateSwitch = function( validationTypeSwitch, charFound, event ){
10942 switch ( validationTypeSwitch ) {
10943 case validationTypeInt.validationNum["text"]:
10944 /* 97-122 65-90 48-57 if keyCode is outside range of alphanumeric chars and not found in list then prevent */
10945 if( validateTextCode( charFound, event ) ){
10949 case validationTypeInt.validationNum["number"]:
10950 /* if key code is outside number range and notfound then prevent */
10951 if( validateNumberCode( charFound, event ) ){
10955 case validationTypeInt.validationNum["email"]:
10956 /* if keyCode is outside charactor/number range and not _-@. then prevent */
10957 if( validateEmailCode( charFound, event ) ){
10966 /* key stroke prevention has to be happen on numeric and alphanumeric fields */
10967 elem.bind('keypress', function( event ){
10968 if(!(event.which)){
10970 event.which = event.keyCode;
10972 else if(event.charCode){
10973 event.which = event.charCode;
10976 var charFound = attFormFieldCtrl.findAllowedCharactor( event.which );
10977 var insideCondOne = ( angular.isDefined( scope.validationType ) && scope.validationType !== '');
10978 var insideCondTwo = ( event.which !== allowedKeys['TAB']
10979 && event.which !== allowedKeys['BACKSPACE'] && event.which!== allowedKeys['DELETE'] );
10980 var goInside = insideCondOne && insideCondTwo;
10981 if( goInside && validateSwitch( validationTypeInt.validationNum[ scope.validationType ], charFound, event ) ){
10982 event.preventDefault();
10988 .directive('attFormFieldValidationAlertPrv', [ function() {
10991 scope : { errorMessage : '=' },
10993 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html',
10994 link: function( scope ) {
10995 scope.errorMessage = scope.errorMessage;
10996 if( angular.isDefined( scope.$parent.hideErrorMsg ) ){
10997 scope.hideErrorMsg = scope.$parent.hideErrorMsg;
11000 scope.hideErrorMsg = true;
11005 //Credit card validation directives starts here
11006 .factory('Cards', [function() {
11007 var defaultFormat = /(\d{1,4})/g;
11008 var defaultInputFormat = /(?:^|\s)(\d{4})$/;
11012 pattern: /^(6011|65|64[4-9]|622)/,
11013 format: defaultFormat,
11014 inputFormat: defaultInputFormat,
11017 cvcSecurityImg: 'visaI',
11023 pattern: /^5[1-5]/,
11024 format: defaultFormat,
11025 inputFormat: defaultInputFormat,
11028 cvcSecurityImg: 'visaI',
11035 format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
11036 inputFormat: /^(\d{4}|\d{4}\s\d{6})$/,
11039 cvcSecurityImg: 'amexI',
11046 format: defaultFormat,
11047 inputFormat: defaultInputFormat,
11050 cvcSecurityImg: 'visaI',
11056 var _fromNumber = function(num) {
11059 num = (num + '').replace(/\D/g, '');
11061 for (i = 0, len = cards.length; i < len; i++) {
11065 if (card.pattern.test(num)) {
11072 var _fromType = function(type) {
11075 for (i = 0, len = cards.length; i < len; i++) {
11079 if (card.type === type) {
11087 fromNumber: function(val) {
11088 return _fromNumber(val);
11090 fromType: function(val) {
11091 return _fromType(val);
11093 defaultFormat: function() {
11094 return defaultFormat;
11096 defaultInputFormat: function() {
11097 return defaultInputFormat;
11102 .factory('_Validate', ['Cards', '$parse', function(Cards, $parse) {
11103 var __indexOf = [].indexOf || function(item)
11105 for (var i = 0, l = this.length; i < l; i++)
11107 if (i in this && this[i] === item)
11115 var _luhnCheck = function(num) {
11116 var digit, digits, odd, sum, i, len;
11120 digits = (num + '').split('').reverse();
11122 for (i = 0, len = digits.length; i < len; i++) {
11125 digit = parseInt(digit, 10);
11127 if ((odd = !odd)) {
11139 return sum % 10 === 0;
11142 var _validators = {};
11144 _validators['cvc'] = function(cvc, ctrl, scope, attr) {
11147 // valid if empty - let ng-required handle empty
11148 if ((angular.isUndefined(cvc)) || (cvc === null) || (cvc.length === 0))
11153 if (!/^\d+$/.test(cvc)) {
11158 if (attr.paymentsTypeModel) {
11159 var typeModel = $parse(attr.paymentsTypeModel);
11160 type = typeModel(scope);
11165 ref1 = Cards.fromType(type);
11166 return (ref = cvc.length, __indexOf.call((ref1 !== null) ? ref1.cvcLength : void 0, ref)) >= 0;
11170 return cvc.length >= 3 && cvc.length <= 4;
11173 _validators['zip'] = function(zip, ctrl, scope, attr) {
11176 // valid if empty - let ng-required handle empty
11177 if ((angular.isUndefined(zip)) || (zip === null) || (zip.length === 0))
11182 if (!/^\d+$/.test(zip)) {
11187 if (attr.paymentsTypeModel) {
11188 var typeModel = $parse(attr.paymentsTypeModel);
11189 type = typeModel(scope);
11193 ref1 = Cards.fromType(type);
11194 return (ref = zip.length, __indexOf.call(ref1 !== null ? ref1.zipLength : void 0, ref)) >= 0;
11198 return zip.length < 6;
11201 _validators['card'] = function(num, ctrl, scope, attr) {
11202 var card, ref, typeModel;
11204 if (attr.paymentsTypeModel) {
11205 typeModel = $parse(attr.paymentsTypeModel);
11208 var clearCard = function() {
11210 typeModel.assign(scope, null);
11215 // valid if empty - let ng-required handle empty
11216 if ((angular.isUndefined(num)) || (num === null) || (num.length === 0)) {
11221 num = (num + '').replace(/\s+|-/g, '');
11223 if (!/^\d+$/.test(num)) {
11228 card = Cards.fromNumber(num);
11233 ctrl.$card = angular.copy(card);
11236 typeModel.assign(scope, card.type);
11239 ret = (ref = num.length, __indexOf.call(card.length, ref) >= 0) && (card.luhn === false || _luhnCheck(num));
11242 return function(type, val, ctrl, scope, attr) {
11243 if (!_validators[type]) {
11245 types = Object.keys(_validators);
11247 errstr = 'Unknown type for validation: "' + type + '". ';
11248 errstr += 'Should be one of: "' + types.join('", "') + '"';
11252 return _validators[type](val, ctrl, scope, attr);
11255 .factory('_ValidateWatch', ['_Validate', function(_Validate) {
11257 var _validatorWatches = {};
11259 _validatorWatches['cvc'] = function(type, ctrl, scope, attr) {
11260 if (attr.paymentsTypeModel) {
11261 scope.$watch(attr.paymentsTypeModel, function(newVal, oldVal) {
11262 if (newVal !== oldVal) {
11263 var valid = _Validate(type, ctrl.$modelValue, ctrl, scope, attr);
11264 ctrl.$setValidity(type, valid);
11269 _validatorWatches['zip'] = function(type, ctrl, scope, attr) {
11270 if (attr.paymentsTypeModel) {
11271 scope.$watch(attr.paymentsTypeModel, function(newVal, oldVal) {
11272 if (newVal !== oldVal) {
11273 var valid = _Validate(type, ctrl.$modelValue, ctrl, scope, attr);
11274 ctrl.$setValidity(type, valid);
11279 return function(type, ctrl, scope, attr) {
11280 if (_validatorWatches[type]) {
11281 return _validatorWatches[type](type, ctrl, scope, attr);
11285 .directive('validateCard', ['$window', '_Validate', '_ValidateWatch', function($window, _Validate, _ValidateWatch) {
11288 require: 'ngModel',
11289 link: function(scope, elem, attr, ctrl) {
11291 var type = attr.validateCard;
11292 _ValidateWatch(type, ctrl, scope, attr);
11293 var validateFn = function(val) {
11294 var valid = _Validate(type, val, ctrl, scope, attr);
11295 ctrl.$setValidity(type, valid);
11296 if (type === 'card')
11298 if (ctrl.$card === null)
11300 if ((val == null) || (val === "") || (val === ''))
11302 scope.invalidCardError = '';
11303 scope.invalidCard = "";
11305 else if (val.length >= 1)
11307 scope.invalidCardError = 'error';
11308 scope.invalidCard = "The number entered is not a recognized credit card number.";
11315 if (ctrl.$card.length.indexOf(val.length) >= 0)
11317 scope.invalidCardError = 'error';
11318 scope.invalidCard = "The number entered is not a recognized credit card number.";
11322 scope.invalidCardError = '';
11323 scope.invalidCard = "";
11328 scope.invalidCardError = '';
11329 scope.invalidCard = "";
11332 elem.bind("blur", function()
11334 if ((!valid) || (ctrl.$card === null))
11336 scope.invalidCardError = 'error';
11337 scope.invalidCard = "The number entered is not a recognized credit card number.";
11341 scope.invalidCardError = '';
11342 scope.invalidCard = "";
11346 return valid ? val : undefined;
11348 ctrl.$formatters.push(validateFn);
11349 ctrl.$parsers.push(validateFn);
11353 .directive('creditCardImage', function() {
11355 templateUrl: 'app/scripts/ng_js_att_tpls/formField/creditCardImage.html',
11358 link: function(scope, element, attr)
11360 scope.$watch(attr.creditCardImage, function(newVal, oldVal)
11362 if (newVal !== oldVal)
11365 if (!angular.isUndefined(newVal) && newVal !== null)
11367 scope.newValCCI = 'show-' + newVal;
11369 if (newVal === null)
11371 scope.newValCCI = '';
11378 .directive('securityCodeImage', ['$document', function($document) {
11380 templateUrl: 'app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html',
11383 link: function(scope, element, attr)
11385 scope.$watch(attr.securityCodeImage, function(newVal, oldVal)
11387 if (newVal !== oldVal)
11389 if (!angular.isUndefined(newVal) && newVal !== null)
11391 if (newVal === 'amexI')
11393 scope.newValI = 'ccv2-security-amex';
11394 scope.newValIAlt = "The 4 digit CVC security code is on the front of the card.";
11395 scope.cvcPlaceholder = "4 digits";
11396 scope.cvcMaxlength = 4;
11398 else if (newVal === 'visaI')
11400 scope.newValI = 'ccv2-security';
11401 scope.newValIAlt = "The CVC security code is on the back of your card right after the credit card number.";
11402 scope.cvcPlaceholder = "3 digits";
11403 scope.cvcMaxlength = 3;
11406 if (newVal === null)
11408 scope.newValI = 'ccv2-security';
11409 scope.cvcPlaceholder = "3 digits";
11410 scope.cvcMaxlength = 3;
11411 scope.newValIAlt = "The CVC security code is on the back of your card right after the credit card number.";
11416 element.bind("click", function(ev) {
11417 ev.preventDefault();
11418 if (element.find("button").hasClass("active")) {
11419 element.find("button").removeClass("active");
11422 element.find("button").addClass("active");
11426 var window = angular.element($document);
11427 window.bind("click", function(ev) {
11428 var targetClassname = ev.target.className;
11429 if ((targetClassname !== "btn btn-alt btn-tooltip active")) {
11430 if (element.find("button").hasClass("active")) {
11431 element.find("button").removeClass("active");
11440 angular.module('att.abs.hourpicker', ['att.abs.utilities'])
11441 .constant('hourpickerConfig', {
11442 days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
11443 customOption: 'Custom'
11446 .controller('hourPickerController', ['$scope', function ($scope) {
11448 $scope.options = [];
11449 this.setOptions = function (value, fromtime, totime, preselect, uncheckedFromTime, uncheckedToTime) {
11450 $scope.options.push(value);
11452 if (preselect !== undefined) {
11453 $scope.preselect = preselect;
11458 if (fromtime !== undefined) {
11459 $scope.fromtime = fromtime;
11460 for (daycount in $scope.days) {
11461 if ($scope.days.hasOwnProperty(daycount)) {
11462 $scope.FrtimeList[$scope.days[daycount]] = {};
11463 if (uncheckedFromTime !== undefined) {
11464 $scope.FrtimeList[$scope.days[daycount]].value = uncheckedFromTime;
11465 $scope.selectedFromOption[$scope.days[daycount]] = uncheckedFromTime;
11467 $scope.FrtimeList[$scope.days[daycount]].value = fromtime[0].value;
11468 $scope.selectedFromOption[$scope.days[daycount]] = fromtime[0].value;
11473 if (totime !== undefined) {
11474 $scope.totime = totime;
11475 for (daycount in $scope.days) {
11476 if ($scope.days.hasOwnProperty(daycount)) {
11477 $scope.TotimeList[$scope.days[daycount]] = {};
11478 if (uncheckedToTime !== undefined) {
11479 $scope.TotimeList[$scope.days[daycount]].value = uncheckedToTime;
11480 $scope.selectedToOption[$scope.days[daycount]] = uncheckedToTime;
11482 $scope.TotimeList[$scope.days[daycount]].value = totime[0].value;
11483 $scope.selectedToOption[$scope.days[daycount]] = totime[0].value;
11485 $scope.showToTimeErrorDay[$scope.days[daycount]] = false;
11490 if (uncheckedFromTime !== undefined) {
11491 $scope.uncheckedFromTime = uncheckedFromTime;
11493 if (uncheckedToTime !== undefined) {
11494 $scope.uncheckedToTime = uncheckedToTime;
11498 this.getSelectedOption = function () {
11499 return $scope.selectedOption;
11502 this.setToTimeErrorDay = function (day, flag) {
11503 $scope.showToTimeErrorDay[day] = flag;
11507 .directive('attHourpickerOption', [function () {
11510 require: '^attHourpicker',
11513 fromtime: "=fromtime",
11515 preselect: "=preselect",
11516 uncheckedFromTime: "=",
11517 uncheckedToTime: "="
11519 link: function (scope, element, attr, ctrl) {
11520 ctrl.setOptions(scope.option,
11524 scope.uncheckedFromTime,
11525 scope.uncheckedToTime);
11530 .directive('attHourpicker', ["hourpickerConfig", "$document", "$log", "$documentBind", "$timeout", function (hourpickerConfig, $document, $log, $documentBind, $timeout) {
11532 require: 'ngModel',
11534 controller: 'hourPickerController',
11540 templateUrl: 'app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html',
11541 link: function (scope, element, attr, ctrl) {
11543 scope.isFromDropDownOpen = false;
11544 scope.isToDropDownOpen = false;
11545 var dropDownOpenValue = "";
11547 scope.days = hourpickerConfig.days;
11548 scope.daysList = {};
11549 scope.FrtimeList = {};
11550 scope.FrtimeListDay = {};
11551 scope.TotimeListDay = {};
11552 scope.selectedFromOption = {};
11553 scope.selectedToOption = {};
11554 scope.TotimeList = {};
11555 scope.selectedIndex = 0;
11556 scope.selectedOption = "Select from list";
11557 scope.customTime = [];
11559 scope.resetFlag = false;
11560 scope.showToTimeErrorDay = {};
11561 scope.validatedCustomPreselect = [];
11563 scope.$watch('resetFlag', function (newVal, oldVal) {
11564 if (newVal !== oldVal) {
11565 if (newVal && scope.selectedOption === hourpickerConfig.customOption) {
11566 //disable and reset all days checkbox
11567 for (day in scope.daysList) {
11568 if (scope.daysList.hasOwnProperty(day)) {
11569 scope.daysList[day] = false;
11570 scope.addSelectedValue(day);
11573 scope.preselectUpdateFxn(scope.preselect);
11575 scope.resetFlag = false;
11579 scope.$watch('selCategory', function (value) {
11581 ctrl.$setViewValue(value);
11585 scope.updateData = function (value) {
11586 if (value.constructor === Array) {
11587 scope.showDaysSelector = true;
11588 scope.selectedOption = hourpickerConfig.customOption;
11589 for (var arry in value) {
11590 if (value.hasOwnProperty(arry)) {
11591 var day = value[arry].day;
11593 if (typeof value[arry].preEnabled === 'boolean' && value[arry].preEnabled) {
11594 scope.daysList[day] = true;
11596 scope.daysList[day] = false;
11599 for (var fromcount in scope.fromtime) {
11600 if (scope.fromtime[fromcount].value === value[arry].FromTime && !scope.uncheckedFromTime) {
11601 scope.FrtimeList[day].value = scope.fromtime[fromcount].value;
11602 scope.selectedFromOption[day] = scope.FrtimeList[day].value;
11605 for (var tocount in scope.totime) {
11606 if (scope.totime[tocount].value === value[arry].ToTime && !scope.uncheckedToTime) {
11607 scope.TotimeList[day].value = scope.totime[tocount].value;
11608 scope.selectedToOption[day] = scope.TotimeList[day].value;
11612 scope.addSelectedValue(day, value[arry].FromTime, value[arry].ToTime);
11615 if (parseInt(arry) + 1 === value.length) {
11621 scope.selectOption(value.day);
11625 scope.$watch('preselect', function (value) {
11626 scope.preselectUpdateFxn(value);
11629 scope.preselectUpdateFxn = function (value) {
11630 if (value !== undefined) {
11631 if (scope.options) {
11632 value = scope.validatePreselectData(value);
11634 if (value === "") {
11637 scope.updateData(value);
11641 scope.validatePreselectData = function (value) {
11642 if (value.constructor === Array) {
11643 for (var arry in value) {
11644 if (value.hasOwnProperty(arry)) {
11645 var day = value[arry].day;
11646 var isDayFound = false;
11647 var isFrmFound = false;
11648 var isToFound = false;
11649 for (var daycount in scope.days) {
11650 if (scope.days[daycount] === day) {
11656 value.splice(arry, 1);
11659 for (var fromcount in scope.fromtime) {
11660 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
11666 value[arry].FromTime = scope.fromtime[0].value;
11668 for (var tocount in scope.totime) {
11669 if (scope.totime[tocount].value === value[arry].ToTime) {
11675 value[arry].ToTime = scope.totime[0].value;
11678 if (typeof value[arry].preEnabled === 'boolean' && value[arry].preEnabled) {
11679 value[arry].preEnabled = true;
11681 value[arry].preEnabled = false;
11684 scope.validatedCustomPreselect[day] = {};
11685 scope.validatedCustomPreselect[day].FromTime = value[arry].FromTime;
11686 scope.validatedCustomPreselect[day].ToTime = value[arry].ToTime;
11689 if (parseInt(arry) + 1 === value.length) {
11695 var isOptionFound = false;
11696 for (var optcount in scope.options) {
11697 if (scope.options[optcount] === value.day) {
11698 isOptionFound = true;
11702 if (!isOptionFound) {
11709 scope.selectPrevNextValue = function ($event, arrayValues, currValue) {
11713 if ($event.keyCode === 38) {
11715 } else if ($event.keyCode === 40) {
11721 if (arrayValues.indexOf(currValue) !== -1) {
11722 index = arrayValues.indexOf(currValue) + value;
11724 for (var count in arrayValues) {
11725 if (arrayValues[count].value === currValue) {
11726 index = parseInt(count) + value;
11732 if (index === arrayValues.length) {
11734 } else if (index === -1) {
11738 $event.preventDefault();
11739 if (arrayValues[index].value) {
11740 return arrayValues[index].value;
11742 return arrayValues[index];
11746 scope.showDropdown = function () {
11747 scope.showlist = !scope.showlist;
11751 scope.showfromDayDropdown = function (value) {
11752 //close dropdown if any other From drop down is opened
11753 for (count in scope.FrtimeListDay) {
11754 if (count !== value && scope.FrtimeListDay[count]) {
11755 scope.FrtimeListDay[count] = false;
11758 for (count in scope.TotimeListDay) {
11759 if (scope.TotimeListDay[count]) {
11760 scope.TotimeListDay[count] = false;
11763 scope.FrtimeListDay[value] = !scope.FrtimeListDay[value];
11765 scope.showlist = false;
11767 //save model value so we can close current dropdown on click of other part of the document
11768 if (scope.FrtimeListDay[value]) {
11769 scope.isFromDropDownOpen = true;
11770 dropDownOpenValue = value;
11772 scope.isFromDropDownOpen = false;
11775 $timeout(function () {
11776 if (scope.FrtimeListDay[value]) {
11777 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
11778 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
11779 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
11780 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
11785 scope.showtoDayDropdown = function (value) {
11786 //close dropdown if any other To drop down is opened
11787 for (count in scope.TotimeListDay) {
11788 if (count !== value && scope.TotimeListDay[count]) {
11789 scope.TotimeListDay[count] = false;
11792 for (count in scope.FrtimeListDay) {
11793 if (scope.FrtimeListDay[count]) {
11794 scope.FrtimeListDay[count] = false;
11797 scope.TotimeListDay[value] = !scope.TotimeListDay[value];
11799 scope.showlist = false;
11801 //save model value so we can close current dropdown on click of other part of the document
11802 if (scope.TotimeListDay[value]) {
11803 scope.isToDropDownOpen = true;
11804 dropDownOpenValue = value;
11807 scope.isToDropDownOpen = false;
11810 $timeout(function () {
11811 if (scope.TotimeListDay[value]) {
11812 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
11813 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
11814 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
11815 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
11820 scope.selectFromDayOption = function (day, value) {
11821 scope.selectedFromOption[day] = value;
11822 scope.FrtimeList[day].value = value;
11823 scope.FrtimeListDay[day] = false;
11824 scope.isFromDropDownOpen = false;
11827 scope.selectToDayOption = function (day, value) {
11828 scope.selectedToOption[day] = value;
11829 scope.TotimeList[day].value = value;
11830 scope.TotimeListDay[day] = false;
11831 scope.isToDropDownOpen = false;
11834 scope.addSelectedValue = function (value, fromtime, totime) {
11836 if (scope.daysList[value] !== undefined && !scope.daysList[value]) {
11837 for (count = 0, len = scope.customTime.length; count < len; count++) {
11838 if (scope.customTime[count].day === value) {
11839 if (scope.uncheckedFromTime) {
11840 scope.selectedFromOption[scope.customTime[count].day] = scope.uncheckedFromTime;
11842 scope.selectedFromOption[scope.customTime[count].day] = scope.FrtimeList[scope.customTime[count].day].value;
11845 if (scope.uncheckedToTime) {
11846 scope.selectedToOption[scope.customTime[count].day] = scope.uncheckedToTime;
11848 scope.selectedToOption[scope.customTime[count].day] = scope.TotimeList[scope.customTime[count].day].value;
11851 scope.customTime.splice(count, 1);
11856 if (scope.selectedFromOption[value] === scope.uncheckedFromTime) {
11858 if (angular.isDefined(scope.validatedCustomPreselect[value])) {
11859 scope.selectedFromOption[value] = scope.validatedCustomPreselect[value].FromTime;
11860 fromtime = scope.validatedCustomPreselect[value].FromTime;
11861 scope.FrtimeList[value].value = scope.validatedCustomPreselect[value].FromTime;
11863 scope.selectedFromOption[value] = scope.fromtime[0].value;
11864 fromtime = scope.fromtime[0].value;
11865 scope.FrtimeList[value].value = scope.fromtime[0].value;
11870 if (scope.selectedToOption[value] === scope.uncheckedToTime) {
11872 if (angular.isDefined(scope.validatedCustomPreselect[value])) {
11873 scope.selectedToOption[value] = scope.validatedCustomPreselect[value].ToTime;
11874 totime = scope.validatedCustomPreselect[value].ToTime;
11875 scope.TotimeList[value].value = scope.validatedCustomPreselect[value].ToTime;
11877 scope.selectedToOption[value] = scope.totime[0].value;
11878 totime = scope.totime[0].value;
11879 scope.TotimeList[value].value = scope.totime[0].value;
11883 custTime["day"] = value;
11884 custTime["FromTime"] = scope.FrtimeList[value].value;
11885 custTime["ToTime"] = scope.TotimeList[value].value;
11887 for (count = 0, len = scope.customTime.length; count < len; count++) {
11888 if (scope.customTime[count].day === value) {
11889 scope.customTime[count].FromTime = custTime["FromTime"];
11890 scope.customTime[count].ToTime = custTime["ToTime"];
11894 if (count === len) {
11895 var x = angular.copy(custTime);
11896 scope.customTime.push(x);
11899 scope.selCategory = scope.customTime;
11903 var outsideClick = function () {
11904 if (scope.showlist) {
11905 scope.$apply(function () {
11906 scope.showlist = false;
11911 $documentBind.click('showlist', outsideClick, scope);
11913 var outsideClickFromDropdown = function () {
11914 scope.$apply(function () {
11915 if (scope.isFromDropDownOpen) {
11916 scope.FrtimeListDay[dropDownOpenValue] = false;
11917 scope.isFromDropDownOpen = false;
11922 $documentBind.click('isFromDropDownOpen', outsideClickFromDropdown, scope);
11924 var outsideClickToDropdown = function () {
11925 scope.$apply(function () {
11926 if (scope.isToDropDownOpen) {
11927 scope.TotimeListDay[dropDownOpenValue] = false;
11928 scope.isToDropDownOpen = false;
11933 $documentBind.click('isToDropDownOpen', outsideClickToDropdown, scope);
11935 scope.selectOption = function (sItem) {
11937 if (sItem === hourpickerConfig.customOption) {
11938 scope.showDaysSelector = true;
11939 scope.selCategory = scope.customTime;
11941 scope.showDaysSelector = false;
11942 var fromTime = /[0-9]\s?am/i.exec(sItem);
11943 var toTime = /[0-9]\s?pm/i.exec(sItem);
11944 scope.selCategory = {
11946 FromTime: fromTime === null ? 'NA' : fromTime[0],
11947 ToTime: toTime === null ? 'NA' : toTime[0]
11951 scope.showlist = false;
11953 scope.selectedOption = sItem;
11959 .directive('attHourpickerValidator', ['hourpickerConfig', function (hourpickerConfig) {
11962 require: ['attHourpicker', 'ngModel'],
11963 link: function (scope, element, attr, ctrl) {
11965 var attHourpickerCtrl = ctrl[0];
11966 var ngModelCtrl = ctrl[1];
11968 //required format [h:MM tt] like '1:10 PM'
11969 var convertTimeStrngToMilitaryFormat = function (time) {
11970 var hours = Number(time.match(/^(\d+)/)[1]);
11971 var minutes = Number(time.match(/:(\d+)/)[1]);
11972 var AMPM = (time.match(/\s(.*)$/)[1]).toUpperCase();
11973 if (AMPM === 'PM' && hours < 12) {
11974 hours = hours + 12;
11976 if (AMPM === 'AM' && hours === 12) {
11977 hours = hours - 12;
11979 var sHours = hours.toString();
11980 var sMinutes = minutes.toString();
11982 sHours = '0' + sHours;
11984 if (minutes < 10) {
11985 sMinutes = '0' + sMinutes;
11987 return parseInt(sHours + sMinutes, 10);
11990 var compareTimeStrings = function (fromTimeString, toTimeString) {
11991 var fromMilitaryTime = convertTimeStrngToMilitaryFormat(fromTimeString);
11992 var toMilitaryTime = convertTimeStrngToMilitaryFormat(toTimeString);
11993 return (toMilitaryTime - fromMilitaryTime);
11996 var validateCustomData = function (finalDataModal) {
11998 if (attHourpickerCtrl.getSelectedOption() === hourpickerConfig.customOption) {
12000 var errorDaysCount = 0;
12002 for (var item in finalDataModal) {
12003 if (finalDataModal.hasOwnProperty(item)) {
12004 if (compareTimeStrings(finalDataModal[item].FromTime, finalDataModal[item].ToTime) <= 0) {
12005 attHourpickerCtrl.setToTimeErrorDay(finalDataModal[item].day, true);
12008 attHourpickerCtrl.setToTimeErrorDay(finalDataModal[item].day, false);
12013 if (errorDaysCount > 0) {
12015 ngModelCtrl.$setValidity('validationStatus', false);
12018 //validation successful
12019 ngModelCtrl.$setValidity('validationStatus', true);
12020 return finalDataModal;
12023 //default case no validation
12024 ngModelCtrl.$setValidity('validationStatus', true);
12025 return finalDataModal;
12030 ngModelCtrl.$parsers.unshift(validateCustomData);
12034 angular.module('att.abs.iconButtons', [])
12035 .constant('buttonConfig', {
12036 activeClass: 'active--button',
12037 toggleEvent: 'click'
12039 .directive('attIconBtnRadio', ['buttonConfig', function(buttonConfig) {
12040 var activeClass = buttonConfig.activeClass || 'active--button';
12041 var toggleEvent = buttonConfig.toggleEvent || 'click';
12043 require: 'ngModel',
12044 link: function(scope, element, attrs, ngModelCtrl) {
12045 element.attr("tabindex","0");
12046 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnRadio+"</span>");
12048 ngModelCtrl.$render = function() {
12049 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, attrs.attIconBtnRadio));
12052 element.parent().bind(toggleEvent, function() {
12053 if (!element.parent().hasClass(activeClass)) {
12054 scope.$apply(function() {
12055 ngModelCtrl.$setViewValue(attrs.attIconBtnRadio);
12056 ngModelCtrl.$render();
12063 .directive('attIconBtnCheckbox', ['buttonConfig', function(buttonConfig) {
12064 var activeClass = buttonConfig.activeClass || 'active--button';
12065 var toggleEvent = buttonConfig.toggleEvent || 'click';
12067 require: 'ngModel',
12068 link: function(scope, element, attrs, ngModelCtrl) {
12069 element.attr("tabindex","0");
12070 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnCheckbox+"</span>");
12071 function getTrueValue() {
12072 var trueValue = scope.$eval(attrs.btnCheckboxTrue);
12073 return angular.isDefined(trueValue) ? trueValue : true;
12075 function getFalseValue() {
12076 var falseValue = scope.$eval(attrs.btnCheckboxFalse);
12077 return angular.isDefined(falseValue) ? falseValue : false;
12080 ngModelCtrl.$render = function() {
12081 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
12084 element.parent().bind(toggleEvent, function() {
12085 scope.$apply(function() {
12086 ngModelCtrl.$setViewValue(element.parent().hasClass(activeClass) ? getFalseValue() : getTrueValue());
12087 ngModelCtrl.$render();
12094 angular.module('att.abs.links', ['ngSanitize'])
12095 .directive('attLink', [function() {
12098 link: function(scope, elem) {
12099 elem.addClass('link');
12100 if(!(elem.attr('href'))){
12101 elem.attr("tabindex", "0");
12106 .directive('attLinkVisited', [function() {
12109 link: function(scope, elem) {
12110 elem.addClass('link--visited');
12111 if(!(elem.attr('href'))){
12112 elem.attr("tabindex", "0");
12117 .directive('attReadmore', ['$timeout',function($timeout) {
12121 lines:"@noOfLines",
12123 //attribute to use readmore inside accordion
12126 templateUrl: 'app/scripts/ng_js_att_tpls/links/readMore.html',
12127 link: function(scope, elem) {
12129 scope.$watch('textModel', function(val){
12131 scope.textToDisplay = '';
12132 scope.readMoreLink = false;
12133 scope.readLessLink = false;
12134 scope.readFlag = false;
12137 if (typeof String.prototype.trim !== 'function') {
12138 String.prototype.trim = function() {
12139 return this.replace(/^\s+|\s+$/g, '');
12142 scope.textToDisplay = val.trim();
12143 scope.readFlag = true;
12144 $timeout(function() {
12145 var readElem = elem[0].children[0].children[0];
12147 if(window.getComputedStyle){
12148 height = parseInt(scope.lines) * parseFloat(window.getComputedStyle(readElem,null).getPropertyValue("height"));
12151 height = parseInt(scope.lines) * parseFloat(readElem.currentStyle.height);
12153 scope.elemHeight = height;
12154 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12157 scope.readMoreLink = true;
12158 scope.readLessLink = false;
12161 // Code to use readmore inside accordion
12162 var parentElem = elem.parent();
12163 if (parentElem.hasClass('att-accordion__body')) {
12164 scope.$watch('isOpen', function(val) {
12166 scope.readMoreLink = true;
12167 scope.readLessLink = false;
12168 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12169 scope.readFlag = true;
12173 scope.readMore = function() {
12174 scope.readMoreLink = false;
12175 scope.readLessLink = true;
12176 scope.readLinkStyle = {'height': 'auto'};
12177 scope.readFlag = false;
12178 var moreLink = angular.element(elem).children().eq(1).find('a')[0];
12179 $timeout(function()
12184 scope.readLess = function() {
12185 scope.readMoreLink = true;
12186 scope.readLessLink = false;
12187 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12188 scope.readFlag = true;
12189 var readLessLink = angular.element(elem).children().eq(0).find('a')[0];
12190 $timeout(function()
12192 readLessLink.focus();
12198 .directive('attLinksList', [function() {
12201 controller: function() {
12203 link: function(scope, elem) {
12204 elem.addClass('links-list');
12208 .directive('attLinksListItem', [function() {
12211 require: '^attLinksList',
12212 link: function(scope, elem) {
12213 elem.addClass('links-list__item');
12214 if(!(elem.attr('href'))){
12215 elem.attr("tabindex", "0");
12220 angular.module('att.abs.loading', [])
12221 .directive('attLoading', ['$window',function($window) {
12226 icon: '@attLoading',
12227 progressStatus: '=?',
12230 templateUrl: 'app/scripts/ng_js_att_tpls/loading/loading.html',
12231 link: function(scope, element) {
12232 var progressvalue = scope.progressStatus;
12233 scope.progressStatus = Math.min(100, Math.max(0, progressvalue));
12234 if($window.navigator.userAgent.indexOf("MSIE 8.")!==-1){
12235 var shiftX = 0, shiftY = scope.progressStatus * 36;
12237 'background-position-x' : shiftX,
12238 'background-position-y' : -shiftY
12244 angular.module('att.abs.modal', ['att.abs.utilities'])
12246 * A helper, internal data structure that acts as a map but also allows getting / removing
12247 * elements in the LIFO order
12249 .factory('$$stackedMap', function () {
12251 createNew: function () {
12255 add: function (key, value) {
12261 get: function (key) {
12262 for (var i = 0; i < stack.length; i++) {
12263 if (key === stack[i].key) {
12270 for (var i = 0; i < stack.length; i++) {
12271 keys.push(stack[i].key);
12276 return stack[stack.length - 1];
12278 remove: function (key) {
12280 for (var i = 0; i < stack.length; i++) {
12281 if (key === stack[i].key) {
12286 return stack.splice(idx, 1)[0];
12288 removeTop: function () {
12289 return stack.splice(stack.length - 1, 1)[0];
12291 length: function () {
12292 return stack.length;
12300 * A helper directive for the $modal service. It creates a backdrop element.
12302 .directive('modalBackdrop', ['$timeout', function ($timeout) {
12306 templateUrl: 'app/scripts/ng_js_att_tpls/modal/backdrop.html',
12307 link: function (scope) {
12308 scope.animate = false;
12309 //trigger CSS transitions
12310 $timeout(function () {
12311 scope.animate = true;
12317 .directive('modalWindow', ['$modalStack','$timeout','$document', function ($modalStack,$timeout,$document) {
12326 templateUrl: 'app/scripts/ng_js_att_tpls/modal/window.html',
12327 link: function (scope, element, attrs) {
12328 scope.windowClass = attrs.windowClass || '';
12329 if (attrs['modalTitle'] && attrs['modalTitle']!=="") {
12330 element[0].setAttribute('aria-label', attrs['modalTitle']);
12331 element[0].removeAttribute('modal-title');
12333 $timeout(function () {
12334 // trigger CSS transitions
12335 scope.focusModalFlag = true;
12336 scope.animate = true;
12338 $document.on('focus keydown', function(e){
12339 if (e.which ===9) {
12340 String.prototype.contains = function(it) {
12341 return this.indexOf(it) !== -1;
12343 if (element[0] !== e.target && !element[0].contains( e.target )) {
12344 element[0].focus();
12348 scope.close = function (evt) {
12349 var modal = $modalStack.getTop();
12350 if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
12351 // Check if preventDefault exists due to lack of support for IE8
12352 if (evt.preventDefault) {
12353 evt.preventDefault();
12354 evt.stopPropagation();
12356 evt.returnValue = false;
12358 $modalStack.dismiss(modal.key, 'backdrop click');
12365 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', 'events', 'keymap',
12366 function ($document, $compile, $rootScope, $$stackedMap, events, keymap) {
12367 var OPENED_MODAL_CLASS = 'modal-open';
12368 var backdropjqLiteEl, backdropDomEl;
12369 var backdropScope = $rootScope.$new(true);
12370 var openedWindows = $$stackedMap.createNew();
12371 var $modalStack = {};
12372 var modalLaunchingElement = undefined;
12373 function backdropIndex() {
12374 var topBackdropIndex = -1;
12375 var opened = openedWindows.keys();
12376 for (var i = 0; i < opened.length; i++) {
12377 if (openedWindows.get(opened[i]).value.backdrop) {
12378 topBackdropIndex = i;
12381 return topBackdropIndex;
12384 $rootScope.$watch(backdropIndex, function(newBackdropIndex){
12385 backdropScope.index = newBackdropIndex;
12388 function removeModalWindow(modalInstance) {
12390 var body = $document.find('body').eq(0);
12391 var html = $document.find('html').eq(0);
12392 var modalWindow = openedWindows.get(modalInstance).value;
12393 //clean up the stack
12394 openedWindows.remove(modalInstance);
12395 ////remove window DOM element
12396 modalWindow.modalDomEl.remove();
12397 body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
12398 html.css({overflow: 'scroll'});
12400 //remove backdrop if no longer needed
12401 if (backdropDomEl && backdropIndex() == -1) {
12402 backdropDomEl.remove();
12403 backdropDomEl = undefined;
12406 modalWindow.modalScope.$destroy();
12409 if (angular.isDefined(modalLaunchingElement) && modalLaunchingElement != null) {
12410 modalLaunchingElement.focus();
12413 $document.bind('keydown', function (evt) {
12415 if (evt.which === 27) {
12416 modal = openedWindows.top();
12417 if (modal && modal.value.keyboard) {
12418 $rootScope.$apply(function () {
12419 $modalStack.dismiss(modal.key);
12422 } else if (evt.keyCode === keymap.KEY.BACKSPACE) {
12423 var doPrevent = false;
12424 var d = evt.srcElement || evt.target;
12426 if (d.type === undefined) {
12428 } else if (d.tagName.toUpperCase() === 'INPUT' &&
12429 ( (type = d.type.toUpperCase()) === 'TEXT' ||
12430 type === 'PASSWORD' ||
12432 type === 'SEARCH' ||
12433 type === 'EMAIL' ||
12434 type === 'NUMBER' ||
12439 || d.tagName.toUpperCase() === 'TEXTAREA') {
12440 doPrevent = d.readOnly || d.disabled;
12445 events.preventDefault(evt);
12450 $modalStack.open = function (modalInstance, modal) {
12451 openedWindows.add(modalInstance, {
12452 deferred: modal.deferred,
12453 modalScope: modal.scope,
12454 backdrop: modal.backdrop,
12455 keyboard: modal.keyboard
12458 //Before opening modal, find the focused element
12459 modalLaunchingElement = document.activeElement;
12461 var body = $document.find('body').eq(0);
12462 var html = $document.find('html').eq(0);
12464 if (backdropIndex() >= 0 && !backdropDomEl) {
12465 backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
12466 backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
12467 body.append(backdropDomEl);
12469 var angularDomEl = angular.element('<div modal-window></div>');
12470 angularDomEl.attr('window-class', modal.windowClass);
12471 angularDomEl.attr('index', openedWindows.length() - 1);
12472 angularDomEl.attr('modal-title', modal.modalTitle);
12473 angularDomEl.html(modal.content);
12475 var modalDomEl = $compile(angularDomEl)(modal.scope);
12476 openedWindows.top().value.modalDomEl = modalDomEl;
12477 body.append(modalDomEl);
12478 body.addClass(OPENED_MODAL_CLASS);
12479 html.css({overflow: 'hidden'});
12482 $modalStack.close = function (modalInstance, result) {
12483 var modal = openedWindows.get(modalInstance);
12485 modal.value.deferred.resolve(result);
12486 removeModalWindow(modalInstance);
12490 $modalStack.dismiss = function (modalInstance, reason) {
12491 var modalWindow = openedWindows.get(modalInstance).value;
12493 modalWindow.deferred.reject(reason);
12494 removeModalWindow(modalInstance);
12498 $modalStack.getTop = function () {
12499 return openedWindows.top();
12502 return $modalStack;
12505 .provider('$modal', function () {
12507 var $modalProvider = {
12509 //can be also false or 'static'
12513 $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
12514 function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
12516 function getTemplatePromise(options) {
12517 return options.template ? $q.when(options.template) :
12518 $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
12519 return result.data;
12523 function getResolvePromises(resolves) {
12524 var promisesArr = [];
12525 angular.forEach(resolves, function (value) {
12526 if (angular.isFunction(value) || angular.isArray(value)) {
12527 promisesArr.push($q.when($injector.invoke(value)));
12530 return promisesArr;
12532 $modal.open = function (modalOptions) {
12533 var modalResultDeferred = $q.defer();
12534 var modalOpenedDeferred = $q.defer();
12536 //prepare an instance of a modal to be injected into controllers and returned to a caller
12537 var modalInstance = {
12538 result: modalResultDeferred.promise,
12539 opened: modalOpenedDeferred.promise,
12540 close: function (result) {
12541 $modalStack.close(modalInstance, result);
12543 dismiss: function (reason) {
12544 $modalStack.dismiss(modalInstance, reason);
12547 //merge and clean up options
12548 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
12549 modalOptions.resolve = modalOptions.resolve || {};
12552 if (!modalOptions.template && !modalOptions.templateUrl) {
12553 throw new Error('One of template or templateUrl options is required.');
12556 var templateAndResolvePromise =
12557 $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
12558 templateAndResolvePromise.then(function(tplAndVars) {
12559 var modalScope = (modalOptions.scope || $rootScope).$new();
12560 modalScope.$close = modalInstance.close;
12561 modalScope.$dismiss = modalInstance.dismiss;
12563 var ctrlInstance, ctrlLocals = {};
12564 var resolveIter = 1;
12567 if (modalOptions.controller) {
12568 ctrlLocals.$scope = modalScope;
12569 ctrlLocals.$modalInstance = modalInstance;
12570 angular.forEach(modalOptions.resolve, function (value, key) {
12571 ctrlLocals[key] = tplAndVars[resolveIter++];
12574 ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
12577 $modalStack.open(modalInstance, {
12579 deferred: modalResultDeferred,
12580 content: tplAndVars[0],
12581 backdrop: modalOptions.backdrop,
12582 keyboard: modalOptions.keyboard,
12583 windowClass: modalOptions.windowClass,
12584 modalTitle: modalOptions.modalTitle
12587 }, function(reason) {
12588 modalResultDeferred.reject(reason);
12591 templateAndResolvePromise.then(function () {
12592 modalOpenedDeferred.resolve(true);
12594 modalOpenedDeferred.reject(false);
12597 return modalInstance;
12604 return $modalProvider;
12607 .directive("simpleModal", ["$modal", function($modal) {
12620 link: function(scope, elm) {
12621 elm.bind('click', function(ev) {
12622 ev.preventDefault();
12623 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
12624 scope.simpleModal = elm.attr("href");
12627 scope.backdrop === "false" ? scope.backdropclick = 'static' : scope.backdropclick = true;
12628 scope.keyboard === "false" ? scope.keyboardev = false : scope.keyboardev = true;
12631 templateUrl: scope.simpleModal,
12632 backdrop:scope.backdropclick,
12633 keyboard:scope.keyboardev,
12634 windowClass:scope.windowClass,
12635 controller: scope.controller,
12636 modalTitle: scope.modalTitle
12637 }).result.then(scope.modalOk, scope.modalCancel);
12643 .directive('tabbedItem', ['$modal', '$log',function ($modal, $log){
12653 templateUrl: 'app/scripts/ng_js_att_tpls/modal/tabbedItem.html',
12654 controller: ['$scope', '$rootScope', '$attrs', function ($scope) {
12655 $scope.clickTab = function (index) {
12656 for (var i = 0; i < $scope.items.length; i++) {
12658 $scope.items[i].isTabOpen = true;
12659 $scope.items[i].showData = true;
12662 $scope.items[i].isTabOpen = false;
12663 $scope.items[i].showData = false;
12666 var modalInstance = $modal.open({
12667 templateUrl: $scope.templateId,
12668 controller: $scope.controller,
12669 windowClass: 'tabbedOverlay_modal',
12670 modalTitle: $scope.modalTitle,
12672 items: function () {
12673 return $scope.items;
12677 modalInstance.result.then(function (selectedItem) {
12678 $scope.selected = selectedItem;
12680 $log.info('Modal dismissed at: ' + new Date());
12683 $scope.isActiveTab = function (index) {
12684 return $scope.items && $scope.items[index] && $scope.items[index].isTabOpen;
12690 .directive('tabbedOverlay', [function () {
12698 templateUrl: 'app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html',
12699 controller: ['$scope', function ($scope) {
12700 $scope.clickTab = function (index) {
12701 for (var i = 0; i < $scope.items.length; i++) {
12703 $scope.items[i].isTabOpen = true;
12704 $scope.items[i].showData = true;
12707 $scope.items[i].isTabOpen = false;
12708 $scope.items[i].showData = false;
12712 $scope.isActiveTab = function (index) {
12713 return $scope.items && $scope.items[index] && $scope.items[index].isTabOpen;
12718 angular.module('att.abs.pagination', ['att.abs.utilities'])
12719 .directive('attPagination', [ function() {
12729 templateUrl: 'app/scripts/ng_js_att_tpls/pagination/pagination.html',
12730 link: function(scope) {
12732 scope.$watch('totalPages', function(value) {
12733 if(angular.isDefined(value) && value !== null){
12736 scope.totalPages = 1;
12740 for (var i = 1; i <= value; i++) {
12741 scope.pages.push(i);
12743 } else if (value > 7) {
12744 var midVal = Math.ceil(value / 2);
12745 scope.pages = [midVal - 1, midVal, midVal + 1];
12747 currentPageChanged(1);
12750 scope.$watch('currentPage', function(value) {
12751 currentPageChanged(value);
12753 var callbackHandler = function(num) {
12754 if (angular.isFunction(scope.clickHandler)){
12755 scope.clickHandler(num);
12758 function currentPageChanged(value) {
12759 if (angular.isDefined(value) && value !== null) {
12760 if (!value || value < 1) {
12763 if (value > scope.totalPages) {
12764 value = scope.totalPages;
12766 if(scope.currentPage !== value) {
12767 scope.currentPage = value;
12768 callbackHandler(scope.currentPage);
12770 if (scope.totalPages > 7) {
12771 if (value < scope.pages[0] && value > 3) {
12772 scope.pages = [value, value + 1, value + 2];
12773 } else if (value > scope.pages[2] && value < scope.totalPages - 2) {
12774 scope.pages = [value - 2, value - 1, value];
12775 } else if (value <= 3) {
12776 scope.pages = [1, 2, 3];
12777 } else if (value >= scope.totalPages - 2) {
12778 scope.pages = [scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
12783 scope.next = function(event) {
12784 event.preventDefault();
12785 if (scope.currentPage < scope.totalPages) {
12786 scope.currentPage += 1;
12787 callbackHandler(scope.currentPage);
12790 scope.prev = function(event) {
12791 event.preventDefault();
12792 if (scope.currentPage > 1) {
12793 scope.currentPage -= 1;
12794 callbackHandler(scope.currentPage);
12797 scope.selectPage = function(value, event) {
12798 event.preventDefault();
12799 scope.currentPage = value;
12800 scope.focusedPage = value;
12801 callbackHandler(scope.currentPage);
12803 scope.checkSelectedPage = function(value) {
12804 if(scope.currentPage === value) {
12809 scope.isFocused = function(page) {
12810 return scope.focusedPage === page;
12816 angular.module('att.abs.paneSelector',['att.abs.utilities'])
12817 .constant('paneGroupConstants',{
12818 SIDE_WIDTH_DEFAULT: '33%',
12819 INNER_PANE_DEFAULT: '67%',
12820 SIDE_PANE_ID: 'sidePane',
12821 NO_DRILL_DOWN: 'none'
12823 .factory('animation', function(){
12825 }).directive('attPaneAccessibility',['keymap','$window',function(keymap,$window) {
12828 require: ['^?sidePane','^?innerPane'],
12829 link: function (scope, elem,attr,ctrl) {
12830 var sidepaneCtrl = ctrl[0],innerPaneCtrl = ctrl[1],ieFlag=false;
12831 scope.ie = (function () {
12832 var undef,v = 3,div = document.createElement('div'),
12833 all = div.getElementsByTagName('i');
12835 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i>< ![endif]-->',
12838 return v > 4 ? v : undef;
12840 if(scope.ie === 8){
12846 elem.bind('keydown',function(ev){
12847 if (keymap.isAllowedKey(ev.keyCode) || keymap.isControl(ev) || keymap.isFunctionKey(ev)) {
12848 ev.preventDefault();
12849 ev.stopPropagation();
12851 switch (ev.keyCode) {
12852 case keymap.KEY.DOWN:
12853 el = angular.element(elem[0])[0];
12854 if(el && el.nextElementSibling){
12855 el.nextElementSibling.focus();
12860 if (el && el.nextSibling){
12861 el = el.nextSibling;
12866 } while (el && el.tagName !== 'DIV');
12870 case keymap.KEY.UP:
12871 el = angular.element(elem[0])[0];
12872 if(el && el.previousElementSibling){
12873 el.previousElementSibling.focus();
12878 if (el && el.previousSibling){
12879 el = el.previousSibling;
12884 } while (el && el.tagName !== 'DIV');
12888 case keymap.KEY.RIGHT:
12889 if(angular.isDefined(sidepaneCtrl)){
12890 el = sidepaneCtrl.getElement()[0];
12892 if(angular.isDefined(innerPaneCtrl)){
12893 el = innerPaneCtrl.getElement()[0];
12896 if (el && el.nextElementSibling){
12897 el = el.nextElementSibling;
12902 }while(window.getComputedStyle(el, null).getPropertyValue("display") === 'none');
12906 if (el && el.nextSibling){
12907 el = el.nextSibling;
12912 }while ((el && el.tagName == 'DIV') && el.currentStyle['display'] == 'none');
12915 el.querySelector("[att-pane-accessibility]").focus();
12918 case keymap.KEY.LEFT:
12919 if(angular.isDefined(sidepaneCtrl)){
12920 el = sidepaneCtrl.getElement()[0];
12922 if(angular.isDefined(innerPaneCtrl)){
12923 el = innerPaneCtrl.getElement()[0];
12926 if (el && el.previousElementSibling){
12927 el = el.previousElementSibling;
12932 }while (window.getComputedStyle(el, null).getPropertyValue("display") == 'none');
12937 if (el && el.previousSibling){
12938 el = el.previousSibling;
12943 }while((el && el.tagName == 'DIV') && el.currentStyle['display'] == 'none');
12946 el.querySelector("[att-pane-accessibility]").focus();
12957 .directive('sideRow', [function(){
12961 require: ['^sidePane','^paneGroup'],
12962 link: function(scope,element,attr,ctrls){
12963 var sidePaneCtrl = ctrls[0];
12964 var paneGroupCtrl = ctrls[1];
12967 Reset the sidePaneId array if a new
12968 set of ngRepeat data appeared
12970 sidePaneCtrl.sidePaneIds = [];
12972 var paneId =attr['paneId'];
12973 var drillDownTo = attr['drillDownTo'];
12974 sidePaneCtrl.sidePaneRows.push({'paneId':paneId, 'drillDownTo':drillDownTo});
12975 element.on('click', function(){
12976 sidePaneCtrl.currentSelectedRowPaneId = paneId;
12977 paneGroupCtrl.slideOutPane(paneId,true);
12982 .controller('SidePaneCtrl',['$scope', '$element','animation', 'paneGroupConstants',
12983 function($scope,$element,animation, paneGroupConstants){
12984 this.getElement = function(){
12987 this.sidePaneTracker = {};
12988 this.currentWidth = paneGroupConstants.SIDE_WIDTH_DEFAULT;
12989 this.paneId = paneGroupConstants.SIDE_PANE_ID;
12990 this.currentSelectedRowPaneId;
12991 this.drillDownToMapper = {};
12992 this.sidePaneRows = [];
12993 this.init = function(){
12994 var sidePaneRows = this.sidePaneRows;
12996 for(var index in sidePaneRows){
12997 if (sidePaneRows.hasOwnProperty(index)) {
12998 var paneId = sidePaneRows[index].paneId;
12999 var drillDownTo = sidePaneRows[index].drillDownTo;
13000 this.drillDownToMapper[paneId] = drillDownTo;
13002 this.currentSelectedRowPaneId = paneId;
13003 this.sidePaneTracker[paneId] = [];
13009 this.getSidePanesList = function(){
13010 return this.sidePaneTracker[this.currentSelectedRowPaneId];
13012 this.addToSidePanesList = function(newPaneId){
13013 if(this.sidePaneTracker[this.currentSelectedRowPaneId] === undefined){
13014 this.sidePaneTracker[this.currentSelectedRowPaneId] = [];
13016 else if(newPaneId){
13017 this.sidePaneTracker[this.currentSelectedRowPaneId].push(newPaneId);
13020 this.setWidth = function(val){
13022 this.currentWidth = val;
13024 animation.set($element,{width:this.currentWidth});
13026 this.resizeWidth = function(val){
13028 this.currentWidth = val;
13030 animation.to($element,.5,{width:val});
13034 .directive('sidePane', ['paneGroupConstants', function(paneGroupConstants){
13039 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/sidePane.html',
13040 require: ['^paneGroup', 'sidePane'],
13041 controller: 'SidePaneCtrl',
13043 link: function(scope,element,attr, ctrls){
13044 var paneGroupCtrl = ctrls[0];
13045 var sidePaneCtrl = ctrls[1];
13046 paneGroupCtrl.addPaneCtrl(paneGroupConstants.SIDE_PANE_ID, sidePaneCtrl);
13050 .directive('drillDownRow', ['$parse', 'paneGroupConstants',function($parse,paneGroupConstants){
13054 require: ['^innerPane','^paneGroup'],
13055 link: function(scope,element,attr,ctrls){
13056 var innerPaneCtrl = ctrls[0];
13057 var paneGroupCtrl = ctrls[1];
13058 element.on('click', function(){
13059 var drillDownTo = innerPaneCtrl.drillDownTo;
13060 if(innerPaneCtrl.drillDownTo !== paneGroupConstants.NO_DRILL_DOWN){
13061 paneGroupCtrl.slideOutPane(drillDownTo);
13063 element[0].focus();
13068 .controller('InnerPaneCtrl', ['$scope', '$element','animation', 'paneGroupConstants',
13069 function($scope,$element,animation,paneGroupConstants){
13070 this.getElement = function(){
13073 this.paneId = $scope.paneId;
13075 this.currentWidth = paneGroupConstants.INNER_PANE_DEFAULT;
13076 this.setWidth = function(val){
13078 this.currentWidth = val;
13080 animation.set($element,{width:this.currentWidth});
13082 this.resizeWidth = function(val,callback){
13083 animation.to($element,.25,{width:val,onComplete: callback});
13085 this.displayNone = function(){
13086 animation.set($element, {display:'none'});
13088 this.displayBlock = function(){
13089 animation.set($element,{display:'block'});
13091 this.hideRightBorder();
13094 this.floatLeft = function(){
13095 animation.set($element,{float:'left'});
13097 this.hideLeftBorder = function(){
13098 animation.set($element, {borderLeftWidth: '0px'});
13100 this.showLeftBorder = function(){
13101 animation.set($element,{borderLeftWidth: '1px'});
13103 this.hideRightBorder = function(){
13104 animation.set($element,{borderRightWidth: '0px'});
13106 this.showRightBorder = function(){
13107 animation.set($element, {borderRightWidth: '1px'});
13109 this.slideFromRight = function(){
13110 animation.set($element, {float:'right'});
13111 animation.set($element, {width: this.currentWidth});
13113 this.startOpen = function(){
13114 return $scope.startOpen;
13117 .directive('innerPane', function(){
13122 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/innerPane.html',
13123 require: ['^paneGroup', 'innerPane'],
13124 controller: 'InnerPaneCtrl',
13128 link: function(scope,element,attr,ctrls){
13129 if(attr.startOpen === ""){
13130 scope.startOpen = true;
13132 var paneGroupCtrl = ctrls[0];
13133 var innerPaneCtrl = ctrls[1];
13134 paneGroupCtrl.addPaneCtrl(scope.paneId,innerPaneCtrl);
13138 .controller('PaneGroupCtrl', ['$scope', '$element', 'paneGroupConstants',function($scope,$element,paneGroupConstants){
13140 this.accountLevelPaneModel = [];
13141 this.title = $scope.title;
13142 this.init = function(){
13143 var sidePane = this.panes[paneGroupConstants.SIDE_PANE_ID];
13147 //Show the other panes that may be set to startOpen
13148 //numOpen starts at 1 because of the side pane
13151 for(key in this.panes){
13152 if(this.panes[key].startOpen && this.panes[key].startOpen()){
13158 width = ((100/numOpen)) + '%';
13160 if(this.panes[sidePane.currentSelectedRowPaneId])
13163 sidePane.setWidth(width);
13164 this.panes[sidePane.currentSelectedRowPaneId].setWidth(width);
13167 sidePane.setWidth();
13168 this.panes[sidePane.currentSelectedRowPaneId].setWidth();
13170 this.panes[sidePane.currentSelectedRowPaneId].displayBlock();
13171 for(key in this.panes){
13172 if(key !== paneGroupConstants.SIDE_PANE_ID && key !== sidePane.currentSelectedRowPaneId){
13173 this.panes[key].displayNone();
13175 this.panes[key].drillDownTo = sidePane.drillDownToMapper[key];
13178 openOtherPanesOnStart(sidePane, this.panes);
13181 function openOtherPanesOnStart(sidePane, panes){
13182 //Build an array of the panes that need to be out
13183 var otherPanesStartOpened = [];
13185 for(index in sidePane.sidePaneRows){
13186 if (sidePane.sidePaneRows.hasOwnProperty(index)) {
13187 var pane = sidePane.sidePaneRows[index];
13189 //Skip the first pane row since we handled it in the begining
13190 if(index > 0 && panes[pane.paneId].startOpen && panes[pane.paneId].startOpen()){
13191 otherPanesStartOpened.push(pane);
13192 //Remember the panes that are opened for the first pane row Index
13193 sidePane.addToSidePanesList(pane.paneId);
13199 for(index in otherPanesStartOpened){
13200 if (otherPanesStartOpened.hasOwnProperty(index)) {
13201 var paneId = otherPanesStartOpened[index].paneId;
13202 var paneCtrl = panes[paneId];
13203 if(paneCtrl && paneCtrl.setWidth && paneCtrl.displayBlock){
13204 paneCtrl.setWidth(width);
13205 paneCtrl.displayBlock();
13215 Resets all the panels to their original positions at the end of a sidebar click
13216 By setting the sideBar to its default width
13217 Setting all panes to float left and displaynone
13218 Setting the pane that was clicked to default width and slide right
13221 this.resetPanes = function(){
13222 for(var key in this.panes){
13223 if(this.panes.hasOwnProperty(key)){
13224 var pane = this.panes[key];
13225 if(pane && (pane.paneId !== paneGroupConstants.SIDE_PANE_ID)){
13227 pane.displayNone();
13232 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13233 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
13237 this.addPaneCtrl = function(paneId,paneCtrl){
13238 this.panes[paneId] = paneCtrl;
13241 this._slideOutPane = function(paneId,isFromSidePane){
13243 //Check current side pane stack to see how many panes are already open for that side pane choice
13244 //then add the new pane that needs to be there
13246 if(isFromSidePane){
13248 //Check if the side pane id has already been clicked
13249 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13250 panesList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13253 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID] && this.panes[paneId]){
13254 this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId = paneId;
13255 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList();
13257 this.panes[paneId].slideFromRight();
13258 this.panes[paneId].displayBlock();
13260 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
13263 else if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID]){
13264 //Restore the panes based on the panelist
13265 if(panesList.length === 0 && this.panes[paneId]){
13266 //Only one pane is out
13267 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
13268 this.panes[paneId].displayBlock();
13269 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
13272 //Multiple panes out
13273 var numPanes = panesList.length + 2;
13274 var width = ((100/numPanes)) + '%';
13275 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(width);
13277 //Set the sidePanes pane
13278 //set the panes children list
13279 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13280 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
13281 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].setWidth(width);
13283 for(var i in panesList){
13284 if(this.panes[panesList[i]]){
13285 this.panes[panesList[i]].displayBlock();
13286 this.panes[panesList[i]].setWidth(width);
13294 //Have to check the paneId that was given and where it is drilling down to
13295 var isPaneInStack = false;
13297 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13298 stackPaneList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13300 for(var j in stackPaneList){
13301 if(stackPaneList.hasOwnProperty(j)){
13302 var pId = stackPaneList[j];
13303 if(pId === paneId){
13304 isPaneInStack = true;
13309 if(!isPaneInStack && this.panes[paneGroupConstants.SIDE_PANE_ID]){
13310 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList(paneId);
13312 var sidePanesListLength;
13313 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13314 sidePanesListLength = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList().length;
13316 var numberPanes = sidePanesListLength + 2;
13317 var widthToSet = ((100/numberPanes)) + '%';
13318 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13319 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(widthToSet);
13323 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13324 slideInPaneId = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList()[sidePanesListLength - 1];
13329 if(that.panes[paneGroupConstants.SIDE_PANE_ID]){
13330 panesList = that.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13333 for(var p in panesList){
13334 if(panesList.hasOwnProperty(p)){
13335 var paneListPaneId = panesList[p];
13336 var pane = this.panes[paneListPaneId];
13337 if(paneListPaneId !== slideInPaneId && pane){
13338 pane.setWidth(widthToSet);
13339 pane.displayBlock();
13345 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13346 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
13347 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].showRightBorder();
13349 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].resizeWidth(widthToSet,function(){
13351 if(that.panes[slideInPaneId] && that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13352 that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].hideRightBorder();
13353 that.panes[slideInPaneId].setWidth(widthToSet);
13354 that.panes[slideInPaneId].slideFromRight();
13355 that.panes[slideInPaneId].displayBlock();
13356 that.panes[slideInPaneId].floatLeft();
13364 this.slideOutPane = function(paneId,isFromSidePane){
13365 this._slideOutPane(paneId,isFromSidePane);
13368 .directive('paneGroup', ['$timeout',function($timeout){
13373 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html',
13376 controller: 'PaneGroupCtrl',
13377 link: function(scope,element,attr,ctrl){
13378 $timeout(initialize,100);
13379 function initialize(){
13385 angular.module('att.abs.tooltip', ['att.abs.position', 'att.abs.utilities', 'ngSanitize'])
13386 // The default options tooltip and popover.
13387 .constant('tooltipDefaultOptions', {
13388 placement: 'above',
13396 * The $tooltip service creates tooltip- and popover-like directives as well as
13397 * houses global options for them.
13399 .provider('$tooltip', ['tooltipDefaultOptions', function(tooltipDefaultOptions) {
13401 // Default hide triggers for each show trigger
13403 'mouseenter': 'mouseleave',
13406 'mouseover':'mouseout'
13409 // The options specified to the provider globally.
13410 var globalOptions = {};
13412 this.options = function(value) {
13413 angular.extend(globalOptions, value);
13417 * This allows you to extend the set of trigger mappings available. E.g.:
13419 * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
13421 this.setTriggers = function(triggers) {
13422 angular.extend(triggerMap, triggers);
13426 * This is a helper function for translating camel-case to snake-case.
13428 function snakeCase(name) {
13429 var regexp = /[A-Z]/g;
13430 var separator = '-';
13431 return name.replace(regexp, function(letter, pos) {
13432 return (pos ? separator : '') + letter.toLowerCase();
13437 * Returns the actual instance of the $tooltip service.
13439 this.$get = ['$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', '$attElementDetach', function($window, $compile, $timeout, $parse, $document, $position, $interpolate, $attElementDetach) {
13440 return function (type, prefix, defaultTriggerShow) {
13441 var options = angular.extend({}, tooltipDefaultOptions, globalOptions);
13443 * Returns an object of show and hide triggers.
13445 * If a trigger is supplied,
13446 * it is used to show the tooltip; otherwise, it will use the `trigger`
13447 * option passed to the `$tooltipProvider.options` method; else it will
13448 * default to the trigger supplied to this directive factory.
13450 * The hide trigger is based on the show trigger. If the `trigger` option
13451 * was passed to the `$tooltipProvider.options` method, it will use the
13452 * mapped trigger from `triggerMap` or the passed trigger if the map is
13453 * undefined; otherwise, it uses the `triggerMap` value of the show
13454 * trigger; else it will just use the show trigger.
13456 function getTriggers(trigger) {
13457 var show = trigger || options.trigger || defaultTriggerShow;
13458 var hide = triggerMap[show] || show;
13465 var directiveName = snakeCase(type);
13467 var startSym = $interpolate.startSymbol();
13468 var endSym = $interpolate.endSymbol();
13473 link: function (scope, element, attrs) {
13474 /* Allows a developer to force element to be non-tabable */
13475 if (!element.attr('tabindex')) {
13476 element.attr('tabindex', '0');
13479 var isElementHovered = false;
13480 element.bind('mouseenter', function(){
13481 isElementHovered = true;
13482 element.removeAttr('title');
13484 element.bind('mouseleave', function(){
13485 isElementHovered = false;
13486 // setTooltipAriaLabel();
13489 /* We store our attributes on our scope so any user of $tooltip service can access attributes */
13490 scope.parentAttrs = attrs;
13492 '<div ' + directiveName + '-popup ' +
13493 'title="' + startSym + 'tt_title' + endSym + '" ' +
13494 'content="' + startSym + 'tt_content' + endSym + '" ' +
13495 'placement="' + startSym + 'tt_placement' + endSym + '" ' +
13496 'animation="tt_animation()" ' +
13497 'is-open="tt_isOpen" ' +
13498 'stylett="' + startSym + 'tt_style' + endSym + '" ' +
13502 var tooltip = $compile(template)(scope);
13503 var transitionTimeout;
13506 var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
13507 var triggers = getTriggers(undefined);
13508 var hasRegisteredTriggers = false;
13509 var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
13510 var tooltipOffset = 0;
13511 var tooltipAriaLabelDefined = false;
13513 // By default, the tooltip is not open.
13514 // add ability to start tooltip opened
13515 scope.tt_isOpen = false;
13517 //Adding a scope watch, to remove the created popup from DOM, incase it is updated outside the provider code.
13518 scope.$watch('tt_isOpen', function(newVal, oldVal){
13519 if(newVal !== oldVal && !newVal){
13520 $attElementDetach(tooltip[0]);
13524 function toggleTooltipBind() {
13525 if (!scope.tt_isOpen) {
13532 // Show the tooltip with delay if specified, otherwise show it immediately
13533 function showTooltipBind() {
13534 if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
13537 if (scope.tt_popupDelay) {
13538 popupTimeout = $timeout(show, scope.tt_popupDelay);
13540 scope.$apply(show);
13544 function hideTooltipBind() {
13545 scope.$apply(function() {
13550 // Show the tooltip popup element.
13557 // Don't show empty tooltips.
13558 if (!scope.tt_content) {
13562 // If there is a pending remove transition, we must cancel it, lest the
13563 // tooltip be mysteriously removed.
13564 if (transitionTimeout) {
13565 $timeout.cancel(transitionTimeout);
13568 // Set the initial positioning.
13569 tooltip.css({top: 0, left: 0, display: 'block', 'z-index': 9999});
13571 // Now we add it to the DOM because need some info about it. But it's not
13572 // visible yet anyway.
13573 if (appendToBody) {
13574 $body = $body || $document.find('body');
13575 $body.append(tooltip);
13577 element.after(tooltip);
13580 // Get the position of the directive element.
13581 position = appendToBody ? $position.offset(element) : $position.position(element);
13583 // Get the height and width of the tooltip so we can center it.
13584 ttWidth = tooltip.prop('offsetWidth');
13585 ttHeight = tooltip.prop('offsetHeight');
13587 // Calculate the tooltip's top and left coordinates to center it with
13589 var ttArrowOffset = 10;
13590 switch (scope.tt_placement) {
13594 top: position.top + position.height / 2 - ttHeight / 2,
13595 left: (position.left + position.width) + tooltipOffset
13599 top: position.top + position.height / 2 - ttHeight / 2,
13600 left: (position.left + position.width + ttArrowOffset) + tooltipOffset
13607 top: (position.top + position.height) + tooltipOffset,
13608 left: position.left + position.width / 2 - ttWidth / 2
13612 top: (position.top + position.height + ttArrowOffset) + tooltipOffset,
13613 left: position.left + position.width / 2 - ttWidth / 2
13620 top: position.top + position.height / 2 - ttHeight / 2,
13621 left: (position.left - ttWidth) - tooltipOffset
13625 top: position.top + position.height / 2 - ttHeight / 2,
13626 left: (position.left - ttWidth - ttArrowOffset) - tooltipOffset
13633 top: (position.top - ttHeight) - tooltipOffset,
13634 left: position.left + position.width / 2 - ttWidth / 2
13638 top: (position.top - ttHeight - ttArrowOffset) - tooltipOffset,
13639 left: position.left + position.width / 2 - ttWidth / 2
13645 ttPosition.top += 'px';
13646 ttPosition.left += 'px';
13648 // Now set the calculated positioning.
13649 tooltip.css(ttPosition);
13651 // And show the tooltip.
13652 scope.tt_isOpen = true;
13655 // Hide the tooltip popup element.
13657 // First things first: we don't show it anymore.
13658 scope.tt_isOpen = false;
13660 //if tooltip is going to be shown after delay, we must cancel this
13661 $timeout.cancel(popupTimeout);
13663 // And now we remove it from the DOM. However, if we have animation, we
13664 // need to wait for it to expire beforehand.
13665 // This is a placeholder for a port of the transitions library.
13666 if (angular.isDefined(scope.tt_animation) && scope.tt_animation()) {
13667 transitionTimeout = $timeout(function() {
13668 $attElementDetach(tooltip[0]);
13671 $attElementDetach(tooltip[0]);
13675 function setTooltipAriaLabel() {
13676 element.removeAttr('title');
13677 if(!isElementHovered){
13678 if (tooltipAriaLabelDefined) {
13679 element.attr('title', scope.tooltipAriaLabel);
13681 element.attr('title', scope.tt_content);
13687 * Observe the relevant attributes.
13689 attrs.$observe(type, function(val) {
13691 scope.tt_content = val;
13692 // setTooltipAriaLabel();
13694 if (scope.tt_isOpen) {
13700 attrs.$observe(prefix + 'Title', function(val) {
13701 scope.tt_title = val;
13704 attrs.$observe(prefix + 'Placement', function(val) {
13705 scope.tt_placement = angular.isDefined(val) ? val : options.placement;
13708 attrs.$observe(prefix + 'Style', function(val) {
13709 scope.tt_style = angular.isDefined(val) ? val : options.stylett;
13712 attrs.$observe(prefix + 'Animation', function(val) {
13713 scope.tt_animation = angular.isDefined(val) ? $parse(val) : function() {
13714 return options.animation;
13718 attrs.$observe(prefix + 'PopupDelay', function(val) {
13719 var delay = parseInt(val, 10);
13720 scope.tt_popupDelay = !isNaN(delay) ? delay : options.popupDelay;
13723 attrs.$observe(prefix + 'Trigger', function(val) {
13725 if (hasRegisteredTriggers) {
13726 element.unbind(triggers.show, showTooltipBind);
13727 element.unbind(triggers.hide, hideTooltipBind);
13730 triggers = getTriggers(val);
13732 /* This fixes issue in which a click on input field with trigger as focus
13733 causes focus to fire following click thus making tooltip flash. */
13734 if (triggers.show === 'focus') {
13735 element.bind('focus', showTooltipBind);
13736 element.bind('blur', hideTooltipBind);
13737 element.bind('click', function(e) {
13738 e.stopPropagation();
13740 } else if (triggers.show === triggers.hide) {
13741 element.bind(triggers.show, toggleTooltipBind);
13743 element.bind(triggers.show, showTooltipBind);
13744 element.bind(triggers.hide, hideTooltipBind);
13747 hasRegisteredTriggers = true;
13750 attrs.$observe(prefix + 'AppendToBody', function (val) {
13751 appendToBody = angular.isDefined(val) ? $parse(val)(scope) : appendToBody;
13754 attrs.$observe(prefix + 'Offset', function (val) {
13755 tooltipOffset = angular.isDefined(val) ? parseInt(val, 10) : 0;
13758 attrs.$observe(prefix + 'AriaLabel', function (val) {
13759 if (angular.isDefined(val)) {
13760 scope.tooltipAriaLabel = val;
13761 tooltipAriaLabelDefined = true;
13763 tooltipAriaLabelDefined = false;
13765 setTooltipAriaLabel();
13768 // if a tooltip is attached to <body> we need to remove it on
13769 // location change as its parent scope will probably not be destroyed
13771 if (appendToBody) {
13772 scope.$on('$locationChangeSuccess', function() {
13773 if (scope.tt_isOpen) {
13779 // Make sure tooltip is destroyed and removed.
13780 scope.$on('$destroy', function() {
13781 if (scope.tt_isOpen) {
13793 .directive('tooltipPopup', ['$document', '$documentBind', function($document, $documentBind) {
13798 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
13799 templateUrl: 'app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html',
13800 link: function(scope, elem) {
13801 scope.$watch("isOpen", function() {
13804 elem.bind('click', function (e) {
13805 e.stopPropagation();
13807 var outsideClick = function() {
13808 scope.$apply(function() {
13809 scope.isOpen = false;
13813 $documentBind.event('click', 'isOpen', outsideClick, scope, true, 10);
13818 .directive('tooltip', ['$tooltip', function($tooltip) {
13819 return $tooltip('tooltip', 'tooltip', 'mouseenter');
13822 .directive('tooltipCondition', [ '$timeout',function($timeout) {
13827 tooltipCondition:"@?"
13829 template:'<p><span tooltip=\"{{tooltipCondition}}\" ng-if=\"showpop\">{{tooltipCondition}}</span><span id=\"innerElement\" ng-hide=\"showpop\">{{tooltipCondition}}</span></p>',
13830 link: function(scope, elem, attr){
13831 scope.showpop=false;
13832 if(attr.height==='true'){
13833 $timeout(function () {
13834 var maxHeight=(elem[0].offsetHeight);
13835 var elemHeight=elem.children(0)[0].offsetHeight;
13836 if(elemHeight > maxHeight){
13837 scope.showpop=true;
13841 else if(scope.tooltipCondition.length>=25){
13842 scope.showpop=true;
13847 angular.module('att.abs.popOvers', ['att.abs.tooltip', 'att.abs.utilities', 'ngSanitize'])
13848 .directive('popover', ['$tooltip', function($tooltip) {
13849 return $tooltip('popover', 'popover', 'click');
13851 .directive('popoverPopup', ['$document', '$documentBind', '$timeout', 'events', 'DOMHelper', function($document, $documentBind, $timeout, events, DOMHelper) {
13856 templateUrl: 'app/scripts/ng_js_att_tpls/popOvers/popOvers.html',
13857 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
13858 link: function(scope, elem, attr, ctrl) {
13860 scope.closeable = false;
13862 scope.closeable = scope.$parent.parentAttrs['closeable'] === '' ? true : false;
13865 /* Before opening modal, find the focused element */
13866 var launchingElement = undefined,
13867 firstTabableElement = undefined;
13869 var outsideClick = function(evt) {
13870 scope.$apply(function() {
13871 scope.isOpen = false;
13874 var escKeydown = function(evt) {
13875 if (evt.which === 27 || evt.keyCode === 27) {
13876 console.log('ESC was pressed!');
13877 scope.$apply(function() {
13878 scope.isOpen = false;
13883 $timeout(function() {
13884 firstTabableElement = DOMHelper.firstTabableElement(elem);
13887 scope.$watch('isOpen', function(value) {
13888 if (scope.isOpen) {
13889 launchingElement = document.activeElement;
13890 /* Focus on first tabbable element */
13891 if (angular.isDefined(firstTabableElement)) {
13893 firstTabableElement.focus();
13897 if (angular.isDefined(launchingElement)) {
13899 launchingElement.focus();
13900 } catch (e) {} /* IE8 will throw exception */
13905 scope.$watch("stylett", function(value) {
13906 scope.popOverStyle = value;
13909 scope.$watch("placement", function(value) {
13910 scope.popOverPlacement = value;
13913 scope.closeMe = function(){
13914 scope.isOpen = false;
13917 elem.bind('click', function (e) {
13918 events.stopPropagation(e);
13921 $documentBind.event('click', 'isOpen', outsideClick, scope, true, 10);
13922 $documentBind.event('keydown', 'isOpen', escKeydown, scope, true, 10);
13927 angular.module('att.abs.profileCard', [])
13928 .constant('profileStatus',{
13930 ACTIVE:{status:"Active",color:"green"},
13931 DEACTIVATED:{status:"Deactivated",color:"red"},
13932 LOCKED:{status:"Locked",color:"red"},
13933 IDLE:{status:"Idle",color:"yellow"},
13934 PENDING:{status:"Pending",color:"blue"}
13936 role:"COMPANY ADMINISTRATOR"
13938 .directive('profileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
13942 templateUrl:function(element, attrs){
13943 if(!attrs.addUser){
13944 return 'app/scripts/ng_js_att_tpls/profileCard/profileCard.html';
13947 return 'app/scripts/ng_js_att_tpls/profileCard/addUser.html';
13953 link: function(scope, elem, attr){
13955 function isImage(src) {
13956 var deferred = $q.defer();
13957 var image = new Image();
13958 image.onerror = function() {
13959 deferred.reject(false);
13961 image.onload = function() {
13962 deferred.resolve(true);
13964 if(src!==undefined && src.length>0 ){
13967 deferred.reject(false);
13969 return deferred.promise;
13973 isImage(scope.profile.img).then(function(img) {
13976 var splitName=(scope.profile.name).split(' ');
13978 for(var i=0;i<splitName.length;i++){
13979 scope.initials += splitName[i][0];
13981 if(scope.profile.role.toUpperCase()===profileStatus.role){
13984 var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
13986 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
13987 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
13988 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
13989 scope.profile.lastLogin=scope.profile.state;
13992 var today=new Date().getTime();
13993 var lastlogin=new Date(scope.profile.lastLogin).getTime();
13994 var diff=(today-lastlogin)/(1000*60*60*24);
13996 scope.profile.lastLogin="Today";
13999 scope.profile.lastLogin="Yesterday";
14005 angular.module('att.abs.progressBars', [])
14007 .directive('attProgressBar', [function(){
14011 templateUrl : 'app/scripts/ng_js_att_tpls/progressBars/progressBars.html'
14014 angular.module('att.abs.radio', [])
14015 .constant('attRadioConfig', {
14016 activeClass : "att-radio--on",
14017 disabledClass : "att-radio--disabled"
14019 .directive('attRadio', ['$compile','attRadioConfig', function ($compile, attRadioConfig) {
14023 require: 'ngModel',
14024 link: function (scope, element, attr, ctrl) {
14027 var parentDiv = angular.element('<div att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-radio"></div>');
14028 element.attr("value",attr.attRadio);
14029 element.removeAttr("att-radio");
14030 element.removeAttr("title");
14031 element.attr("ng-model","radioVal");
14032 parentDiv.append(element.prop('outerHTML'));
14033 parentDiv.append('<div class="att-radio__indicator"></div>');
14034 parentDiv.attr("title", attr.title);
14036 var elm = parentDiv.prop('outerHTML');
14037 elm = $compile(elm)(scope);
14038 element = element.replaceWith(elm);
14039 var radioElm = elm.find("input");
14041 radioElm.on('focus', function() {
14042 elm.css("outline","2px solid #5E9ED6");
14043 // elm.css("outline","-mos-focus-ring-color auto 5px");
14044 elm.css("outline","-webkit-focus-ring-color auto 5px");
14047 radioElm.on('blur', function() {
14048 elm.css("outline","none");
14051 ngCtrl.$render = function () {
14052 scope.radioVal = ngCtrl.$modelValue;
14053 var selected = angular.equals(ngCtrl.$modelValue, attr.attRadio);
14054 elm.toggleClass(attRadioConfig.activeClass, selected);
14057 scope.updateModel = function () {
14058 radioElm[0].focus();
14059 var isActive = elm.hasClass(attRadioConfig.activeClass);
14061 if (!isActive && !scope.disabled) {
14062 ngCtrl.$setViewValue(isActive ? null : attr.attRadio);
14067 attr.$observe('disabled', function (val) {
14068 scope.disabled = (val || val === "disabled" || val === "true");
14069 if (scope.disabled){
14070 elm.addClass(attRadioConfig.disabledClass);
14071 elm.attr("tabindex", "-1");
14073 elm.removeClass(attRadioConfig.disabledClass);
14074 elm.attr("tabindex", "0");
14080 angular.module('att.abs.scrollbar', ['att.abs.position'])
14082 .constant('attScrollbarConstant', {
14084 // Vertical or horizontal scrollbar? ( x || y ).
14086 // Whether navigation pane is required of not.
14088 // Enable or disable the mousewheel.
14090 // How many pixels must the mouswheel scroll at a time.
14092 // Lock default scrolling window when there is no more content.
14094 //// Enable invert style scrolling
14095 scrollInvert: false,
14096 // Set the size of the scrollbar to auto or a fixed number.
14098 // Set the size of the thumb to auto or a fixed number.
14100 // Set to false to hide the scrollbar if not being used
14101 alwaysVisible: true
14105 .directive('attScrollbar', ['$window', '$timeout', '$parse', '$animate', 'attScrollbarConstant', '$position', function ($window, $timeout, $parse, $animate, attScrollbarConstant, $position) {
14110 templateUrl: 'app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html',
14111 controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
14113 axis: $attrs.attScrollbar || attScrollbarConstant.defaults.axis,
14114 navigation: $attrs.navigation || attScrollbarConstant.defaults.navigation,
14115 wheel: attScrollbarConstant.defaults.wheel,
14116 wheelSpeed: attScrollbarConstant.defaults.wheelSpeed,
14117 wheelLock: attScrollbarConstant.defaults.wheelLock,
14118 scrollInvert: attScrollbarConstant.defaults.scrollInvert,
14119 trackSize: attScrollbarConstant.defaults.trackSize,
14120 thumbSize: attScrollbarConstant.defaults.thumbSize,
14121 alwaysVisible: attScrollbarConstant.defaults.alwaysVisible
14123 var options = $attrs.scrollbar;
14125 options = $parse(options)($scope);
14129 this.options = angular.extend({}, defaults, options);
14130 this._defaults = defaults;
14133 $body = angular.element(document.querySelectorAll('body')[0]),
14134 $document = angular.element(document),
14135 $viewport = angular.element($element[0].querySelectorAll('.scroll-viewport')[0]),
14136 $overview = angular.element($element[0].querySelectorAll('.scroll-overview')[0]),
14137 $scrollbar = angular.element($element[0].querySelectorAll('.scroll-bar')[0]),
14138 $thumb = angular.element($element[0].querySelectorAll('.scroll-thumb')[0]),
14140 isHorizontal = this.options.axis === 'x',
14141 hasTouchEvents = false,
14142 // Modern browsers support "wheel"
14143 wheelEvent = ("onwheel" in document ? "wheel" :
14144 // Webkit and IE support at least "mousewheel"
14145 document.onmousewheel !== undefined ? "mousewheel" :
14146 // let's assume that remaining browsers are older Firefox
14148 sizeLabel = isHorizontal ? 'width' : 'height',
14149 sizeLabelCap = sizeLabel.charAt(0).toUpperCase() + sizeLabel.slice(1).toLowerCase(),
14150 posiLabel = isHorizontal ? 'left' : 'top',
14151 // moveEvent = document.createEvent('HTMLEvents'),
14152 restoreVisibilityAfterWheel,
14153 thumbscrolltouch = false,
14154 documnetscrolltouch = false;
14155 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
14156 hasTouchEvents = true;
14159 //moveEvent.initEvent('move', true, true);
14160 this.contentPosition = 0;
14161 this.viewportSize = 0;
14162 this.contentSize = 0;
14163 this.contentRatio = 0;
14164 this.trackSize = 0;
14165 this.trackRatio = 0;
14166 this.thumbSize = 0;
14167 this.thumbPosition = 0;
14169 this.initialize = function () {
14170 if (!this.options.alwaysVisible) {
14171 $scrollbar.css('opacity', 0);
14178 this.setSizeData = function () {
14179 this.viewportSize = $viewport.prop('offset' + sizeLabelCap) || 1;
14180 this.contentSize = $overview.prop('scroll' + sizeLabelCap) || 1;
14181 this.contentRatio = this.viewportSize / this.contentSize;
14182 this.trackSize = this.options.trackSize || this.viewportSize;
14183 this.thumbSize = Math.min(this.trackSize, Math.max(0, (this.options.thumbSize || (this.trackSize * this.contentRatio))));
14184 this.trackRatio = this.options.thumbSize ? (this.contentSize - this.viewportSize) / (this.trackSize - this.thumbSize) : (this.contentSize / this.trackSize);
14187 this.update = function (scrollTo) {
14188 self.setSizeData();
14189 mousePosition = $scrollbar.prop('offsetTop');
14191 $scrollbar.toggleClass('disable', this.contentRatio >= 1 || isNaN(this.contentRatio));
14193 if (!this.options.alwaysVisible && this.contentRatio < 1 && this.viewportSize > 0) {
14194 //flash the scrollbar when update happens
14195 $animate.addClass($scrollbar, 'visible').then(function () {
14196 $animate.removeClass($scrollbar, 'visible');
14201 if (scrollTo !== null) {
14202 if (scrollTo === 'bottom') {
14203 this.contentPosition = this.contentSize - this.viewportSize;
14205 this.contentPosition = parseInt(scrollTo, 10) || 0;
14209 ensureContentPosition();
14210 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14211 $scrollbar.css(sizeLabel, self.trackSize + 'px');
14212 $thumb.css(sizeLabel, self.thumbSize + 'px');
14213 $overview.css(posiLabel, -self.contentPosition + 'px');
14218 fireEvent = function (obj, evt) {
14219 var fireOnThis = obj;
14221 if (document.createEvent) {
14223 evtObj = document.createEvent('HTMLEvents');
14224 evtObj.initEvent(evt, true, false);
14225 fireOnThis.dispatchEvent(evtObj);
14226 } else if (document.createEventObject) {
14228 evtObj = document.createEventObject();
14229 fireOnThis.fireEvent('on' + evt, evtObj);
14233 function ensureContentPosition() {
14234 // if scrollbar is on, ensure the bottom of the content does not go above the bottom of the viewport
14235 if (self.contentRatio <= 1 && self.contentPosition > self.contentSize - self.viewportSize) {
14236 self.contentPosition = self.contentSize - self.viewportSize;
14238 // if scrollbar is off, ensure the top of the content does not go below the top of the viewport
14239 else if (self.contentRatio > 1 && self.contentPosition > 0) {
14240 self.contentPosition = 0;
14243 if (self.contentPosition <= 0) {
14244 $scope.prevAvailable = false;
14246 $scope.prevAvailable = true;
14249 if (self.contentPosition >= (self.contentSize - self.viewportSize)) {
14250 $scope.nextAvailable = false;
14252 $scope.nextAvailable = true;
14256 function setEvents() {
14257 if (hasTouchEvents) {
14258 $viewport.on('touchstart', touchstart);
14259 $thumb.on('touchstart', touchstart);
14261 $thumb.on('mousedown', start);
14262 $scrollbar.on('mousedown', drag);
14265 angular.element($window).on('resize', resize);
14267 if (self.options.wheel) {
14268 $element.on(wheelEvent, wheel);
14272 function resize() {
14276 function touchstart(event) {
14277 if (1 === event.touches.length) {
14278 event.stopPropagation();
14279 start(event.touches[0]);
14283 function start(event) {
14284 $body.addClass('scroll-no-select');
14285 $element.addClass('scroll-no-select');
14287 if (!self.options.alwaysVisible) {
14288 $scrollbar.addClass('visible');
14290 mousePosition = isHorizontal ? event.clientX : event.clientY;
14291 self.thumbPosition = parseInt($thumb.css(posiLabel), 10) || 0;
14293 if (hasTouchEvents) {
14294 documnetscrolltouch = false;
14295 thumbscrolltouch = false;
14296 $viewport.on('touchmove', touchdrag);
14297 $viewport.on('touchend', end);
14298 $thumb.on('touchmove', touchdragthumb);
14299 $thumb.on('touchend', end);
14301 $document.on('mousemove', drag);
14302 $document.on('mouseup', end);
14303 $thumb.on('mouseup', end);
14307 function wheel(event) {
14308 if (self.contentRatio >= 1) {
14312 if (!self.options.alwaysVisible) {
14313 //cancel removing visibility if wheel event is triggered before the timeout
14314 if (restoreVisibilityAfterWheel) {
14315 $timeout.cancel(restoreVisibilityAfterWheel);
14317 $scrollbar.addClass('visible');
14319 restoreVisibilityAfterWheel = $timeout(function () {
14320 $scrollbar.removeClass('visible');
14324 var evntObj = (event && event.originalEvent) || event || $window.event,
14325 deltaDir = self.options.axis.toUpperCase(),
14327 X: evntObj.deltaX || 0,
14328 Y: evntObj.deltaY || 0
14330 wheelSpeed = evntObj.deltaMode === 0 ? self.options.wheelSpeed : 1;
14332 if (self.options.scrollInvert) {
14336 if (wheelEvent === 'mousewheel') {
14337 delta.Y = -1 * evntObj.wheelDelta / 40;
14338 if (evntObj.wheelDeltaX) {
14339 delta.X = -1 * evntObj.wheelDeltaX / 40;
14342 delta.X *= -1 / wheelSpeed;
14343 delta.Y *= -1 / wheelSpeed;
14345 var wheelSpeedDelta = delta[deltaDir];
14347 self.contentPosition -= wheelSpeedDelta * self.options.wheelSpeed;
14348 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
14350 fireEvent($element[0], 'move');
14352 ensureContentPosition();
14353 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14354 $overview.css(posiLabel, -self.contentPosition + 'px');
14356 if (self.options.wheelLock || (self.contentPosition !== (self.contentSize - self.viewportSize) && self.contentPosition !== 0)) {
14357 evntObj.preventDefault();
14363 function touchdrag(event) {
14364 event.preventDefault();
14365 documnetscrolltouch = true;
14366 drag(event.touches[0]);
14369 function touchdragthumb(event) {
14370 event.preventDefault();
14371 thumbscrolltouch = true;
14372 drag(event.touches[0]);
14375 function drag(event) {
14376 if (self.contentRatio >= 1) {
14380 var mousePositionNew = isHorizontal ? event.clientX : event.clientY,
14381 thumbPositionDelta = mousePositionNew - mousePosition;
14383 if ((self.options.scrollInvert && !hasTouchEvents) ||
14384 (hasTouchEvents && !self.options.scrollInvert)) {
14385 thumbPositionDelta = mousePosition - mousePositionNew;
14387 if (documnetscrolltouch && hasTouchEvents) {
14388 thumbPositionDelta = mousePosition - mousePositionNew;
14390 if (thumbscrolltouch && hasTouchEvents) {
14391 thumbPositionDelta = mousePositionNew - mousePosition;
14393 var thumbPositionNew = Math.min((self.trackSize - self.thumbSize), Math.max(0, self.thumbPosition + thumbPositionDelta));
14394 self.contentPosition = thumbPositionNew * self.trackRatio;
14396 fireEvent($element[0], 'move');
14398 ensureContentPosition();
14399 $thumb.css(posiLabel, thumbPositionNew + 'px');
14400 $overview.css(posiLabel, -self.contentPosition + 'px');
14405 $scope.customScroll = function (direction) {
14406 if (self.contentRatio >= 1) {
14410 var customScrollDelta;
14411 var viewportDimension = $position.position($viewport);
14413 if (isHorizontal) {
14414 customScrollDelta = viewportDimension.width;
14416 customScrollDelta = viewportDimension.height;
14420 self.contentPosition += customScrollDelta;
14422 self.contentPosition -= customScrollDelta;
14424 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
14426 fireEvent($element[0], 'move');
14428 ensureContentPosition();
14429 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14430 $overview.css(posiLabel, -self.contentPosition + 'px');
14434 $body.removeClass('scroll-no-select');
14435 $element.removeClass('scroll-no-select');
14436 if (!self.options.alwaysVisible) {
14437 $scrollbar.removeClass('visible');
14439 $document.off('mousemove', drag);
14440 $document.off('mouseup', end);
14441 $thumb.off('mouseup', end);
14442 $document.off('touchmove', touchdrag);
14443 $document.off('ontouchend', end);
14444 $thumb.off('touchmove', touchdragthumb);
14445 $thumb.off('touchend', end);
14448 this.cleanup = function () {
14449 $viewport.off('touchstart', touchstart);
14450 $thumb.off('mousedown', start);
14451 $scrollbar.off('mousedown', drag);
14452 $thumb.off('touchmove', touchdragthumb);
14453 $thumb.off('touchend', end);
14454 angular.element($window).off('resize', resize);
14455 $element.off(wheelEvent, wheel);
14456 //ensure scrollbar isn't activated
14457 self.options.alwaysVisible = true;
14461 link: function (scope, iElement, iAttrs, controller) {
14462 scope.navigation = controller.options.navigation;
14463 scope.viewportHeight = iAttrs.viewportHeight;
14464 scope.viewportWidth = iAttrs.viewportWidth;
14465 scope.scrollbarAxis = controller.options.axis;
14466 if (scope.scrollbarAxis === 'x') {
14467 iElement.addClass('horizontal');
14468 } else if (scope.scrollbarAxis === 'y') {
14469 iElement.addClass('vertical');
14472 var position = iElement.css('position');
14473 if (position !== 'relative' && position !== 'absolute') {
14474 iElement.css('position', 'relative');
14477 scope.$watch(function () {
14478 $timeout(refreshScrollbar, 100, false);
14481 var refreshScrollbar = function () {
14482 var $overview = angular.element(iElement[0].querySelectorAll('.scroll-overview')[0]);
14483 var newValue = $overview.prop('scrollHeight');
14484 var oldValue = scope.oldValue;
14485 if (newValue !== oldValue) {
14486 scope.oldValue = newValue;
14487 controller.update();
14491 controller.initialize();
14492 iElement.on('$destroy', function () {
14493 controller.cleanup();
14499 angular.module('att.abs.search', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
14500 .directive('attSearch', ['$document', '$filter', '$isElement', '$documentBind', '$timeout', '$log', 'keymap', function($document, $filter, $isElement, $documentBind, $timeout, $log, keymap){
14503 scope:{cName: '=attSearch'},
14507 templateUrl: 'app/scripts/ng_js_att_tpls/search/search.html',
14508 link: function(scope, element, attr, ctrl) {
14509 scope.selectedIndex = -1;
14510 scope.selectedOption = attr.placeholder;
14511 scope.isDisabled = false;
14512 scope.className = "select2-match";
14513 scope.showSearch = false;
14514 scope.showlist = false;
14516 // This is used to jump to elements in list
14518 // This is used to ensure searches only persist so many ms.
14519 var prevSearchDate = new Date();
14520 // This is used to shift focus back after closing dropdown
14521 var dropdownElement = undefined;
14522 // Used to ensure focus on dropdown elements
14524 $timeout(function() {
14525 list = element.find('li');
14528 $log.warn('attSearch is deprecated, please use attSelect instead. This component will be removed by version 2.7.')
14529 //scope.noFilter = true;
14530 if (attr.noFilter || attr.noFilter === 'true') {
14531 scope.noFilter = true;
14533 scope.noFilter = false;
14535 if (attr.placeholderAsOption === 'false') {
14536 //scope.selectMsg = '';
14537 scope.selectedOption = attr.placeholder;
14539 scope.selectMsg = attr.placeholder;
14541 if (attr.startsWithFilter || attr.startsWithFilter === 'true') {
14542 scope.startsWithFilter = true;
14544 if (attr.showInputFilter === 'true') {
14545 scope.showSearch = false;
14546 $log.warn('showInputFilter functionality has been removed from the library.');
14547 // This is deprecated
14549 if (attr.disabled) {
14550 scope.isDisabled = true;
14552 dropdownElement = angular.element(element).children().eq(0).find('a')[0];
14554 var selectOptionFromSearch = function() {
14555 if (!scope.noFilter) {
14559 // Find next element that matches search criteria.
14560 // If no element is found, loop to beginning and search.
14561 var criteria = search;
14563 for (i = prevIndex; i < scope.cName.length; i++) {
14564 // Need to ensure we keep searching until all startsWith have passed before looping
14565 if (scope.cName[i].title.startsWith(criteria) && i !== scope.selectedIndex) {
14566 scope.selectOption(scope.cName[i], i, scope.showlist);
14572 if ((i >= scope.cName.length || !scope.cName[i+1].title.startsWith(criteria)) && prevIndex > 0) {
14576 scope.showDropdown = function() {
14577 if (!(attr.disabled)) {
14578 scope.showlist = !scope.showlist;
14579 scope.setSelectTop();
14582 element.bind('keydown', function(e) {
14583 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
14584 e.preventDefault();
14585 e.stopPropagation();
14587 switch (e.keyCode) {
14588 case keymap.KEY.DOWN:
14589 scope.selectNext();
14591 case keymap.KEY.UP:
14592 scope.selectPrev();
14595 case keymap.KEY.ENTER:
14596 scope.selectCurrent();
14599 case keymap.KEY.BACKSPACE:
14604 case keymap.KEY.SPACE:
14605 if (!scope.noFilter) {
14606 scope.title += ' ';
14610 case keymap.KEY.ESC:
14611 if (scope.title === '' || scope.title === undefined) {
14612 scope.showlist = false;
14613 dropdownElement.focus();
14619 if (scope.noFilter) {
14621 dropdownElement.focus();
14622 scope.showlist = false;
14629 if (e.keyCode !== 9)
14631 if (!scope.noFilter) {
14632 scope.showlist = true;
14633 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14635 var date = new Date();
14636 var delta = Math.abs(prevSearchDate.getMilliseconds() - date.getMilliseconds());
14637 prevSearchDate = date;
14641 search = search ? search + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14642 if (search.length > 2) {
14643 search = search.substring(0, 2);
14645 selectOptionFromSearch();
14648 } else if (e.keyCode === 9) {
14649 scope.showlist = false;
14655 scope.selectOption = function(sTitle, sIndex, keepOpen) {
14656 if (sIndex === -1 || sIndex === '-1') {
14657 scope.selCategory = '';
14658 scope.selectedIndex = -1;
14659 ctrl.$setViewValue('');
14660 if(attr.placeholderAsOption !== 'false')
14662 scope.selectedOption = scope.selectMsg;
14665 scope.selCategory = scope.cName[sIndex];
14666 scope.selectedIndex = sIndex;
14667 ctrl.$setViewValue(scope.selCategory);
14668 scope.selectedOption = scope.selCategory.title;
14669 if (angular.isDefined(list[sIndex])) {
14670 list[sIndex].focus();
14675 scope.showlist = false;
14676 dropdownElement.focus();
14680 scope.selectCurrent = function() {
14681 if (scope.showlist) {
14682 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14685 scope.showlist = true;
14686 scope.setSelectTop();
14690 scope.hoverIn = function(cItem) {
14691 scope.selectedIndex = cItem;
14694 scope.setSelectTop = function() {
14695 $timeout(function() {
14696 if (scope.showlist && !scope.noFilter)
14698 var containerUL = angular.element(element)[0].querySelector(".select2-results");
14699 if(angular.element(containerUL.querySelector('.select2-result-current'))[0])
14701 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
14703 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
14707 scope.setCurrentTop = function() {
14708 $timeout(function() {
14709 if (scope.showlist) {
14710 var containerUL = angular.element(element)[0].querySelector(".select2-results");
14711 if(angular.element(containerUL.querySelector('.hovstyle'))[0])
14713 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
14715 if (selectedElemTopPos < (angular.element(containerUL)[0].scrollTop)) {
14716 angular.element(containerUL)[0].scrollTop -= 30;
14717 } else if ((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight)) {
14718 angular.element(containerUL)[0].scrollTop += 30;
14724 scope.selectNext = function() {
14725 if ((scope.selectedIndex + 1) <= (scope.cName.length - 1)) {
14726 scope.selectedIndex += 1;
14727 if (!scope.showlist) {
14728 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14733 scope.setCurrentTop();
14735 scope.selectPrev = function() {
14736 if ((scope.selectedIndex - 1) >= 0) {
14737 scope.selectedIndex -= 1;
14738 if (!scope.showlist) {
14739 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14743 } else if (scope.selectedIndex - 1 < 0) {
14744 // If placeholderAsOption is true or undefined (default), ensure we can select it on up key.
14745 if (attr.placeholderAsOption === undefined || attr.placeholderAsOption === 'true') {
14746 scope.selectedIndex = -1;
14748 scope.selectedIndex = 0;
14750 if (!scope.showlist) {
14751 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14756 scope.setCurrentTop();
14758 scope.updateSelection = function(sItem) {
14759 scope.selectedOption = sItem.title;
14762 scope.focusme = function() {
14763 $timeout(function() {
14764 var list = angular.element(element).find('ul').find('li');
14765 var index = scope.selectedIndex + 2;
14766 if (scope.noFilter) {
14767 index = scope.selectedIndex;
14769 if (angular.isDefined(list[index])) {
14770 list[index].focus();
14774 scope.$watch('selCategory', function(value) {
14776 scope.updateSelection(value);
14779 ctrl.$viewChangeListeners.push(function() {
14780 scope.$eval(attr.ngChange);
14782 ctrl.$render = function() {
14783 scope.selCategory = ctrl.$viewValue;
14785 var outsideClick = function(e) {
14786 var isElement = $isElement(angular.element(e.target), element, $document);
14788 scope.showlist = false;
14789 dropdownElement.focus();
14793 $documentBind.click('showlist', outsideClick, scope);
14797 angular.module('att.abs.select', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
14798 .directive('attSelect', ["$document", "$filter", "$isElement", '$documentBind', '$timeout', 'keymap', '$log', function($document, $filter, $isElement, $documentBind, $timeout, keymap, $log) {
14802 cName: '=attSelect'
14806 require: 'ngModel',
14807 templateUrl: 'app/scripts/ng_js_att_tpls/select/select.html',
14808 link: function(scope, element, attr, ctrl) {
14809 scope.selectedIndex = -1;
14810 scope.selectedOption = attr.placeholder;
14811 scope.isDisabled = false;
14812 scope.className = "select2-match";
14813 scope.showSearch = false;
14814 scope.showlist = false;
14815 scope.titleName = attr.titlename;
14816 scope.$watch('ngModel', function() {
14817 // console.log('sv:', ctrl.$modelValue);
14820 // This is used to jump to elements in list
14822 // This is used to ensure searches only persist so many ms.
14823 var prevSearchDate = new Date();
14824 // This is used to shift focus back after closing dropdown
14825 var dropdownElement = undefined;
14826 // Used to ensure focus on dropdown elements
14828 $timeout(function() {
14829 list = element.find('li');
14831 //scope.noFilter = true;
14832 if (attr.noFilter || attr.noFilter === 'true') {
14833 scope.noFilter = true;
14835 scope.noFilter = false;
14837 if (attr.placeholderAsOption === 'false') {
14838 scope.selectedOption = attr.placeholder;
14840 scope.selectMsg = attr.placeholder;
14842 if (attr.startsWithFilter || attr.startsWithFilter === 'true') {
14843 scope.startsWithFilter = true;
14845 if (attr.showInputFilter === 'true') {
14846 scope.showSearch = false;
14847 /* This is deprecated */
14848 $log.warn('showInputFilter functionality has been removed from the library.');
14850 if (attr.disabled) {
14851 scope.isDisabled = true;
14853 var getFilterType = function() {
14854 if (scope.startsWithFilter) {
14855 return 'startsWith';
14860 dropdownElement = angular.element(element).children().eq(0).find('span')[0];
14862 var selectOptionFromSearch = function() {
14863 if (!scope.noFilter) {
14867 // Find next element that matches search criteria.
14868 // If no element is found, loop to beginning and search.
14869 var criteria = search;
14871 for (i = prevIndex; i < scope.cName.length; i++) {
14872 // Need to ensure we keep searching until all startsWith have passed before looping
14873 if (scope.cName[i].title.startsWith(criteria) && i !== scope.selectedIndex) {
14874 scope.selectOption(scope.cName[i], i, scope.showlist);
14880 if ((i >= scope.cName.length || !scope.cName[i+1].title.startsWith(criteria)) && prevIndex > 0) {
14884 scope.showDropdown = function() {
14885 if (!(attr.disabled)) {
14886 scope.showlist = !scope.showlist;
14887 scope.setSelectTop();
14888 /* Ensure selected element is focused upon opening dropdown */
14892 element.bind('keydown', function(e) {
14893 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
14894 e.preventDefault();
14895 e.stopPropagation();
14897 switch (e.keyCode) {
14898 case keymap.KEY.DOWN:
14899 scope.selectNext();
14901 case keymap.KEY.UP:
14902 scope.selectPrev();
14905 case keymap.KEY.ENTER:
14906 scope.selectCurrent();
14909 case keymap.KEY.BACKSPACE:
14914 case keymap.KEY.SPACE:
14915 if (!scope.noFilter) {
14916 scope.title += ' ';
14920 case keymap.KEY.ESC:
14921 if (scope.title === '' || scope.title === undefined) {
14922 scope.showlist = false;
14923 dropdownElement.focus();
14929 if (scope.noFilter) {
14931 dropdownElement.focus();
14932 scope.showlist = false;
14939 if (e.keyCode !== keymap.KEY.TAB)
14941 if (!scope.noFilter) {
14942 scope.showlist = true;
14943 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14945 /* Perform index correction */
14946 if (scope.title != '') {
14947 var filteredArray = $filter(getFilterType())(scope.cName, scope.title);
14949 for (var i = 0; i < filteredArray.length; i++) {
14950 for (var j = 0; j < scope.cName.length; j++) {
14951 if (!angular.isDefined(scope.cName[scope.selectedIndex])) {
14954 if (filteredArray[i]['title'] === scope.cName[scope.selectedIndex]['title']) {
14955 scope.selectedIndex = i;
14963 var date = new Date();
14964 var delta = Math.abs(prevSearchDate.getMilliseconds() - date.getMilliseconds());
14965 prevSearchDate = date;
14969 search = search ? search + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14970 if (search.length > 2) {
14971 search = search.substring(0, 2);
14973 selectOptionFromSearch();
14976 } else if (e.keyCode === keymap.KEY.TAB) {
14977 scope.showlist = false;
14983 scope.selectOption = function(sTitle, sIndex, keepOpen) {
14985 if (sIndex === -1 || sIndex === '-1') {
14986 scope.selCategory = '';
14987 scope.selectedIndex = -1;
14988 ctrl.$setViewValue('');
14989 if(attr.placeholderAsOption !== 'false')
14991 scope.selectedOption = scope.selectMsg;
14995 /* Apply filter here to remap the selected index and shift focus*/
14996 if (scope.title != '') {
14997 var filteredArray = $filter(getFilterType())(scope.cName, scope.title);
14999 if (angular.isDefined(filteredArray) && angular.isDefined(filteredArray[sIndex]))
15001 for (var i = 0; i < scope.cName.length; i++) {
15002 if (filteredArray[sIndex]['title'] === scope.cName[i]['title']) {
15009 scope.selCategory = scope.cName[sIndex];
15010 scope.selectedIndex = sIndex;
15011 ctrl.$setViewValue(scope.selCategory);
15012 scope.selectedOption = scope.selCategory.title;
15015 $timeout(function(){
15016 if (angular.isDefined(list[sIndex])) {
15018 list[index].focus();
15019 } catch (e) {} /* IE8 will throw exception if display:none or not in DOM */
15025 scope.showlist = false;
15026 dropdownElement.focus();
15029 scope.selectCurrent = function() {
15030 if (scope.showlist) {
15031 scope.selectOption(scope.selectMsg,scope.selectedIndex,false);
15033 scope.showlist = true;
15034 scope.setSelectTop();
15038 scope.hoverIn = function(cItem) {
15039 scope.selectedIndex = cItem;
15042 scope.setSelectTop = function() {
15043 $timeout(function() {
15044 if (scope.showlist && !scope.noFilter)
15046 var containerUL = angular.element(element)[0].querySelector(".select2-results");
15047 if(angular.element(containerUL.querySelector('.select2-result-current'))[0])
15049 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
15051 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
15055 scope.setCurrentTop = function() {
15056 $timeout(function() {
15057 if (scope.showlist) {
15058 var containerUL = angular.element(element)[0].querySelector(".select2-results");
15059 if(angular.element(containerUL.querySelector('.hovstyle'))[0])
15061 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
15063 if (selectedElemTopPos < (angular.element(containerUL)[0].scrollTop)) {
15064 angular.element(containerUL)[0].scrollTop -= 30;
15065 } else if ((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight)) {
15066 angular.element(containerUL)[0].scrollTop += 30;
15072 scope.selectNext = function() {
15073 var length = scope.cName.length;
15075 if ((scope.selectedIndex + 1) <= (scope.cName.length - 1)) {
15076 scope.selectedIndex += 1;
15077 var nextDisabled = scope.cName[scope.selectedIndex].disabled;
15078 if (nextDisabled) {
15079 scope.selectedIndex += 1;
15081 if (!scope.showlist) {
15082 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15087 scope.setCurrentTop();
15089 scope.selectPrev = function() {
15090 if ((scope.selectedIndex - 1) >= 0) {
15091 scope.selectedIndex -= 1;
15092 var prevDisabled = scope.cName[scope.selectedIndex].disabled;
15093 if (prevDisabled) {
15094 scope.selectedIndex -= 1;
15096 if (!scope.showlist) {
15097 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15101 } else if (scope.selectedIndex - 1 < 0) {
15102 // If placeholderAsOption is true or undefined (default), ensure we can select it on up key.
15103 if (attr.placeholderAsOption === undefined || attr.placeholderAsOption === 'true') {
15104 if(attr.placeholder === undefined ){
15105 scope.selectedIndex = 0;
15108 scope.selectedIndex = -1;
15111 scope.selectedIndex = 0;
15113 if (!scope.showlist) {
15114 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15119 scope.setCurrentTop();
15121 scope.updateSelection = function(sItem) {
15122 scope.selectedOption = sItem.title;
15125 if (sItem.index < 0) {
15126 scope.selectOption(scope.selectMsg, sItem.index, scope.showlist);
15129 scope.focusme = function() {
15130 $timeout(function() {
15131 var list = angular.element(element).find('ul').find('li');
15132 var index = scope.selectedIndex + 2;
15133 if (scope.noFilter) {
15134 index = scope.selectedIndex;
15136 if (angular.isDefined(list[index])) {
15138 list[index].focus();
15139 } catch (e) {} /* IE8 will throw exception if display:none or not in DOM */
15143 scope.$watch('selCategory', function(value) {
15145 scope.updateSelection(value);
15148 ctrl.$viewChangeListeners.push(function() {
15149 scope.$eval(attr.ngChange);
15151 ctrl.$render = function() {
15152 scope.selCategory = ctrl.$viewValue;
15154 var outsideClick = function(e) {
15155 var isElement = $isElement(angular.element(e.target), element, $document);
15157 scope.showlist = false;
15158 dropdownElement.focus();
15162 $documentBind.click('showlist', outsideClick, scope);
15166 .directive('textDropdown', ['$document', '$isElement', '$documentBind', "keymap", function($document, $isElement, $documentBind, keymap) {
15171 actions: '=actions',
15172 defaultAction: '=defaultAction',
15173 onActionClicked: '=?'
15175 templateUrl: 'app/scripts/ng_js_att_tpls/select/textDropdown.html',
15176 link: function(scope, element, attr) {
15177 scope.selectedIndex = 0;
15178 scope.selectedOption = attr.placeholder;
15179 scope.isDisabled = false;
15180 scope.isActionsShown = false;
15181 var dropdownElement = undefined;
15182 if (attr.disabled) {
15183 scope.isDisabled = true;
15186 dropdownElement = element.find('div')[0];
15188 // Set default Action
15189 if (!angular.isDefined(scope.defaultAction)) {
15190 scope.currentAction = scope.actions[0];
15191 scope.selectedIndex = 0;
15192 } else if (angular.isDefined(scope.defaultAction) || scope.defaultAction !== '') {
15193 for (var act in scope.actions) {
15194 if (scope.actions[act] === scope.defaultAction) {
15195 scope.currentAction = scope.actions[act];
15196 scope.selectedIndex = scope.actions.indexOf(act);
15197 scope.isActionsShown = false;
15202 scope.currentAction = scope.actions[0];
15204 scope.toggle = function() {
15205 scope.isActionsShown = !scope.isActionsShown;
15207 scope.chooseAction = function($event, action, $index) {
15208 if ($event != null) {
15209 scope.currentAction = action;
15210 scope.selectedIndex = $index;
15212 scope.currentAction = scope.actions[scope.selectedIndex];
15214 if (angular.isFunction(scope.onActionClicked)) {
15215 scope.onActionClicked(scope.currentAction);
15219 scope.isCurrentAction = function(action) {
15220 return (action === scope.currentAction);
15222 element.bind("keydown", function(e) {
15223 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
15224 e.preventDefault();
15225 e.stopPropagation();
15226 switch (e.keyCode) {
15227 case keymap.KEY.DOWN:
15228 scope.selectNext();
15230 case keymap.KEY.UP:
15231 scope.selectPrev();
15233 case keymap.KEY.ENTER:
15234 scope.selectCurrent();
15236 case keymap.KEY.ESC:
15237 scope.isActionsShown = false;
15238 dropdownElement.focus();
15246 } else if (e.keyCode === keymap.KEY.TAB) {
15247 scope.isActionsShown = false;
15251 scope.selectCurrent = function() {
15252 if (scope.selectedIndex < 0) {
15253 scope.selectedIndex = 0;
15255 if (!scope.isActionsShown) {
15258 scope.chooseAction(null, scope.currentAction);
15261 scope.selectNext = function() {
15262 if (scope.isActionsShown) {
15263 if ((scope.selectedIndex + 1) < scope.actions.length) {
15264 scope.selectedIndex += 1;
15266 scope.selectedIndex = (scope.actions.length - 1);
15271 scope.selectPrev = function() {
15272 if (scope.isActionsShown) {
15273 if ((scope.selectedIndex - 1) >= 0) {
15274 scope.selectedIndex -= 1;
15275 } else if (scope.selectedIndex - 1 < 0) {
15276 scope.selectedIndex = 0;
15281 scope.hoverIn = function(cItem) {
15282 scope.selectedIndex = cItem;
15285 var outsideClick = function(e) {
15286 var isElement = $isElement(angular.element(e.target), element, $document);
15292 $documentBind.click('isActionsShown', outsideClick, scope);
15296 angular.module('att.abs.slider', ['att.abs.position'])
15297 .constant('sliderDefaultOptions', {
15303 .directive('attSlider', ['sliderDefaultOptions','$position','$document', function(sliderDefaultOptions,$position,$document)
15317 ngModelSingle: '=?',
15320 ngModelDisabled: '=?'
15322 templateUrl: 'app/scripts/ng_js_att_tpls/slider/slider.html',
15323 link: function(scope, elem, attr)
15325 var minOffset, maxOffset, newOffset, newOffset1, newOffset2, offsetRange, valueRange, start_x = 0, disabledRange, disabled, evFlag = false, minValue, maxValue, range, refLow, refHigh, maxPtr, minPtr, singlePtr, getHandles;
15326 scope.minPtrOffset = 0;
15327 scope.maxPtrOffset = 0;
15328 var disableWidth = sliderDefaultOptions.disabledWidth;
15330 var obj = elem.children();
15331 disabledRange = obj[0].children;
15332 disabledRange = angular.element(disabledRange[0]);
15333 getHandles = obj[1].children;
15334 singlePtr = angular.element(getHandles[0]);
15335 minPtr = angular.element(getHandles[1]);
15336 maxPtr = angular.element(getHandles[2]);
15337 disabled = ((attr.ngModelSingle == null) && (attr.ngModelLow == null) && (attr.ngModelHigh == null)) && (attr.ngModelDisabled != null);
15338 range = (attr.ngModelSingle == null) && ((attr.ngModelLow != null) && (attr.ngModelHigh != null));
15339 refLow = 'ngModelLow';
15340 refHigh = 'ngModelHigh';
15346 singlePtr.remove();
15349 disabledRange.remove();
15352 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
15353 scope.handleStyle = {left: disableWidth + 'px'};
15355 minValue = parseFloat(scope.floor);
15356 maxValue = parseFloat(scope.ceiling);
15357 valueRange = maxValue - minValue;
15359 if (attr.width !== undefined) {
15360 maxOffset = attr.width;
15363 if (elem[0].clientWidth !== 0) {
15364 maxOffset = elem[0].clientWidth;
15367 maxOffset = sliderDefaultOptions.width;
15370 offsetRange = maxOffset - minOffset;
15372 scope.keyDown = function(ev){
15373 if(ev.keyCode === 39){
15374 var elemLeft = $position.position(elem).left;
15376 if(scope.ref === "ngModelLow"){
15377 newOffset1 = sliderDefaultOptions.step + newOffset1;
15378 newOffset = newOffset1;
15380 else if(scope.ref === "ngModelHigh"){
15381 newOffset2 = sliderDefaultOptions.step + newOffset2;
15382 newOffset = newOffset2;
15384 else{newOffset = sliderDefaultOptions.step + newOffset;}
15387 if(range &&scope.ref === "ngModelLow"){
15391 newOffset = sliderDefaultOptions.step + elemLeft;
15392 newOffset1 = newOffset2 = newOffset;
15396 else if(ev.keyCode === 37){
15397 var ptrLeft = $position.position(singlePtr).left;
15399 if (!(newOffset<=0)){
15400 if(scope.ref === "ngModelLow"){
15401 newOffset1 = newOffset1 - sliderDefaultOptions.step;
15402 newOffset = newOffset1;
15404 else if(scope.ref === "ngModelHigh"){
15405 newOffset2 = newOffset2 - sliderDefaultOptions.step;
15406 newOffset = newOffset2;
15409 newOffset = newOffset - sliderDefaultOptions.step;
15410 newOffset1 = newOffset2 = newOffset;
15415 newOffset = ptrLeft - sliderDefaultOptions.step;
15419 scope.ptrOffset(newOffset);
15423 scope.mouseDown = function(e, ref) {
15429 start_x = e.clientX - newOffset;
15432 start_x = e.clientX;
15435 if (scope.ref === refLow) {
15436 start_x = e.clientX - scope.minPtrOffset;
15439 start_x = e.clientX - scope.maxPtrOffset;
15443 scope.ref= 'ngModelDisabled';
15444 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
15447 // Mouse Move Event
15448 scope.moveElem = function(ev) {
15451 eventX = ev.clientX;
15452 newOffset = eventX - start_x;
15453 scope.ptrOffset(newOffset);
15456 scope.focus=function(ev,ref){
15461 scope.mouseUp = function(ev) {
15463 minPtr.removeClass('dragging');
15464 maxPtr.removeClass('dragging');
15465 singlePtr.removeClass('dragging');
15466 $document.off('mousemove');
15469 scope.keyUp = function(ev) {
15471 minPtr.removeClass('dragging');
15472 maxPtr.removeClass('dragging');
15473 singlePtr.removeClass('dragging');
15474 $document.off('mousemove');
15476 //Function to calculate the current PositionValue
15477 scope.calStep = function(value, precision, step, floor) {
15478 var decimals, remainder, roundedValue, steppedValue;
15479 if (floor === null) {
15482 if (step === null) {
15483 step = 1 / Math.pow(10, precision);
15485 remainder = (value - floor) % step;
15486 steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
15487 decimals = Math.pow(10, precision);
15488 roundedValue = steppedValue * decimals / decimals;
15489 return roundedValue.toFixed(precision);
15491 //Function to calculate Offset Percent
15492 scope.percentOffset = function(offset) {
15493 return ((offset - minOffset) / offsetRange) * 100;
15495 //Function to calculate Offset position
15496 scope.ptrOffset = function(newOffset){
15497 var newPercent, newValue;
15498 newOffset = Math.max(Math.min(newOffset, maxOffset), minOffset);
15499 newPercent = scope.percentOffset(newOffset);
15500 newValue = minValue + (valueRange * newPercent / 100.0);
15502 var rangeSliderWidth;
15503 if (scope.ref === refLow) {
15504 scope.minHandleStyle = {left: newOffset + "px"};
15505 scope.minNewVal = newValue;
15506 scope.minPtrOffset = newOffset;
15507 minPtr.addClass('dragging');
15508 if (newValue > scope.maxNewVal) {
15509 scope.ref = refHigh;
15511 scope.maxNewVal = newValue;
15512 scope.maxPtrOffset = newOffset;
15513 maxPtr.addClass('dragging');
15514 minPtr.removeClass('dragging');
15515 scope.maxHandleStyle = {left: newOffset + "px"};
15519 scope.maxHandleStyle = {left: newOffset + "px"};
15520 scope.maxNewVal = newValue;
15521 scope.maxPtrOffset = newOffset;
15522 maxPtr.addClass('dragging');
15523 if (newValue < scope.minNewVal) {
15524 scope.ref = refLow;
15526 scope.minVal = newValue;
15527 scope.minPtrOffset = newOffset;
15528 minPtr.addClass('dragging');
15529 maxPtr.removeClass('dragging');
15530 scope.minHandleStyle = {left: newOffset + "px"};
15533 rangeSliderWidth = parseInt(scope.maxPtrOffset) - parseInt(scope.minPtrOffset);
15534 scope.rangeStyle = {width: rangeSliderWidth + "px", left: scope.minPtrOffset + "px"};
15537 if (disabled && newOffset > disableWidth) {
15538 scope.rangeStyle = {width: newOffset + "px", zIndex: 0};
15541 singlePtr.addClass('dragging');
15542 scope.rangeStyle = {width: newOffset + "px"};
15544 scope.handleStyle = {left: newOffset + "px"};
15546 if ((scope.precision === undefined) || (scope.step === undefined)) {
15547 scope.precision = sliderDefaultOptions.precision;
15548 scope.step = sliderDefaultOptions.step;
15550 newValue = scope.calStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
15551 scope[scope.ref] = newValue;
15556 ]).directive('attSliderMin',[function()
15559 require: '^attSlider',
15563 templateUrl: 'app/scripts/ng_js_att_tpls/slider/minContent.html'
15566 ]).directive('attSliderMax',[function()
15569 require: '^attSlider',
15573 templateUrl: 'app/scripts/ng_js_att_tpls/slider/maxContent.html'
15577 angular.module('att.abs.splitButtonDropdown', ['att.abs.utilities','att.abs.position'])
15578 .directive('attButtonDropdown', ['$document', '$parse', '$documentBind', '$timeout','$isElement', function ($document, $parse, $documentBind, $timeout,$isElement) {
15583 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html',
15591 controller: ['$scope', '$element', function ($scope, $element) {
15593 this.cSelected = 0;
15594 this.closeAndFocusDropdown = function () {
15595 if ($scope.isDropDownOpen) {
15596 $scope.$apply(function () {
15597 $scope.isDropDownOpen = false;
15598 angular.element($element[0].querySelector('a.dropdown-toggle'))[0].focus();
15603 this.focusNext = function () {
15604 this.cSelected = this.cSelected + 1 >= this.childScopes.length ?($scope.cycleSelection === true ? 0 : this.childScopes.length-1): this.cSelected +1;
15605 this.childScopes[this.cSelected].sFlag = true;
15606 this.resetFlag(this.cSelected);
15609 this.focusPrev = function () {
15610 this.cSelected = this.cSelected -1 < 0 ? ($scope.cycleSelection === true ? this.childScopes.length-1 : 0) : this.cSelected - 1 ;
15611 this.childScopes[this.cSelected].sFlag = true;
15612 this.resetFlag(this.cSelected);
15615 this.childScopes = [];
15616 this.registerScope = function(childScope)
15618 this.childScopes.push(childScope);
15621 this.resetFlag = function(index){
15622 for(var i=0; i < this.childScopes.length; i++)
15626 this.childScopes[i].sFlag = false;
15632 link: function (scope, element, attr) {
15633 scope.isSmall = attr.small === "" ? true : false;
15634 scope.multiselect = attr.multiselect === ""? true : false;
15635 scope.cycleSelection = attr.cycleSelection === "" ? true : false;
15636 scope.isDropDownOpen = false;
15637 scope.isActionDropdown = false;
15639 if (!(scope.btnText)) {
15640 scope.isActionDropdown = true;
15643 scope.clickFxn = function () {
15644 if (typeof scope.btnClick === "function" && !scope.btnLink) {
15645 scope.btnClick = $parse(scope.btnClick);
15648 if(scope.multiselect === true)
15650 scope.isDropDownOpen = false;
15654 scope.toggleDropdown = function () {
15655 if (!(scope.btnType === 'disabled')) {
15656 scope.isDropDownOpen = !scope.isDropDownOpen;
15657 if (scope.isDropDownOpen) {
15658 $timeout(function () {
15659 angular.element(element[0].querySelector('li'))[0].focus();
15665 scope.btnTypeSelector = function (directiveValue, attrValue) {
15666 if (directiveValue !== "") {
15667 scope.btnTypeFinal = directiveValue;
15669 scope.btnTypeFinal = attrValue;
15673 var outsideClick = function(e) {
15674 var isElement = $isElement(angular.element(e.target), element.find('ul').eq(0), $document);
15676 scope.isDropDownOpen = false;
15681 $documentBind.click('isDropDownOpen', outsideClick, scope);
15683 attr.$observe('btnType', function (val) {
15684 scope.btnType = val;
15686 attr.$observe('attButtonDropdown', function (val) {
15687 attr.attButtonDropdown = val;
15688 scope.btnTypeSelector(attr.attButtonDropdown, scope.btnType);
15695 .directive('attButtonDropdownItem', ['$location','keymap', function ($location,keymap) {
15698 require: ['^attButtonDropdown','?ngModel'],
15701 templateUrl:'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html', scope: {
15704 link: function (scope, element, attr, ctrl) {
15705 var rootLink = angular.element(element[0].querySelector('a'));
15706 scope.sFlag = false;
15707 ctrl[0].registerScope(scope);
15708 var clickOnLink = function () {
15709 if (scope.itemLinkFinal) {
15710 $location.url(scope.itemLinkFinal);
15715 scope.isSelected = ctrl[1].$viewValue;
15717 scope.isSelected = false;
15720 element.bind('keydown', function(e) {
15721 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
15722 e.preventDefault();
15723 e.stopPropagation();
15724 switch (e.keyCode) {
15725 case keymap.KEY.DOWN:
15726 ctrl[0].focusNext();
15728 case keymap.KEY.UP:
15729 ctrl[0].focusPrev();
15731 case keymap.KEY.ENTER:
15732 scope.selectItem();
15734 case keymap.KEY.ESC:
15735 ctrl[0].closeAndFocusDropdown();
15745 scope.selectItem = function()
15748 scope.$evalAsync(function(){ctrl[1].$setViewValue(!ctrl[1].$viewValue)});
15756 angular.module('att.abs.splitIconButton', ['att.abs.utilities'])
15757 .constant('iconStateConstants', {
15761 NEXT_TO_DROPDOWN:'next-to-dropdown',
15762 LEFT_NEXT_TO_DROPDOWN:'left-next-to-dropdown',
15768 SPLIT_ICON_BTN_EVENT_EMITTER_KEY: 'splitIconButtonTap'
15770 .directive('expandableLine', [function(){
15775 require: ['^attSplitIconButton', 'expandableLine'],
15776 controller: ['$scope', function($scope){
15777 $scope.isActive = false;
15778 this.setActiveState = function(isActive){
15779 $scope.isActive = isActive;
15781 this.isActive = $scope.isActive;
15782 this.dirType = $scope.dirType;
15784 template: '<div ng-class="{\'expand-line-container\': !isActive, \'expand-line-container-active\': isActive}"> <div ng-class="{\'hovered-line\':isActive, \'vertical-line\':!isActive}"> </div></div>',
15788 link: function(scope,element,attr,ctrls) {
15789 var attSplitIconButtonCtrl = ctrls[0];
15790 var expandableLineCtrl = ctrls[1];
15791 attSplitIconButtonCtrl.addSubCtrl(expandableLineCtrl);
15795 .controller('AttSplitIconCtrl', ['$scope', function($scope){
15796 this.setType = function(type){
15797 $scope.type = type;
15799 this.isDropdown = function(isDropdown){
15800 $scope.isDropdown = isDropdown;
15802 this.dropDownClicked = function(){
15803 if($scope.dropDownClicked) {
15804 $scope.dropDownClicked();
15807 this.dirType = $scope.dirType;
15809 .directive('attSplitIcon', ['$document', '$timeout','iconStateConstants','$documentBind','events', 'keymap',
15810 function($document,$timeout,iconStateConstants,$documentBind, events, keymap){
15816 require: ['^attSplitIconButton','attSplitIcon'],
15817 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html',
15820 iconTitle: '@title',
15822 dropDownWatch: '=',
15825 controller:'AttSplitIconCtrl',
15826 link: function(scope,element,attr,ctrls){
15827 var attSplitIconButtonCtrl = ctrls[0];
15828 var attSplitIconCtrl = ctrls[1];
15829 attSplitIconButtonCtrl.addSubCtrl(attSplitIconCtrl);
15830 scope.iconStateConstants = iconStateConstants;
15831 var currentIndex = 0;
15832 var isMyElement = false;
15834 scope.isDropdown = false;
15835 scope.isDropdownOpen = false;
15836 var outsideClick = function(e) {
15837 if(scope.isDropdown){
15839 isMyElement = false;
15840 scope.toggleDropdown();
15842 scope.toggleDropdown(false);
15847 if(attr.dropDownId && attr.dropDownId !== ''){
15848 scope.dropDownId = attr.dropDownId;
15849 scope.isDropdown = true;
15851 scope.$on(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, function(evnt, data){
15852 if(typeof data === 'boolean' && data) {
15853 scope.dropDownClicked();
15855 Check if the dropdown is open and if we are selecting one
15856 of the items, so that when pressing enter it will trigger it.
15858 if(scope.isDropDownOpen) {
15859 listElements[currentIndex].eq(0).find('a')[0].click();
15863 //Only trigger the keyboard event if the icon button is a dropdown type
15864 if(scope.isDropdown) {
15865 triggerKeyboardEvents(e);
15868 function triggerKeyboardEvents(e) {
15870 case (keymap.KEY.TAB):
15871 scope.toggleDropdown(false);
15874 case (keymap.KEY.ESC):
15877 case (keymap.KEY.ENTER):
15878 if (scope.isDropDownOpen) {
15879 listElementsInit();
15882 case (keymap.KEY.UP):
15883 e.preventDefault();
15884 events.stopPropagation(e);
15885 if(scope.isDropDownOpen) {
15886 scope.previousItemInDropdown();
15889 case (keymap.KEY.DOWN):
15890 e.preventDefault();
15891 events.stopPropagation(e);
15892 //Dropdown is open and the user taps down again
15893 if(scope.isDropDownOpen) {
15894 //Now we need to go through the rows in the dropdown
15895 scope.nextItemInDropdown();
15897 isMyElement = true;
15899 listElementsInit();
15906 function listElementsInit() {
15907 if(listElements === undefined) {
15909 var liTemps = element.find('li');
15910 for(var i = 0; i < liTemps.length; i++) {
15911 listElements.push(liTemps.eq(i));
15913 listElements[currentIndex].children().eq(0).addClass('selected-item');
15917 scope.nextItemInDropdown = function(){
15918 if(listElements && currentIndex < listElements.length - 1){
15920 listElements[currentIndex - 1].children().eq(0).removeClass('selected-item');
15921 listElements[currentIndex].children().eq(0).addClass('selected-item');
15924 scope.previousItemInDropdown = function(){
15925 if(currentIndex > 0) {
15927 listElements[currentIndex].children().eq(0).addClass('selected-item');
15929 if(currentIndex + 1 < listElements.length)
15930 listElements[currentIndex + 1].children().eq(0).removeClass('selected-item');
15933 scope.$watch('isIconHovered', function(val) {
15934 scope.hoverWatch = val;
15936 scope.$watch('type', function(val) {
15937 function toggleValues(isMiddle,isNextToDropDown,isRight,isLeft,isLeftNextDropdown){
15938 scope['isMiddle'] = isMiddle;
15939 scope['isNextToDropDown'] = isNextToDropDown;
15940 scope['isRight'] = isRight;
15941 scope['isLeft'] = isLeft;
15942 scope['isLeftNextDropdown'] = isLeftNextDropdown;
15945 case (scope.iconStateConstants.MIDDLE):
15946 toggleValues(true,false,false,true,false);
15948 case (scope.iconStateConstants.LEFT):
15949 toggleValues(false,false,false,true,false);
15951 case (scope.iconStateConstants.RIGHT):
15952 toggleValues(false,false,true,false,false);
15954 case (scope.iconStateConstants.NEXT_TO_DROPDOWN):
15955 toggleValues(false,true,true,true,false);
15957 case (scope.iconStateConstants.LEFT_NEXT_TO_DROPDOWN):
15958 toggleValues(false,false,false,true,true);
15964 scope.dropDownClicked = function() {
15965 isMyElement = true;
15967 scope.toggleDropdown = function(val) {
15968 if(val !== undefined) {
15969 scope.isDropDownOpen = val;
15971 scope.isDropDownOpen = !scope.isDropDownOpen;
15973 scope.dropDownWatch = scope.isDropDownOpen;
15975 $documentBind.click('isDropdown', outsideClick, scope);
15979 .controller('AttSplitIconButtonCtrl',['$scope', 'iconStateConstants',function($scope,iconStateConstants){
15980 this.subCtrls = [];
15981 $scope.isLeftLineShown=true;
15982 $scope.isRightLineShown=true;
15983 $scope.childrenScopes = [];
15986 function getDirIndex(dirType) {
15988 for(var c in that.subCtrls) {
15989 var ctrl = that.subCtrls[c];
15990 if(ctrl.dirType === dirType) {
15997 this.addSubCtrl = function(sub) {
15998 this.subCtrls.push(sub);
16000 this.isLeftLineShown = function(isShown) {
16001 if(isShown === undefined) {
16002 return $scope.isLeftLineShown;
16004 $scope.isLeftLineShown = isShown;
16007 this.isRightLineShown = function(isShown) {
16008 if(isShown === undefined) {
16009 return $scope.isRightLineShown;
16011 $scope.isRightLineShown = isShown;
16014 this.setLeftLineHover = function(isHovered) {
16015 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
16017 if($scope.isLeftLineShown && this.subCtrls[leftLineIndex] && this.subCtrls[leftLineIndex].setActiveState) {
16018 this.subCtrls[leftLineIndex].setActiveState(isHovered);
16021 this.setRightLineHover = function(isHovered) {
16022 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
16023 if($scope.isRightLineShown && this.subCtrls[rightLineIndex] && this.subCtrls[rightLineIndex].setActiveState){
16024 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16027 this.toggleLines = function(isHovered, buttonGroupCtrl, buttonCtrl, isDropDownOpen) {
16028 var subIconButtons = buttonGroupCtrl.subIconButtons;
16029 var subIconButtonsLength = subIconButtons.length;
16030 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
16031 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
16032 function noVerticalLineToggle() {
16033 for(var i =0; i < subIconButtonsLength; i++) {
16034 if(subIconButtons[i] === buttonCtrl) {
16035 if(i + 1 <= subIconButtonsLength - 1 && subIconButtons[i+1].isLeftLineShown()
16036 && subIconButtons[i+1].subCtrls[leftLineIndex]
16037 && subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState) {
16038 subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState(isHovered);
16040 if(i - 1 >= 0 && subIconButtons[i-1].isRightLineShown()
16041 && subIconButtons[i-1].subCtrls[rightLineIndex]
16042 && subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState) {
16043 subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState(isHovered);
16049 if(isDropDownOpen) {
16051 If the button is next to the dropdown button then just keep the
16052 buttons left line or its left neighbors right line toggled on
16053 If the button is the dropdown button don't do anything
16054 else do things normally witht the button
16056 /*if(subIconButtons[subIconButtonsLength-1] === buttonCtrl) {
16060 if(subIconButtons[subIconButtonsLength-2]==buttonCtrl) {
16061 if(subIconButtons[subIconButtonsLength-2].isLeftLineShown()) {
16062 subIconButtons[subIconButtonsLength-2].subCtrls[leftLineIndex].setActiveState(isHovered);
16063 } else if(subIconButtonsLength - 3 >= 0) {
16064 if(subIconButtons[subIconButtonsLength-3].isRightLineShown()) {
16065 subIconButtons[subIconButtonsLength-3].subCtrls[rightLineIndex].setActiveState(isHovered);
16069 noVerticalLineToggle();
16071 if($scope.isLeftLineShown) {
16072 this.subCtrls[leftLineIndex].setActiveState(isHovered);
16074 if($scope.isRightLineShown) {
16075 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16078 } else { // End of if(isDropDownOpen)
16079 //Handle Special cases where they aren't showing any vertical lines
16080 //and the dropdown isn't down
16081 if(!$scope.isLeftLineShown && !$scope.isRightLineShown) {
16082 noVerticalLineToggle();
16084 if($scope.isLeftLineShown && this.subCtrls[leftLineIndex].setActiveState) {
16085 this.subCtrls[leftLineIndex].setActiveState(isHovered);
16087 if($scope.isRightLineShown && this.subCtrls[rightLineIndex].setActiveState){
16088 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16092 this.setButtonType = function(type){
16093 var buttonIndex = getDirIndex(iconStateConstants.DIR_TYPE.BUTTON);
16094 if(this.subCtrls[buttonIndex] && this.subCtrls[buttonIndex].setType) {
16095 this.subCtrls[buttonIndex].setType(type);
16099 .directive('attSplitIconButton', ['$document', 'iconStateConstants', 'keymap',
16100 function($document, iconStateConstants, keymap){
16106 require: ['^attSplitIconButtonGroup', 'attSplitIconButton'],
16107 controller: 'AttSplitIconButtonCtrl',
16108 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html',
16114 link: function(scope,element,attr,ctrls) {
16116 scope.title = scope.icon;
16118 var attSplitButtonGroupCtrl = ctrls[0];
16119 var attSplitIconButtonCtrl = ctrls[1];
16120 attSplitButtonGroupCtrl.addIconButton(attSplitIconButtonCtrl);
16121 element.bind('keydown', function(e){
16122 //Check if the key is the up or down key
16123 if(e.which === keymap.KEY.ESC ||
16124 e.which === keymap.KEY.DOWN ||
16125 e.which === keymap.KEY.ENTER ||
16126 e.which === keymap.KEY.UP ||
16127 e.which === keymap.KEY.TAB ) {
16128 scope.clickHandler();
16129 scope.$broadcast(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, e);
16132 scope.dropDownWatch = false;
16133 scope.iconStateConstants = iconStateConstants;
16134 scope.clickHandler = function() {
16135 attSplitButtonGroupCtrl.hideLeftLineRightButton(attSplitIconButtonCtrl);
16137 scope.$watch('isHovered', function(val){
16139 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
16141 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
16144 scope.$watch('dropDownWatch', function(val) {
16145 attSplitButtonGroupCtrl.isDropDownOpen = val;
16146 attSplitButtonGroupCtrl.toggleDropdownState(val);
16151 .controller('AttSplitIconButtonGroupCtrl', ['$scope','iconStateConstants',function($scope,iconStateConstants){
16152 this.subIconButtons = [];
16153 this.addIconButton = function(iconButton){
16154 this.subIconButtons.push(iconButton);
16156 this.isDropDownOpen = false;
16157 this.hideLeftLineRightButton = function(btn){
16158 var numButtons = this.subIconButtons.length;
16159 var buttonLeftOfRightMost = this.subIconButtons[numButtons - 2];
16160 var rightMostButton = this.subIconButtons[numButtons -1];
16162 if (btn != buttonLeftOfRightMost && btn != rightMostButton ){
16163 rightMostButton.setLeftLineHover(false);
16166 this.toggleDropdownState = function(isDropDownOpen){
16167 var numButtons = this.subIconButtons.length;
16168 if(numButtons > 2) {
16169 if(isDropDownOpen) {
16170 if(this.subIconButtons[numButtons - 2].isRightLineShown()) {
16171 this.subIconButtons[numButtons - 2].setRightLineHover(true);
16173 this.subIconButtons[numButtons - 1].setLeftLineHover(true);
16175 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.NEXT_TO_DROPDOWN);
16177 this.subIconButtons[numButtons - 1].setLeftLineHover(false);
16178 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.MIDDLE);
16181 if(isDropDownOpen) {
16182 this.subIconButtons[0].setRightLineHover(true);
16183 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT_NEXT_TO_DROPDOWN);
16185 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT);
16190 .directive('attSplitIconButtonGroup', ['$document', '$timeout', 'iconStateConstants' ,function($document,$timeout,iconStateConstants){
16196 require: 'attSplitIconButtonGroup',
16197 controller: 'AttSplitIconButtonGroupCtrl',
16198 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html',
16200 link: function(scope,element,attr,ctrls){
16201 $timeout(initialize,100);
16202 function initialize(){
16203 var subIconButtonCtrls = ctrls.subIconButtons;
16204 var leftMostButtonIndex = 0;
16205 var rightMostButtonIndex =subIconButtonCtrls.length-1;
16206 //left most button config
16207 subIconButtonCtrls[leftMostButtonIndex].setButtonType(iconStateConstants.LEFT);
16208 subIconButtonCtrls[leftMostButtonIndex].isLeftLineShown(false);
16209 subIconButtonCtrls[leftMostButtonIndex].isRightLineShown(true);
16210 //right most button config
16211 subIconButtonCtrls[rightMostButtonIndex].setButtonType(iconStateConstants.RIGHT);
16212 subIconButtonCtrls[rightMostButtonIndex].isRightLineShown(false);
16213 subIconButtonCtrls[rightMostButtonIndex].isLeftLineShown(false);
16214 //middle buttons config
16215 if(rightMostButtonIndex >= 2) {
16217 while(index < rightMostButtonIndex) {
16218 subIconButtonCtrls[index].setButtonType(iconStateConstants.MIDDLE);
16219 subIconButtonCtrls[index].isRightLineShown(false);
16220 subIconButtonCtrls[index].isLeftLineShown(false);
16224 while(skipIndex <= rightMostButtonIndex){
16225 if(skipIndex == rightMostButtonIndex) {
16226 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
16228 subIconButtonCtrls[skipIndex].isRightLineShown(true);
16229 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
16231 skipIndex = skipIndex + 2;
16234 //reposition the dropdown
16235 var ulElem = element.find('ul');
16236 if(ulElem.length > 0) {
16237 var numButtons = rightMostButtonIndex+1;
16238 if(numButtons > 2) {
16239 var offset = (numButtons)*34-70+(numButtons/1.5) + 0.5;
16240 var offSetStr = offset+'px';
16241 angular.element(ulElem).css('left',offSetStr);
16242 angular.element(ulElem).css('border-top-left-radius','0px');
16244 angular.element(ulElem).css('left','0px');
16252 angular.module('att.abs.stepSlider', ['att.abs.position'])
16253 .constant('sliderConstants', {
16255 The MIT License (MIT)
16256 Copyright (c) 2013 Julien Valéry
16269 className: "jslider",
16270 selector: ".jslider-"
16276 BLUE_HIGHLIGHT: 'blue',
16277 MAGENTA: 'magenta',
16280 DARK_BLUE: 'dark-blue',
16281 REGULAR: 'regular',
16285 .factory('utils', function () {
16287 The MIT License (MIT)
16288 Copyright (c) 2013 Julien Valéry
16291 offset: function (elm) {
16292 var rawDom = elm[0];
16295 var body = document.documentElement || document.body;
16296 var scrollX = window.pageXOffset || body.scrollLeft;
16297 var scrollY = window.pageYOffset || body.scrollTop;
16298 _x = rawDom.getBoundingClientRect().left + scrollX;
16299 _y = rawDom.getBoundingClientRect().top + scrollY;
16300 return {left: _x, top: _y};
16302 roundUpToScale: function (mousePrc, scale, cutOffWidth, cutOffIndex) {
16308 for (var index = 1; index < scale.length; index++) {
16309 lowerVal = scale[index - 1];
16310 higherVal = scale[index];
16311 middle = ((higherVal - lowerVal) * .5) + lowerVal;
16313 Handles a situation where the user clicks close to the start point of
16314 the slider but the pointer doesn't move
16316 if ((lowerVal === 0 && mousePrc <= middle) || checkEquality(lowerVal, mousePrc)) {
16317 newMousePrc = lowerVal;
16320 else if (lowerVal < mousePrc && (mousePrc < higherVal ||
16321 checkEquality(mousePrc, higherVal)))
16323 newMousePrc = higherVal;
16327 //Check if the newMousePrc is <= the cuttOffPoint
16328 if (cutOffWidth && newMousePrc < cutOffWidth) {
16329 return scale[cutOffIndex];
16332 return newMousePrc;
16335 Checks to see if 2 points are so close that they are
16338 function checkEquality(point1, point2) {
16339 var precision = 0.1;
16340 if (Math.abs(point2 - point1) <= precision) {
16346 valueForDifferentScale: function (from, to, prc, prcToValueMapper) {
16347 var decimalPrc = prc / 100;
16348 if (decimalPrc === 0) {
16351 return prcToValueMapper[prc];
16353 /* converts the default value Kbps to Mbps or Gbps */
16354 convertToMbpsGbps: function (unitValue, unitLabel, configDecimalPlaces) {
16355 var defaultDecimalPlaces = 3; /* this is the default decimal places as per business requirements */
16356 if (configDecimalPlaces) {
16357 defaultDecimalPlaces = configDecimalPlaces;
16360 if ((unitValue > 1024 && unitValue < 1000000) && angular.equals(unitLabel, 'Kbps')) {
16361 unitValue = truncator((unitValue/1000), defaultDecimalPlaces);
16362 unitLabel = 'Mbps';
16363 } else if ((unitValue > 1024 && unitValue < 1000000) && angular.equals(unitLabel, 'Mbps')){
16364 unitValue = truncator((unitValue/1000), defaultDecimalPlaces);
16365 unitLabel = 'Mbps';
16366 } else if (unitValue <= 1024 && angular.equals(unitLabel, 'Mbps')) {
16367 unitLabel = 'Kbps';
16369 unitLabel = 'Kbps';
16372 if (unitValue >= 1000000 && angular.equals(unitLabel, 'Kbps')) {
16373 unitValue = truncator((unitValue/1000000), defaultDecimalPlaces);
16374 unitLabel = 'Gbps';
16377 unitValue: unitValue,
16378 unitLabel: unitLabel
16381 function truncator(numToTruncate, intDecimalPlaces) {
16382 var cnvrtdNum = Math.pow(10, intDecimalPlaces);
16383 return ~~(numToTruncate * cnvrtdNum)/cnvrtdNum;
16386 getConversionFactorValue: function (value, conversion, firstDimension) {
16388 Loop through the conversion array and keep checking the
16391 if (value <= conversion[0].startVal) {
16394 scaledDimension: firstDimension
16398 for (var index in conversion) {
16399 var c = conversion[index];
16400 if (value > c.startVal) {
16404 var scaleFactor = conversion[endIndex].scaleFactor;
16405 var scaledVal = value / scaleFactor;
16406 var scaledDimension = conversion[endIndex].dimension;
16408 scaledVal: scaledVal,
16409 scaledDimension: scaledDimension
16414 .factory('sliderDraggable', ['utils', function (utils) {
16416 The MIT License (MIT)
16417 Copyright (c) 2013 Julien Valéry
16419 function Draggable() {
16420 this._init.apply(this, arguments);
16422 Draggable.prototype.oninit = function () {
16424 Draggable.prototype.events = function () {
16426 Draggable.prototype.onmousedown = function () {
16427 this.ptr.css({position: "absolute"});
16429 Draggable.prototype.onmousemove = function (evt, x, y) {
16430 this.ptr.css({left: x, top: y});
16432 Draggable.prototype.onmouseup = function () {
16434 Draggable.prototype.isDefault = {
16440 Draggable.prototype._init = function () {
16441 if (arguments.length > 0) {
16442 this.ptr = arguments[0];
16443 this.parent = arguments[2];
16448 angular.extend(this.is, this.isDefault);
16449 var offset = utils.offset(this.ptr);
16453 width: this.ptr[0].clientWidth,
16454 height: this.ptr[0].clientHeight
16456 this.oninit.apply(this, arguments);
16460 Draggable.prototype._getPageCoords = function (event) {
16462 if (event.targetTouches && event.targetTouches[0]) {
16463 value = {x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY};
16465 value = {x: event.pageX, y: event.pageY};
16469 Draggable.prototype._bindEvent = function (ptr, eventType, handler) {
16470 if (this.supportTouches_) {
16471 ptr[0].attachEvent(this.events_[ eventType ], handler);
16475 ptr.bind(this.events_[ eventType ], handler);
16479 Draggable.prototype._events = function () {
16481 this.supportTouches_ = 'ontouchend' in document;
16483 "click": this.supportTouches_ ? "touchstart" : "click",
16484 "down": this.supportTouches_ ? "touchstart" : "mousedown",
16485 "move": this.supportTouches_ ? "touchmove" : "mousemove",
16486 "up": this.supportTouches_ ? "touchend" : "mouseup",
16487 "mousedown": this.supportTouches_ ? "mousedown" : "mousedown"
16489 var documentElt = angular.element(window.document);
16490 this._bindEvent(documentElt, "move", function (event) {
16491 if (self.is.drag) {
16492 event.stopPropagation();
16493 event.preventDefault();
16494 if (!self.parent.disabled) {
16495 self._mousemove(event);
16499 this._bindEvent(documentElt, "down", function (event) {
16500 if (self.is.drag) {
16501 event.stopPropagation();
16502 event.preventDefault();
16505 this._bindEvent(documentElt, "up", function (event) {
16506 self._mouseup(event);
16508 this._bindEvent(this.ptr, "down", function (event) {
16509 self._mousedown(event);
16512 this._bindEvent(this.ptr, "up", function (event) {
16513 self._mouseup(event);
16517 Draggable.prototype._mousedown = function (evt) {
16518 this.is.drag = true;
16519 this.is.clicked = false;
16520 this.is.mouseup = false;
16521 var coords = this._getPageCoords(evt);
16522 this.cx = coords.x - this.ptr[0].offsetLeft;
16523 this.cy = coords.y - this.ptr[0].offsetTop;
16524 angular.extend(this.d, {
16525 left: this.ptr[0].offsetLeft,
16526 top: this.ptr[0].offsetTop,
16527 width: this.ptr[0].clientWidth,
16528 height: this.ptr[0].clientHeight
16530 if (this.outer && this.outer.get(0)) {
16531 this.outer.css({height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden"});
16533 this.onmousedown(evt);
16535 Draggable.prototype._mousemove = function (evt) {
16536 if (this.uid === 0) {
16539 this.is.toclick = false;
16540 var coords = this._getPageCoords(evt);
16541 this.onmousemove(evt, coords.x - this.cx, coords.y - this.cy);
16543 Draggable.prototype._mouseup = function (evt) {
16544 if (this.is.drag) {
16545 this.is.drag = false;
16546 if (this.outer && this.outer.get(0)) {
16547 if ($.browser.mozilla) {
16548 this.outer.css({overflow: "hidden"});
16550 this.outer.css({overflow: "visible"});
16552 if ($.browser.msie && $.browser.version === '6.0') {
16553 this.outer.css({height: "100%"});
16555 this.outer.css({height: "auto"});
16558 this.onmouseup(evt);
16563 .factory('sliderPointer', ['sliderDraggable', 'utils', function (Draggable, utils) {
16565 The MIT License (MIT)
16566 Copyright (c) 2013 Julien Valéry
16568 function SliderPointer() {
16569 Draggable.apply(this, arguments);
16571 SliderPointer.prototype = new Draggable();
16572 SliderPointer.prototype.oninit = function (ptr, id, _constructor) {
16574 this.parent = _constructor;
16576 this.settings = angular.copy(_constructor.settings);
16578 SliderPointer.prototype.onmousedown = function (evt) {
16579 var off = utils.offset(this.parent.domNode);
16583 width: this.parent.domNode[0].clientWidth,
16584 height: this.parent.domNode[0].clientHeight
16588 width: offset.width,
16589 height: offset.height
16591 this.ptr.addClass("jslider-pointer-hover");
16592 this.setIndexOver();
16594 SliderPointer.prototype.onmousemove = function (evt, x, y) {
16595 var coords = this._getPageCoords(evt);
16596 //val is the percent where the slider pointer is located
16597 var val = this.calc(coords.x);
16598 if (!this.parent.settings.smooth) {
16599 val = utils.roundUpToScale(val,
16600 this.parent.settings.scale,
16601 this.parent.settings.cutOffWidth,
16602 this.parent.settings.cutOffIndex);
16604 var cutOffWidth = this.parent.settings.cutOffWidth;
16605 if (cutOffWidth && val < cutOffWidth) {
16610 SliderPointer.prototype.onmouseup = function (evt) {
16611 if (this.settings.callback && angular.isFunction(this.settings.callback)) {
16612 var val = this.parent.getValue();
16613 this.settings.callback.call(this.parent, val);
16615 this.ptr.removeClass("jslider-pointer-hover");
16617 SliderPointer.prototype.setIndexOver = function () {
16618 this.parent.setPointersIndex(1);
16621 SliderPointer.prototype.index = function (i) {
16623 SliderPointer.prototype.limits = function (x) {
16624 return this.parent.limits(x, this);
16626 SliderPointer.prototype.calc = function (coords) {
16627 var diff = coords - this._parent.offset.left;
16628 var val = this.limits((diff * 100) / this._parent.width);
16631 SliderPointer.prototype.set = function (value, opt_origin) {
16632 this.value.origin = this.parent.round(value);
16633 this._set(this.parent.valueToPrc(value, this), opt_origin);
16635 SliderPointer.prototype._set = function (prc, opt_origin) {
16637 this.value.origin = this.parent.prcToValue(prc);
16639 this.value.prc = prc;
16640 //Sets the location of the SliderPointer
16641 this.ptr.css({left: prc + '%'});
16642 this.parent.redraw(this);
16644 return SliderPointer;
16646 .factory('slider', ['sliderPointer', 'sliderConstants', 'utils', function (SliderPointer, sliderConstants, utils) {
16648 The MIT License (MIT)
16649 Copyright (c) 2013 Julien Valéry
16652 function Slider() {
16653 return this.init.apply(this, arguments);
16655 function changeCutOffWidth(width) {
16656 cutOffDom.css('width', width);
16659 Slider.prototype.changeCutOffWidth = changeCutOffWidth;
16660 Slider.prototype.init = function (inputNode, templateNode, settings) {
16661 this.settings = sliderConstants.SLIDER.settings;
16662 angular.extend(this.settings, angular.copy(settings));
16663 this.inputNode = inputNode;
16664 this.inputNode.addClass("ng-hide");
16665 this.settings.interval = this.settings.to - this.settings.from;
16666 if (this.settings.calculate && $.isFunction(this.settings.calculate)) {
16667 this.nice = this.settings.calculate;
16669 if (this.settings.onstatechange && $.isFunction(this.settings.onstatechange)) {
16670 this.onstatechange = this.settings.onstatechange;
16672 this.is = {init: false};
16674 this.create(templateNode);
16676 Slider.prototype.create = function (templateNode) {
16678 this.domNode = templateNode;
16679 var off = utils.offset(this.domNode);
16683 width: this.domNode[0].clientWidth,
16684 height: this.domNode[0].clientHeight
16686 this.sizes = {domWidth: this.domNode[0].clientWidth, domOffset: offset};
16687 angular.extend(this.o, {
16691 o: angular.element(this.domNode.find('div')[5])
16694 o: angular.element(this.domNode.find('div')[6])
16698 0: angular.element(this.domNode.find('div')[3]),
16699 1: angular.element(this.domNode.find('div')[5])
16702 angular.extend(this.o.labels[0], {
16703 value: this.o.labels[0].o.find("span")
16705 angular.extend(this.o.labels[1], {
16706 value: this.o.labels[1].o.find("span")
16708 if (!$this.settings.value.split(";")[1]) {
16709 this.settings.single = true;
16711 var domNodeDivs = this.domNode.find('div');
16712 cutOffDom = angular.element(domNodeDivs[8]);
16713 if (cutOffDom && cutOffDom.css) {
16714 cutOffDom.css('width', '0%');
16716 var pointers = [angular.element(domNodeDivs[1]), angular.element(domNodeDivs[2])];
16717 angular.forEach(pointers, function (pointer, key) {
16718 $this.settings = angular.copy($this.settings);
16719 var value = $this.settings.value.split(';')[key];
16721 $this.o.pointers[key] = new SliderPointer(pointer, key, $this);
16722 var prev = $this.settings.value.split(';')[key - 1];
16723 if (prev && parseInt(value, 10) < parseInt(prev, 10)) {
16726 var value1 = value < $this.settings.from ? $this.settings.from : value;
16727 value1 = value > $this.settings.to ? $this.settings.to : value;
16728 $this.o.pointers[key].set(value1, true);
16730 $this.domNode.bind('mousedown', $this.clickHandler.apply($this));
16734 this.o.value = angular.element(this.domNode.find("i")[2]);
16735 this.is.init = true;
16736 angular.forEach(this.o.pointers, function (pointer) {
16737 $this.redraw(pointer);
16740 Slider.prototype.clickHandler = function () {
16742 return function (evt) {
16743 if (self.disabled) {
16746 var className = evt.target.className;
16748 if (className.indexOf('jslider-pointer-to') > 0) {
16751 var _off = utils.offset(self.domNode);
16755 width: self.domNode[0].clientWidth,
16756 height: self.domNode[0].clientHeight
16759 var targetPtr = self.o.pointers[targetIdx];
16760 targetPtr._parent = {offset: offset, width: offset.width, height: offset.height};
16761 targetPtr._mousemove(evt);
16762 targetPtr.onmouseup();
16766 Slider.prototype.disable = function (bool) {
16767 this.disabled = bool;
16769 Slider.prototype.nice = function (value) {
16772 Slider.prototype.onstatechange = function () {
16774 Slider.prototype.limits = function (x, pointer) {
16775 if (!this.settings.smooth) {
16776 var step = this.settings.step * 100 / (this.settings.interval);
16777 x = Math.round(x / step) * step;
16779 var another = this.o.pointers[1 - pointer.uid];
16780 if (another && pointer.uid && x < another.value.prc) {
16781 x = another.value.prc;
16783 if (another && !pointer.uid && x > another.value.prc) {
16784 x = another.value.prc;
16792 var val = Math.round(x * 10) / 10;
16795 Slider.prototype.setPointersIndex = function (i) {
16796 angular.forEach(this.getPointers(), function (pointer, i) {
16800 Slider.prototype.getPointers = function () {
16801 return this.o.pointers;
16803 Slider.prototype.onresize = function () {
16806 domWidth: this.domNode[0].clientWidth,
16807 domHeight: this.domNode[0].clientHeight,
16809 left: this.domNode[0].offsetLeft,
16810 top: this.domNode[0].offsetTop,
16811 width: this.domNode[0].clientWidth,
16812 height: this.domNode[0].clientHeight
16815 angular.forEach(this.o.pointers, function (ptr, key) {
16819 Slider.prototype.update = function () {
16823 Slider.prototype.drawScale = function () {
16825 Slider.prototype.redraw = function (pointer) {
16826 if (!this.settings.smooth) {
16827 var newMousePrc = utils.roundUpToScale(pointer.value.prc,
16828 this.settings.scale,
16829 this.settings.cutOffWidth,
16830 this.settings.cutOffIndex);
16831 pointer.value.origin = newMousePrc;
16832 pointer.value.prc = newMousePrc;
16835 if (!this.is.init) {
16839 var width = this.o.pointers[1].value.prc;
16840 var newPos = {left: '0%', width: width + '%'};
16841 this.o.value.css(newPos);
16842 var htmlValue = this.nice(pointer.value.origin);
16843 var scaledDimension = this.settings.firstDimension;
16844 if (this.settings.stepWithDifferentScale && !this.settings.smooth) {
16845 htmlValue = utils.valueForDifferentScale(this.settings.from,
16846 this.settings.to, htmlValue, this.settings.prcToValueMapper);
16848 //This is the base value before the conversion
16849 if (this.settings.realtimeCallback && angular.isFunction(this.settings.realtimeCallback)
16850 && this.settings.cutOffVal !== undefined && pointer.uid === 1) {
16851 this.settings.realtimeCallback(htmlValue);
16853 //Need to change this to the correct value for the scale
16854 if (this.settings.conversion) {
16855 var conversionObj = utils.getConversionFactorValue(parseInt(htmlValue),
16856 this.settings.conversion,
16857 this.settings.firstDimension);
16858 htmlValue = conversionObj.scaledVal;
16859 scaledDimension = conversionObj.scaledDimension;
16862 htmlValue = parseFloat(htmlValue);
16863 var tooltipLabel = utils.convertToMbpsGbps(htmlValue, scaledDimension, this.settings.decimalPlaces);
16865 this.o.labels[pointer.uid].value.html(tooltipLabel.unitValue + ' ' + tooltipLabel.unitLabel);
16866 //Top tooltip label
16867 this.redrawLabels(pointer);
16869 Slider.prototype.redrawLabels = function (pointer) {
16870 function setPosition(label, sizes, prc) {
16871 sizes.margin = -sizes.label / 2;
16872 var domSize = self.sizes.domWidth;
16873 var label_left = sizes.border + sizes.margin;
16874 if (label_left < 0) {
16875 sizes.margin -= label_left;
16877 if (sizes.border + sizes.label / 2 > domSize) {
16879 sizes.right = true;
16881 sizes.right = false;
16882 //Adjust the tooltip location
16883 sizes.margin = -((label.o[0].clientWidth / 2) - label.o[0].clientWidth / 20);
16884 label.o.css({left: prc + "%", marginLeft: sizes.margin, right: "auto"});
16886 label.o.css({left: "auto", right: 0});
16890 var label = this.o.labels[pointer.uid];
16891 var prc = pointer.value.prc;
16893 label: label.o[0].offsetWidth,
16895 border: (prc * domSize) / 100
16897 var another_label = null;
16898 var another = null;
16899 if (!this.settings.single) {
16900 another = this.o.pointers[1 - pointer.uid];
16901 another_label = this.o.labels[another.uid];
16902 switch (pointer.uid) {
16904 if (sizes.border + sizes.label / 2 > another_label.o[0].offsetLeft - this.sizes.domOffset.left) {
16905 another_label.o.css({visibility: "hidden"});
16906 another_label.value.html(this.nice(another.value.origin));
16907 label.o.css({visibility: "hidden"});
16908 prc = (another.value.prc - prc) / 2 + prc;
16909 if (another.value.prc !== pointer.value.prc) {
16910 label.value.html(this.nice(pointer.value.origin) + " – " + this.nice(another.value.origin));
16911 sizes.label = label.o[0].clientWidth;
16912 sizes.border = (prc * domSize) / 100;
16915 another_label.o.css({visibility: "visible"});
16919 if (sizes.border - sizes.label / 2 < another_label.o[0].offsetLeft - this.sizes.domOffset.left + another_label.o[0].clientWidth) {
16920 another_label.o.css({visibility: "hidden"});
16921 another_label.value.html(this.nice(another.value.origin));
16922 label.o.css({visibility: "visible"});
16923 prc = (prc - another.value.prc) / 2 + another.value.prc;
16924 if (another.value.prc !== pointer.value.prc) {
16925 label.value.html(this.nice(another.value.origin) + " – " + this.nice(pointer.value.origin));
16926 sizes.label = label.o[0].clientWidth;
16927 sizes.border = (prc * domSize) / 100;
16930 another_label.o.css({visibility: "visible"});
16935 sizes = setPosition(label, sizes, prc);
16936 var domSize = self.sizes.domWidth;
16937 //This is the 0th pointer
16938 if (another_label) {
16940 label: another_label.o[0].clientWidth,
16942 border: (another.value.prc * this.sizes.domWidth) / 100
16944 sizes = setPosition(another_label, sizes, another.value.prc);
16947 Slider.prototype.redrawLimits = function () {
16948 if (this.settings.limits) {
16949 var limits = [true, true];
16950 for (var key in this.o.pointers) {
16951 if (!this.settings.single || key === 0) {
16952 var pointer = this.o.pointers[key];
16953 var label = this.o.labels[pointer.uid];
16954 var label_left = label.o[0].offsetLeft - this.sizes.domOffset.left;
16955 var limit = this.o.limits[0];
16956 if (label_left < limit[0].clientWidth)
16958 limit = this.o.limits[1];
16959 if (label_left + label.o[0].clientWidth > this.sizes.domWidth - limit[0].clientWidth)
16963 for (var i = 0; i < limits.length; i++) {
16965 angular.element(this.o.limits[i]).addClass("animate-show");}
16967 angular.element(this.o.limits[i]).addClass("animate-hidde");}
16971 Slider.prototype.setValue = function () {
16972 var value = this.getValue();
16973 this.inputNode.attr("value", value);
16974 this.onstatechange.call(this, value, this.inputNode);
16976 Slider.prototype.getValue = function () {
16977 if (!this.is.init){
16981 angular.forEach(this.o.pointers, function (pointer, key) {
16982 if (pointer.value.prc !== undefined && !isNaN(pointer.value.prc)) {
16983 var pointerPrc = pointer.value.prc;
16984 var myValue = $this.prcToValue(pointerPrc);
16985 if (!$this.settings.smooth) {
16986 var myValue = utils.valueForDifferentScale($this.settings.from,
16989 $this.settings.prcToValueMapper);
16991 value += (key > 0 ? ";" : "") + myValue;
16996 Slider.prototype.getPrcValue = function () {
17000 $.each(this.o.pointers, function (i) {
17001 if (this.value.prc !== undefined && !isNaN(this.value.prc))
17002 value += (i > 0 ? ";" : "") + this.value.prc;
17006 Slider.prototype.prcToValue = function (prc) {
17008 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
17009 var h = this.settings.heterogeneity;
17011 var _from = this.settings.from;
17012 for (var i = 0; i <= h.length; i++) {
17015 v = h[i].split("/");}
17017 v = [100, this.settings.to];}
17018 if (prc >= _start && prc <= v[0]) {
17019 value = _from + ((prc - _start) * (v[1] - _from)) / (v[0] - _start);
17026 value = this.settings.from + (prc * this.settings.interval) / 100;
17028 var roundedValue = this.round(value);
17029 return roundedValue;
17031 Slider.prototype.valueToPrc = function (value, pointer) {
17033 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
17034 var h = this.settings.heterogeneity;
17036 var _from = this.settings.from;
17037 for (var i = 0; i <= h.length; i++) {
17040 v = h[i].split("/");
17042 v = [100, this.settings.to];
17043 if (value >= _from && value <= v[1]) {
17044 prc = pointer.limits(_start + (value - _from) * (v[0] - _start) / (v[1] - _from));
17050 prc = pointer.limits((value - this.settings.from) * 100 / this.settings.interval);
17054 Slider.prototype.round = function (value) {
17055 value = Math.round(value / this.settings.step) * this.settings.step;
17056 if (this.settings.round){
17057 value = Math.round(value * Math.pow(10, this.settings.round)) / Math.pow(10, this.settings.round);}
17059 value = Math.round(value);}
17064 .directive('attStepSlider', [
17065 '$compile', '$templateCache', '$timeout', '$window', 'slider', 'sliderConstants', 'utils',
17066 function (compile, templateCache, timeout, win, Slider, sliderConstants, utils) {
17068 The MIT License (MIT)
17069 Copyright (c) 2013 Julien Valéry
17071 var templateUrl = 'app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html';
17074 require: '?ngModel',
17080 templateUrl: templateUrl,
17081 link: function (scope, element, attrs, ngModel) {
17084 scope.mainSliderClass = 'step-slider';
17085 element.after(compile(templateCache.get(templateUrl))(scope, function (clonedElement, scope) {
17086 scope.tmplElt = clonedElement;
17088 ngModel.$render = function () {
17089 if (ngModel.$viewValue.split && ngModel.$viewValue.split(";").length === 1) {
17090 ngModel.$viewValue = '0;' + ngModel.$viewValue;
17091 } else if (typeof (ngModel.$viewValue) === 'number') {
17092 ngModel.$viewValue = '0;' + ngModel.$viewValue;
17094 if (!ngModel.$viewValue && ngModel.$viewValue !== 0) {
17097 if (typeof (ngModel.$viewValue) === 'number') {
17098 ngModel.$viewValue = '' + ngModel.$viewValue;
17100 if (scope.slider) {
17101 var firstPointer = '0';
17102 scope.slider.getPointers()[0].set(firstPointer, true);
17103 if (ngModel.$viewValue.split(";")[1]) {
17104 var value = ngModel.$viewValue.split(";")[1];
17105 if (value.length >= 4) {
17106 value = value.substring(0, 2);
17108 if (!scope.options.realtime)
17109 scope.options.callback(parseFloat(ngModel.$viewValue.split(";")[1]));
17110 scope.slider.getPointers()[1].set(ngModel.$viewValue.split(";")[1], true);
17114 var init = function () {
17115 scope.from = '' + scope.options.from;
17116 scope.to = '' + scope.options.to;
17117 if (scope.options.calculate && typeof scope.options.calculate === 'function') {
17118 scope.from = scope.options.calculate(scope.from);
17119 scope.to = scope.options.calculate(scope.to);
17121 scope.showDividers = scope.options.showDividers;
17122 scope.COLORS = sliderConstants.COLORS;
17123 scope.sliderColor = scope.options.sliderColor;
17124 if (!scope.sliderColor)
17125 scope.sliderColor = sliderConstants.COLORS.REGULAR;
17126 var scaleArray = scope.options.scale;
17127 /* Make a copy of the scaleArray before converting it to percentage for the bars */
17128 var nonPercentScaleArray = [];
17129 /* Define variable for displaying lower range values */
17130 var scaledUpValueArray=[];
17131 /* Create Mapper for the percentage to value */
17132 var prcToValueMapper = {};
17133 for (var i in scaleArray) {
17134 var s = scaleArray[i];
17135 nonPercentScaleArray.push(s);
17137 function addScaleArrayStartAndEnd() {
17138 if (scaleArray[0] !== 0) {
17139 scaleArray.splice(0, 0, 0);
17141 if (scaleArray[scaleArray.length - 1] !== 100) {
17142 scaleArray.splice(scaleArray.length, 0, 100);
17145 function convertScaleArrayToPercentage() {
17146 if (scaleArray[scaleArray.length - 1] !== scope.options.to) {
17147 scaleArray.splice(scaleArray.length, 0, scope.options.to);
17150 if(scope.options.displayScaledvalues){
17151 for(var i in scaleArray){
17152 scaledUpValueArray.push(Math.log2(scaleArray[i]));
17154 var maxScaledUpValue=scaledUpValueArray[scaledUpValueArray.length-1];
17157 for (var i in scaleArray) {
17159 var fromValueCheck = (scaleArray[i] / scope.options.from);
17160 var toValueCheck = (scaleArray[i] / scope.options.to);
17162 if (scope.options.displayScaledvalues){
17163 prcValue = (scaledUpValueArray[i] /maxScaledUpValue)*100;
17165 prcValue = ((scaleArray[i] - scope.options.from) / (scope.options.to - scope.options.from)) * 100;
17168 var realValue = scaleArray[i];
17170 if (toValueCheck === 1) {
17173 else if (fromValueCheck === 1) {
17176 scaleArray[i] = prcValue;
17177 prcToValueMapper['' + prcValue] = realValue;
17180 if ((scope.options.from !== 0 || scope.options.to !== 100)
17181 && scope.options.smooth) {
17183 scale array is in real values.
17185 addScaleArrayStartAndEnd();
17186 scope.options.stepWithDifferentScale = true;
17188 else if ((scope.options.from !== 0 || scope.options.to !== 100)
17189 && !scope.options.smooth) {
17191 Case for different from and to values other than 0 and 100
17192 so we have to do some different calculations
17194 scope.options.stepWithDifferentScale = true;
17195 convertScaleArrayToPercentage();
17196 addScaleArrayStartAndEnd();
17200 This is the normal case where the from and to values are 0 and
17203 //Check that the scale starts at 0 and 100
17204 convertScaleArrayToPercentage();
17205 addScaleArrayStartAndEnd();
17207 var decimalPlaces = 0;
17208 if (scope.options.decimalPlaces) {
17209 decimalPlaces = scope.options.decimalPlaces;
17211 //Modify the endDimension based on whether converison was passed in
17212 //Also change the toStr value to scale to the last factor
17213 scope.endDimension = scope.options.dimension;
17214 if (scope.options.conversion) {
17215 //Get the dimension of the last conversion
17216 var lastIndex = scope.options.conversion.length - 1;
17217 var lastDimension = scope.options.conversion[lastIndex].dimension;
17218 var lastScaleFactor = scope.options.conversion[lastIndex].scaleFactor;
17219 scope.endDimension = ' ' + lastDimension;
17221 var toVal = (scope.to / lastScaleFactor).toFixed(decimalPlaces);
17222 scope.toStr = toVal;
17224 scope.toStr = scope.options.to;
17227 var tooltipLabel = utils.convertToMbpsGbps(scope.toStr, scope.endDimension, scope.options.decimalPlaces);
17228 scope.toStr = tooltipLabel.unitValue;
17229 scope.endDimension = ' ' + tooltipLabel.unitLabel;
17232 from: scope.options.from,
17233 to: scope.options.to,
17234 step: scope.options.step,
17235 smooth: scope.options.smooth,
17237 stepWithDifferentScale: scope.options.stepWithDifferentScale,
17238 round: scope.options.round || false,
17239 value: ngModel.$viewValue,
17240 scale: scope.options.scale,
17241 nonPercentScaleArray: nonPercentScaleArray,
17242 prcToValueMapper: prcToValueMapper,
17243 firstDimension: scope.options.dimension,
17244 decimalPlaces: decimalPlaces,
17245 conversion: scope.options.conversion,
17246 realtimeCallback: scope.options.callback
17248 if (angular.isFunction(scope.options.realtime)) {
17249 OPTIONS.realtimeCallback = function (value) {
17250 ngModel.$setViewValue(value);
17251 scope.options.callback(value);
17255 OPTIONS.callback = forceApply;
17257 OPTIONS.calculate = scope.options.calculate || undefined;
17258 OPTIONS.onstatechange = scope.options.onstatechange || undefined;
17259 timeout(function () {
17260 var scaleDiv = scope.tmplElt.find('div')[7];
17261 if (!OPTIONS.conversion) {
17262 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-left', '10px');
17263 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-right', '15px');
17265 scope.slider = angular.element.slider(element, scope.tmplElt, OPTIONS);
17266 angular.element(scaleDiv).html(scope.generateScale());
17267 scope.drawScale(scaleDiv);
17269 scope.$watch('options.disable', function (val) {
17270 if (scope.slider) {
17271 scope.tmplElt.toggleClass('disabled', val);
17272 scope.slider.disable(val);
17275 scope.$watch('cutOff', function (cutOffVal) {
17276 if (cutOffVal && cutOffVal > 0) {
17277 var cutOffPrc = (cutOffVal - scope.slider.settings.from) / (scope.slider.settings.to -
17278 scope.slider.settings.from);
17279 cutOffPrc = cutOffPrc * 100;
17280 scope.isCutOffSlider = true;
17281 scope.slider.settings.cutOffWidth = cutOffPrc;
17282 //cutOffVal is the actual value of the cutoff point
17283 scope.cutOffVal = cutOffVal;
17284 if (scope.options.conversion) {
17285 var convertedVal = utils.getConversionFactorValue(cutOffVal, scope.options.conversion, scope.options.dimension);
17286 convertedVal.scaledVal = parseFloat(convertedVal.scaledVal).toFixed(scope.options.decimalPlaces);
17287 scope.cutOffVal = convertedVal.scaledVal + ' ' + convertedVal.scaledDimension;
17289 scope.slider.settings.cutOffVal = cutOffVal;
17290 //Calculate the cutOff percentage
17291 scope.slider.changeCutOffWidth(cutOffPrc + '%');
17292 var scale = scope.slider.settings.nonPercentScaleArray;
17293 //Calculate where the cutOff point in relation to the scale array
17294 for (var i in scale) {
17296 var lowerVal = scale[i - 1];
17297 var higherVal = scale[i];
17298 if (cutOffVal > lowerVal && cutOffVal <= higherVal) {
17299 scope.slider.settings.cutOffIndex = i;
17304 scope.slider.settings.cutOffVal = 0;
17309 function initListener() {
17310 angular.element(win).bind('resize', function (event) {
17311 scope.slider.onresize();
17314 scope.generateScale = function () {
17315 if (scope.options.scale && scope.options.scale.length > 0) {
17317 var s = scope.options.scale;
17318 var position = 'left';
17319 for (var i = 0; i < s.length; i++) {
17320 if (i !== 0 && i !== s.length - 1) {
17321 var scaledPosition = ((s[i] - scope.from) / (scope.to - scope.from)) * 100;
17322 if (scope.options.stepWithDifferentScale && !scope.options.smooth) {
17323 scaledPosition = s[i];
17325 str += '<span style="' + position + ': ' + scaledPosition + '%"></span>';
17333 scope.drawScale = function (scaleDiv) {
17334 angular.forEach(angular.element(scaleDiv).find('ins'), function (scaleLabel, key) {
17335 scaleLabel.style.marginLeft = -scaleLabel.clientWidth / 2;
17338 var forceApply = function (value) {
17339 var val = value.split(";")[1];
17340 scope.$apply(function () {
17341 ngModel.$setViewValue(parseInt(val));
17343 if (scope.options.callback) {
17344 scope.options.callback(parseInt(val));
17347 scope.$watch('options', function (value) {
17350 angular.element.slider = function (inputElement, element, settings) {
17351 if (!element.data('jslider'))
17352 element.data('jslider', new Slider(inputElement, element, settings));
17353 var sliderObj = element.data('jslider');
17359 angular.module('att.abs.steptracker', ['att.abs.transition'])
17360 .directive('steptracker', ['$timeout', function ($timeout) {
17362 // This allows dev's clickHandler to cancel an operation
17366 cstep: "=currentStep",
17367 clickHandler: '=?',
17372 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/step-tracker.html',
17373 link: function (scope, elem) {
17374 if (scope.disableClick === undefined) {
17375 scope.disableClick = false;
17377 $timeout(function () {
17378 if (scope.cstep < 1) {
17381 else if (scope.cstep > scope.sdata.length) {
17382 scope.cstep = scope.sdata.length;
17384 var divs = elem.find('div');
17385 var slidertracks = [];
17386 for (var i in divs) {
17387 if (divs.eq(i)[0]) {
17388 var el = divs.eq(i)[0].className;
17389 if (el.indexOf('track ng-scope') > -1) {
17390 slidertracks.push(divs.eq(i));
17394 var currentPage,totalPage,currentTrack = updateCurrentTrack(scope.cstep);
17395 function updateCurrentTrack(step) {
17396 // Always return the step-1 because array starts at 0
17397 return angular.element(slidertracks[step - 1]);
17399 function updateTrackWidth() {
17400 if (scope.cstep > 0 && scope.cstep <= scope.sdata.length - 1 && currentPage > 0) {
17401 var newWidth = ((currentPage / totalPage) * 100) + "%";
17402 currentTrack = updateCurrentTrack(scope.cstep);
17403 currentTrack.css('width', newWidth);
17406 function updatePages() {
17407 if (scope.cstep <= scope.sdata.length) {
17408 currentPage = scope.sdata[scope.cstep - 1]['currentPage'];
17409 totalPage = scope.sdata[scope.cstep - 1]['totalPages'];
17412 // dynamically add width for steps, depending on the number of steps.
17413 scope.set_width = function (indexval) {
17414 var setwidth = (100 / (scope.sdata.length - 1)) + "%";
17415 // skip last element and add width for all other element
17416 if ((scope.sdata.length - 1) > indexval) {
17417 return {'width': setwidth};
17420 scope.$watch('sdata', function () {
17422 var prevStep = scope.cstep;
17423 // Before anything, ensure currentPage is never below 1
17424 if (currentPage < 1) {
17426 if (scope.cstep !== 1) {
17427 // Decrease step, current track width is 0%, new step width updates
17432 // Move to next step, reset currentPage, totalPage, and ensure previous steps are completed
17433 if (currentPage > totalPage) {
17434 if (scope.cstep > scope.sdata.length - 1) {
17438 currentPage = totalPage;
17439 updateTrackWidth();
17442 updateTrackWidth();
17445 if (currentPage < 1 && prevStep === scope.cstep) {
17447 if (scope.cstep > 1) {
17449 scope.sdata[scope.cstep - 1]['currentPage'] = scope.sdata[scope.cstep - 1]['totalPages'];
17450 scope.sdata[scope.cstep]['currentPage'] = 1;
17453 updateTrackWidth();
17455 //add the active class for current step
17456 scope.activestep = function (index) {
17457 return (index === scope.cstep - 1);
17459 //add the done class for finished step
17460 scope.donesteps = function (index) {
17461 return (index < scope.cstep - 1);
17463 //add the last class for final step
17464 scope.laststep = function (index) {
17465 return (index === scope.sdata.length - 1);
17467 scope.isIncomplete = function (index) {
17468 if (index === scope.cstep - 1) {
17471 if (index >= 0 && index < scope.sdata.length - 1) {
17472 var step = scope.sdata[index];
17473 return (step['currentPage'] <= step['totalPages']);
17477 scope.stepclick = function ($event, steps) {
17478 // If we are decreasing steps, reset all currentPage counts to 1
17479 if (steps < scope.cstep) {
17480 for (var i = scope.cstep - 1; i > steps; i--) {
17481 scope.sdata[i]['currentPage'] = 1;
17483 scope.sdata[steps]['currentPage']--;
17485 if (angular.isFunction(scope.clickHandler)) {
17486 scope.clickHandler($event, steps);
17488 scope.cstep = steps + 1;
17489 // In the case we decremented previously from this step, we need to reset currentpage to default
17490 if (scope.cstep <= scope.sdata.length && scope.sdata[scope.cstep]['currentPage'] < 1) {
17491 scope.sdata[scope.cstep]['currentPage'] = 1;
17494 updateTrackWidth();
17501 .constant('timelineConstants', {
17504 COMPLETED: 'completed',
17505 CANCELLED: 'cancelled'
17508 .controller('AttTimelineCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
17509 var timelineBarCtrls = [];
17510 var timelineDotCtrls = [];
17512 this.isAlternate = function () {
17513 return $scope.alternate;
17515 this.addTimelineBarCtrls = function (t) {
17516 timelineBarCtrls.push(t);
17518 this.addTimelineDotCtrls = function (b) {
17519 timelineDotCtrls.push(b);
17521 $timeout(init, 200);
17523 function compare(a, b) {
17524 if (a.order < b.order) {
17527 if (a.order > b.order) {
17532 timelineDotCtrls.sort(compare);
17533 timelineBarCtrls.sort(compare);
17534 if ($scope.$parent.animate) {
17537 $scope.$watch('trigger', function (val) {
17539 $scope.resetTimeline();
17541 $scope.$parent.animate = false;
17545 function animateSequence() {
17546 var dotsDuration = .25;
17547 var timelineBarProgressDuration = .25;
17548 if (typeof $scope.barAnimateDuration === 'number') {
17549 timelineBarProgressDuration = $scope.barAnimateDuration;
17551 var start = createAnimation(0, timelineBarProgressDuration);
17552 function setToInactiveStates() {
17553 for (var i in timelineDotCtrls) {
17554 var dotCtrl = timelineDotCtrls[i];
17556 dotCtrl.unhoveredStateForBelow(.25);
17558 dotCtrl.unhoveredStateForAbove(.25);
17560 if (dotCtrl.isStop()) {
17565 function createAnimation(i, duration) {
17567 return function () {
17568 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
17569 timelineBarCtrls[i].isCancelled(true);
17571 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17573 } else if (i === timelineBarCtrls.length - 1) {
17574 return function () {
17575 //Removes the bolded text from the start
17576 if (timelineDotCtrls[0].isCurrentStep()) {
17577 timelineDotCtrls[0].isCurrentStep(false);
17579 if (timelineDotCtrls[i].isStop()) {
17580 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17581 timelineDotCtrls[i].isCurrentStep(true);
17583 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17584 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17586 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17587 $timeout(function () {
17588 setToInactiveStates();
17593 else if (i === timelineBarCtrls.length) {
17594 return function () {
17595 //Removes the bolded text from the start
17596 if (timelineDotCtrls[0].isCurrentStep()) {
17597 timelineDotCtrls[0].isCurrentStep(false);
17599 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17600 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17601 timelineDotCtrls[i].isCurrentStep(true);
17602 $timeout(function () {
17603 setToInactiveStates();
17608 return function () {
17609 //Removes the bolded text from the start
17610 if (timelineDotCtrls[0].isCurrentStep()) {
17611 timelineDotCtrls[0].isCurrentStep(false);
17613 if (timelineDotCtrls[i].isStop()) {
17614 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17615 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17616 timelineDotCtrls[i].isCurrentStep(true);
17617 $timeout(function () {
17618 setToInactiveStates();
17621 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
17622 timelineBarCtrls[i].isCancelled(true);
17624 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17625 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17626 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17634 .directive('attTimeline', ['$timeout', '$compile', function ($timeout, $compile) {
17642 barAnimateDuration: '='
17644 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timeline.html',
17645 controller: 'AttTimelineCtrl',
17646 link: function (scope, element, attrs, ctrl) {
17647 var init = function () {
17648 var steps = scope.steps;
17649 var middleSteps = [];
17650 for (var i = 1; i < steps.length; i++) {
17651 var aStep = steps[i];
17652 middleSteps.push(aStep);
17654 scope.middleSteps = middleSteps;
17655 //Used in calculating the width of the loading bars
17656 ctrl.numSteps = steps.length - 1;
17659 //Recompile in case of scope changes
17660 scope.resetTimeline = function () {
17661 scope.animate = true;
17662 $compile(element)(scope);
17667 .controller('TimelineBarCtrl', ['$scope', function ($scope) {
17668 this.type = 'timelinebar';
17669 this.order = parseInt($scope.order);
17670 this.animate = function (callback, duration) {
17671 $scope.loadingAnimation(callback, duration);
17673 this.isCancelled = function (isCancelled) {
17674 $scope.isCancelled = isCancelled;
17677 .directive('timelineBar', ['animation', '$progressBar', function (animation, $progressBar) {
17681 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineBar.html',
17685 require: ['^attTimeline', 'timelineBar'],
17686 controller: 'TimelineBarCtrl',
17687 link: function (scope, element, attrs, ctrls) {
17688 var attTimelineCtrl = ctrls[0];
17689 var timelineBarCtrl = ctrls[1];
17690 attTimelineCtrl.addTimelineBarCtrls(timelineBarCtrl);
17691 scope.isCompleted = true;
17692 var widthPerc = (100 / attTimelineCtrl.numSteps) - 3;
17693 element.css('width', widthPerc + '%');
17694 var elem = element.find('div').eq(0);
17695 animation.set(elem, {opacity: 0.0});
17696 var updateCallback = function (selfElement) {
17697 animation.set(elem, {opacity: 1.0});
17698 animation.set(elem, {
17699 scaleX: selfElement.progress(),
17700 transformOrigin: "left"
17703 scope.loadingAnimation = $progressBar(updateCallback);
17707 .controller('TimelineDotCtrl', ['$scope', '$timeout', 'timelineConstants', function ($scope, $timeout, timelineConstants) {
17709 this.order = parseInt($scope.order);
17711 $timeout(function () {
17712 if (self.order !== 0) {
17713 if (self.order % 2 !== 0) {
17714 $scope.initializeAboveForAnimation();
17717 $scope.initializeBelowForAnimation();
17721 this.expandedAnimate = function (duration) {
17723 $scope.expandedAnimate(duration);
17724 if (self.order !== 0 && !$scope.isStepsLessThanFive()) {
17725 if (self.order % 2 !== 0) {
17726 $scope.expandContentForAbove(duration);
17728 $scope.expandContentForBelow(duration);
17732 this.unhoveredStateForAbove = function (duration) {
17733 $scope.unhoveredStateForAbove(duration);
17735 this.unhoveredStateForBelow = function (duration) {
17736 $scope.unhoveredStateForBelow(duration);
17738 this.shrinkAnimate = function (duration) {
17739 $scope.shrinkAnimate(duration);
17741 this.setExpanded = function () {
17744 this.isStop = function () {
17745 return $scope.isStop;
17747 this.isCancelled = function () {
17748 return ($scope.type === timelineConstants.STEP_TYPE.CANCELLED);
17750 this.isAlert = function () {
17751 return ($scope.type === timelineConstants.STEP_TYPE.ALERT);
17753 //Sets the bolded text
17754 this.isCurrentStep = function (isCurrentStep) {
17755 if (isCurrentStep !== undefined) {
17756 $scope.isCurrentStep = isCurrentStep;
17758 return $scope.isCurrentStep;
17761 .directive('timelineDot', ['animation', 'timelineConstants',
17762 function (animation, timelineConstants) {
17774 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineDot.html',
17775 require: ['^attTimeline', 'timelineDot'],
17776 controller: 'TimelineDotCtrl',
17777 link: function (scope, element, attrs, ctrls) {
17778 var attTimelineCtrl = ctrls[0];
17779 var timelineDotCtrl = ctrls[1];
17780 attTimelineCtrl.addTimelineDotCtrls(timelineDotCtrl);
17781 scope.numSteps = attTimelineCtrl.numSteps + 1;
17782 scope.isCurrentStep = false;
17783 scope.isCompleted = false;
17784 scope.isStop = false;
17785 if (scope.type === timelineConstants.STEP_TYPE.ALERT || scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
17786 scope.isStop = true;
17788 scope.isInactive = true;
17789 var divs = element.find('div');
17790 var biggerCircleElem = divs.eq(0);
17791 var expandableCircleElem = divs.eq(2);
17792 var infoboxElem = divs.eq(3);
17793 var titleElem = divs.eq(5);
17794 var contentElem = divs.eq(6);
17795 var dateElem = divs.eq(9);
17796 function isEmptyStep() {
17797 if (!scope.description && !scope.by && !scope.date) {
17802 scope.isStepsLessThanFive = function () {
17803 if (scope.numSteps < 5) {
17808 scope.titleMouseover = function (num) {
17809 if (!scope.isStepsLessThanFive() && !isEmptyStep()) {
17810 if (num === 1 && scope.order % 2 === 0) {
17811 scope.expandContentForBelow(.25);
17813 if (num === 2 && scope.order % 2 !== 0) {
17814 scope.expandContentForAbove(.25);
17818 scope.titleMouseleave = function () {
17819 if (scope.order % 2 === 0) {
17820 scope.unhoveredStateForBelow(.25);
17823 scope.unhoveredStateForAbove(.25);
17826 scope.initializeAboveForAnimation = function () {
17827 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17828 animation.set(contentElem, {opacity: 0});
17829 animation.set(dateElem, {opacity: 0});
17830 if (!isEmptyStep()) {
17831 var yOffset = contentElem[0].offsetHeight + dateElem[0].offsetHeight;
17832 animation.set(titleElem, {'top': yOffset});
17836 scope.expandContentForAbove = function (duration) {
17837 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17838 animation.to(titleElem, duration, {'top': 0});
17839 animation.to(contentElem, duration, {opacity: 1});
17840 animation.to(dateElem, duration, {opacity: 1});
17843 scope.unhoveredStateForAbove = function (duration) {
17844 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17845 animation.set(contentElem, {opacity: 0});
17846 animation.set(dateElem, {opacity: 1});
17847 var yOffset = contentElem[0].offsetHeight;
17848 animation.to(titleElem, duration, {'top': yOffset});
17851 scope.initializeBelowForAnimation = function () {
17852 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17853 animation.set(contentElem, {height: '0%', opacity: 0, top: '-20px'});
17854 animation.set(dateElem, {opacity: 0});
17857 scope.expandContentForBelow = function (duration) {
17858 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17859 animation.set(dateElem, {opacity: 1});
17860 animation.to(contentElem, duration, {height: 'auto', opacity: 1, top: '0px'});
17863 scope.unhoveredStateForBelow = function (duration) {
17864 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17865 animation.to(contentElem, duration, {height: '0%', opacity: 0, top: '-20px', position: 'relative'});
17866 animation.set(dateElem, {opacity: 1});
17869 /*Default Initializaztion*/
17870 //If the info box is above and the description and date and by are empty then we have do reset its position
17871 if (isEmptyStep() && (scope.order % 2 !== 0 && attTimelineCtrl.isAlternate())) {
17872 infoboxElem.css('top', '-47px');
17874 //Check if the order is odd and set the appropiate above or below and other effects
17875 if (scope.order % 2 === 0 || !attTimelineCtrl.isAlternate()) {
17876 scope.isBelowInfoBoxShown = true;
17879 scope.isBelowInfoBoxShown = false;
17881 //modify some css for steps less than 5 and not alternating
17882 if (scope.isStepsLessThanFive() && !attTimelineCtrl.isAlternate()) {
17883 animation.set(dateElem, {marginTop: 10});
17886 animation.set(biggerCircleElem, {opacity: '.5'});
17887 //shrink the expandableCircle to we can expand it later
17888 animation.set(expandableCircleElem, {opacity: '0.0'});
17889 animation.set(expandableCircleElem, {scale: .10});
17890 if (scope.order === 0) {
17891 animation.set(expandableCircleElem, {opacity: '1.0'});
17892 animation.set(expandableCircleElem, {scale: 1});
17893 animation.set(biggerCircleElem, {scale: 3});
17894 scope.isCurrentStep = true;
17895 scope.isInactive = false;
17896 scope.isCompleted = true;
17898 scope.setColor = function () {
17899 scope.isInactive = false;
17900 if (scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
17901 scope.isCancelled = true;
17903 else if (scope.type === timelineConstants.STEP_TYPE.ALERT) {
17904 scope.isAlert = true;
17907 scope.isCompleted = true;
17909 if (!scope.$phase) {
17913 scope.setSize = function (size) {
17914 animation.set(biggerCircle, {scale: size});
17916 scope.setExpandedCircle = function () {
17917 animation.set(expandableCircleElem, {opacity: '1.0'});
17918 animation.set(expandableCircleElem, {scale: 1});
17920 scope.expandedAnimate = function (duration) {
17921 animation.to(biggerCircleElem, duration, {scale: 3});
17922 animation.set(expandableCircleElem, {opacity: '1.0'});
17923 animation.to(expandableCircleElem, duration, {scale: 1});
17925 scope.shrinkAnimate = function (duration) {
17926 animation.to(biggerCircleElem, duration, {scale: 1});
17931 angular.module('att.abs.table', ['att.abs.utilities'])
17932 .constant('tableConfig', {
17933 //true for descending & false for ascending
17934 defaultSortPattern: false,
17935 highlightSearchStringClass: 'tablesorter-search-highlight'
17938 .directive('attTable', ['$filter', function($filter) {
17948 searchCategory: "=",
17951 require: 'attTable',
17952 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTable.html',
17953 controller: ['$scope', function($scope) {
17955 this.currentSortIndex = null;
17956 this.setIndex = function(headerScope) {
17957 this.headers.push(headerScope);
17959 this.getIndex = function(headerName) {
17960 for (var i = 0; i < this.headers.length; i++) {
17961 if (this.headers[i].headerName === headerName) {
17962 return this.headers[i].index;
17967 this.sortData = function(columnIndex, reverse) {
17968 $scope.$parent.columnIndex = columnIndex;
17969 $scope.$parent.reverse = reverse;
17970 this.currentSortIndex = columnIndex;
17971 $scope.currentPage = 1;
17972 this.resetSortPattern();
17974 this.getSearchString = function() {
17975 return $scope.searchString;
17977 this.resetSortPattern = function() {
17978 for(var i = 0; i < this.headers.length; i++) {
17979 var currentScope = this.headers[i];
17980 if(currentScope.index !== this.currentSortIndex) {
17981 currentScope.resetSortPattern();
17986 link: function(scope, elem, attr, ctrl) {
17987 scope.searchCriteria = {};
17988 scope.$watchCollection('tableData', function(value) {
17989 if(value && !isNaN(value.length)) {
17990 scope.totalRows = value.length;
17993 scope.$watch('currentPage', function(val) {
17994 scope.$parent.currentPage = val;
17996 scope.$watch('viewPerPage', function(val) {
17997 scope.$parent.viewPerPage = val;
17999 scope.$watch(function() {
18000 return scope.totalRows / scope.viewPerPage;
18001 }, function(value) {
18002 if(!isNaN(value)) {
18003 scope.totalPage = Math.ceil(value);
18004 scope.currentPage = 1;
18007 var searchValCheck = function(val){
18008 if(angular.isDefined(val) && val !== null && val !== ""){
18012 var setSearchCriteria = function(v1,v2){
18013 if(searchValCheck(v1) && searchValCheck(v2)){
18014 var index = ctrl.getIndex(v2);
18015 scope.searchCriteria = {};
18016 if (index !== null) {
18017 scope.searchCriteria[index] = v1;
18019 }else if(searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")){
18020 scope.searchCriteria = {
18024 scope.searchCriteria = {};
18027 scope.$watch('searchCategory', function(newVal,oldVal) {
18028 if(newVal !== oldVal){
18029 setSearchCriteria(scope.searchString,newVal);
18032 scope.$watch('searchString', function (newVal,oldVal) {
18033 if(newVal !== oldVal){
18034 setSearchCriteria(newVal,scope.searchCategory);
18037 scope.$watchCollection('searchCriteria', function(val) {
18038 scope.$parent.searchCriteria = val;
18039 scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;
18040 scope.currentPage = 1;
18046 .directive('attTableRow', [function() {
18049 compile: function (elem, attr) {
18050 if (attr.type === 'header') {
18051 elem.find('tr').eq(0).addClass('tablesorter-headerRow');
18052 } else if (attr.type === 'body') {
18053 var html = elem.children();
18054 if(attr.rowRepeat){
18055 if (attr.trackBy) {
18056 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1) track by " + attr.trackBy));
18058 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1) track by $index"));
18061 html.attr('ng-class', "{'alt-row': $even,'normal-row': $odd}");
18068 .directive('attTableHeader', ['tableConfig', function(tableConfig) {
18078 require: '^attTable',
18079 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableHeader.html',
18080 link: function(scope, elem, attr, ctrl) {
18081 var reverse = tableConfig.defaultSortPattern;
18082 scope.headerName = elem.text();
18083 scope.sortPattern = null;
18084 ctrl.setIndex(scope);
18086 scope.$watch(function() {
18087 return elem.text();
18088 }, function(value) {
18089 scope.headerName = value;
18091 scope.sort = function(sortType) {
18092 if(typeof sortType === 'boolean') {
18093 reverse = sortType;
18095 ctrl.sortData(scope.index, reverse);
18096 scope.sortPattern = reverse ? 'descending' : 'ascending';
18097 reverse = !reverse;
18099 scope.$watch(function() {
18100 return ctrl.currentSortIndex;
18101 }, function(value) {
18102 if (value !== scope.index) {
18103 scope.sortPattern = null;
18107 if (scope.sortable === undefined || scope.sortable === 'true' || scope.sortable === true) {
18108 scope.sortable = 'true';
18109 } else if (scope.sortable === false || scope.sortable === 'false') {
18110 scope.sortable = 'false';
18113 if(scope.sortable !== 'false') {
18114 if(scope.defaultSort === 'A' || scope.defaultSort === 'a') {
18116 } else if(scope.defaultSort === 'D' || scope.defaultSort === 'd') {
18120 scope.resetSortPattern = function() {
18121 reverse = tableConfig.defaultSortPattern;
18127 .directive('attTableBody', ['$filter', '$timeout', 'tableConfig', function($filter, $timeout, tableConfig) {
18130 require: '^attTable',
18133 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableBody.html',
18134 link: function (scope, elem, attr, ctrl) {
18135 var highlightSearchStringClass = tableConfig.highlightSearchStringClass;
18136 var searchString = "";
18137 var wrapElement = function (elem) {
18138 var text = elem.text();
18139 elem.html($filter('highlight')(text, searchString, highlightSearchStringClass));
18141 var traverse = function (elem) {
18142 var innerHtml = elem.children();
18143 if (innerHtml.length > 0) {
18144 for (var i = 0; i < innerHtml.length; i++) {
18145 traverse(innerHtml.eq(i));
18152 var clearWrap = function (elem) {
18153 var elems = elem.find('*');
18154 for (var i = 0; i < elems.length; i++) {
18155 if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
18156 var text = elems.eq(i).text();
18157 elems.eq(i).replaceWith(text);
18161 $timeout(function () {
18162 var actualHtml = elem.children();
18163 scope.$watch(function () {
18164 return ctrl.getSearchString();
18165 }, function (val) {
18166 searchString = val;
18168 if (actualHtml.length > 0) {
18179 angular.module('att.abs.tableMessages', ['att.abs.utilities'])
18180 .constant('messageConstants', {
18181 TABLE_MESSAGE_TYPES: {
18186 USER_MESSAGE_TYPES: {
18191 .directive('attTableMessage', ['messageConstants', function(messageConstants) {
18198 onRefreshClick: '&'
18200 templateUrl: 'app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html',
18201 link: function(scope) {
18202 scope.messageConstants = messageConstants;
18203 scope.refreshAction = function(evt) {
18204 scope.onRefreshClick(evt);
18208 }]).directive('attUserMessage', ['messageConstants', '$timeout', 'DOMHelper', function(messageConstants, $timeout, DOMHelper) {
18219 templateUrl: 'app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html',
18220 link: function(scope, element) {
18221 var prevActiveElement = undefined;
18222 var firstElement = undefined;
18223 scope.messageConstants = messageConstants;
18225 $timeout(function() {
18226 firstElement = DOMHelper.firstTabableElement(element[0]);
18230 scope.$watch('trigger', function() {
18231 if (scope.trigger) {
18232 prevActiveElement = document.activeElement;
18233 if (angular.isDefined(firstElement)) {
18234 firstElement.focus();
18237 if (angular.isDefined(prevActiveElement)) {
18238 prevActiveElement.focus();
18247 angular.module('att.abs.tabs', ['att.abs.utilities'])
18248 .directive('attTabs', function () {
18256 controller: ['$scope', function ($scope) {
18257 this.getData = function () {
18258 return $scope.tabs;
18260 this.onClickTab = function (tab) {
18261 $scope.currentTab = tab.url;
18262 return $scope.currentTab;
18264 this.isActiveTab = function (tab) {
18265 return (tab === $scope.currentTab);
18268 link: function (scope) {
18269 for (var i = 0; i < scope.tabs.length; i++) {
18270 if ((scope.tabs[i].selected) && (scope.tabs[i].url)) {
18271 scope.currentTab = scope.tabs[i].url;
18277 .directive('floatingTabs', function () {
18279 require: '^attTabs',
18286 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/floatingTabs.html',
18287 link: function (scope, elem, attr, attTabsCtrl) {
18288 scope.tabs = attTabsCtrl.getData();
18289 scope.onClickTab = attTabsCtrl.onClickTab;
18290 scope.isActiveTab = attTabsCtrl.isActiveTab;
18294 .directive('simplifiedTabs', function () {
18296 require: '^attTabs',
18303 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html',
18304 link: function (scope, elem, attr, attTabsCtrl) {
18305 scope.tabs = attTabsCtrl.getData();
18306 scope.clickTab = function (tab) {
18307 scope.ctab = tab.id;
18310 scope.isActive = function (tab) {
18311 return (tab === scope.ctab);
18316 .directive('genericTabs', function () {
18318 require: '^attTabs',
18325 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/genericTabs.html',
18326 link: function (scope, elem, attr, attTabsCtrl) {
18327 scope.tabs = attTabsCtrl.getData();
18328 scope.clickTab = function (tab) {
18329 scope.ctab = tab.id;
18332 scope.isActive = function (tab) {
18333 return (tab === scope.ctab);
18338 .directive('skipNavigation', function(){
18340 link: function(scope,elem,attr){
18341 elem.bind('click', function(){
18342 var skiptoBody = angular.element(elem.parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18343 (angular.element(skiptoBody)).attr('tabindex',-1);
18344 skiptoBody.focus();
18350 .directive('parentTab', [function () {
18355 activeSubMenu: '=',
18358 controller: ['$scope', function ($scope) {
18359 $scope.megaMenu = $scope.menuItems;
18360 $scope.megaMenuTab;
18361 $scope.megaMenuHoverTab;
18362 this.setMenu = function () {
18363 $scope.menuItems = $scope.megaMenu;
18364 $scope.activeSubMenu.scroll=false;
18365 for (var i = 0; i < $scope.menuItems.length; i++) {
18366 if ($scope.menuItems[i].active) {
18367 $scope.activeMenu = $scope.menuItems[i];
18370 this.setSubMenuStatus(false);
18373 this.setActiveMenu = function () {
18374 if (!($scope.megaMenuTab === undefined || $scope.megaMenuTab === null)) {
18375 $scope.menuItems = [$scope.megaMenuTab];
18376 $scope.megaMenuTab.scroll = true;
18377 $scope.activeMenu = {};
18378 $scope.activeSubMenu = $scope.megaMenuTab;
18379 this.setSubMenuStatus(true);
18382 for(var i=0; i<$scope.menuItems.length; i++){
18383 ($scope.menuItems[i].active = false);
18384 if($scope.menuItems[i].subItems)
18385 for(var j=0; j<$scope.menuItems[i].subItems.length; j++){
18386 $scope.menuItems[i].subItems[j].active = false;
18389 $scope.menuItems=$scope.megaMenu;
18393 var checkSubMenuStatus = false;
18394 this.setSubMenuStatus = function (value) {
18395 checkSubMenuStatus = value;
18397 this.getSubMenuStatus = function () {
18398 return checkSubMenuStatus;
18400 this.setActiveMenuTab = function (tab) {
18401 $scope.megaMenuTab = tab;
18403 this.setActiveMenuHoverTab = function (tab) {
18404 $scope.megaMenuHoverTab = tab;
18406 this.setActiveSubMenuTab = function () {
18407 $scope.megaMenuTab = $scope.megaMenuHoverTab;
18409 this.resetMenuTab = function () {
18410 $scope.megaMenuTab = undefined;
18412 this.clearSubMenu = function () {
18413 /* Clears Sub-tems when focus shifts from Sub-menu to Mega menu*/
18414 $scope.$evalAsync(function(){
18415 $scope.megaMenuTab = undefined;
18416 $scope.megaMenuHoverTab = undefined;
18422 .directive('parentmenuTabs', [function () {
18431 controller: ['$scope', function ($scope) {
18432 this.getMenu = function () {
18433 return $scope.menuItems;
18435 this.setMenu = function (menuItem) {
18436 $scope.menuItems = menuItem;
18439 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html'
18443 .directive('menuTabs', ["$window", "$document",'events','keymap', function (win, $document, events, keymap) {
18448 require: ['^?parentTab', '^?parentmenuTabs'],
18453 subItemActive: "@",
18457 templateUrl: function (element, attrs) {
18458 if (attrs.megaMenu) {
18459 return 'app/scripts/ng_js_att_tpls/tabs/menuTab.html';
18462 return 'app/scripts/ng_js_att_tpls/tabs/submenuTab.html';
18465 link: function (scope, elem, attr, ctrl) {
18466 var parentCtrl = ctrl[0];
18467 var parentmenuCtrl = ctrl[1];
18468 scope.clickInactive = true;
18469 scope.showHoverChild = function (e) {
18470 scope.clickInactive = false;
18471 scope.hoverChild = ctrl[0].getSubMenuStatus();
18472 if (e.type === "mouseover" && ctrl[0].getSubMenuStatus())
18474 //scope.showChildren(e);
18478 scope.showChildren = function (e) {
18479 scope.parentMenuItems = parentmenuCtrl.getMenu();
18480 for (var i = 0; i < scope.parentMenuItems.length; i++) {
18481 scope.parentMenuItems[i].active = false;
18482 if (scope.parentMenuItems[i].subItems) {
18483 for (var j = 0; j < scope.parentMenuItems[i].subItems.length; j++) {
18484 scope.parentMenuItems[i].subItems[j].active = false;
18487 scope.clickInactive = true;
18489 scope.menuItem.active = true;
18490 scope.activeMenu = scope.menuItem;
18491 e.stopPropagation();
18493 scope.$watch("subItemActive", function (value) {
18494 if (value === "true" && scope.subMenu === 'true') {
18495 parentCtrl.setActiveMenuHoverTab(scope.menuItem);
18498 scope.showMenuClick = function (e) {
18499 parentCtrl.setActiveMenuTab(scope.menuItem);
18500 e.stopPropagation();
18502 scope.showSubMenuClick = function (e) {
18503 parentCtrl.setActiveSubMenuTab();
18504 e.stopPropagation();
18506 scope.resetMenu = function (e) {
18507 parentCtrl.resetMenuTab();
18508 e.stopPropagation();
18510 function debounce(method, delay) {
18511 clearTimeout(method._tId);
18512 method._tId = setTimeout(function () {
18513 parentCtrl.setMenu();
18516 function debounce1(method, delay) {
18517 clearTimeout(method._tId);
18518 method._tId = setTimeout(function () {
18519 parentCtrl.setActiveMenu();
18522 $document.bind('scroll', function () {
18523 /* if (win.pageYOffset === 0) {
18524 debounce(parentCtrl.setMenu, 100);
18526 else if (win.pageYOffset > 1 && win.pageYOffset < 1500) {
18527 debounce1(parentCtrl.setActiveMenu, 100);
18530 elem.bind('keydown', function(evt){
18531 if (!(evt.keyCode)){
18532 evt.keyCode = evt.which;
18534 if(evt.keyCode !== keymap.KEY.TAB){
18535 events.preventDefault(evt);
18536 events.stopPropagation(evt);
18539 switch (evt.keyCode) {
18540 case keymap.KEY.ESC:
18542 if (!(elem.attr('mega-menu'))) {
18543 if (elem.attr("sub-menu") === "true") {
18544 /* condition true when user navigates through Sub-menu*/
18546 skiptoBody = angular.element(elem.parent().parent().parent().parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18547 (angular.element(skiptoBody)).attr('tabindex',-1);
18548 skiptoBody.focus();
18550 else if (elem.attr("sub-menu") === undefined) {
18551 skiptoBody = angular.element(elem.parent().parent().parent().parent().parent().parent().parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18552 (angular.element(skiptoBody)).attr('tabindex',-1);
18553 skiptoBody.focus();
18558 if (elem.attr("menu-item") === "item") {
18559 /* Works when user on Mega menu*/
18561 skiptoBody = angular.element(elem.parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18562 (angular.element(skiptoBody)).attr('tabindex',-1);
18563 skiptoBody.focus();
18567 case keymap.KEY.RIGHT:
18568 if (!(elem.attr('mega-menu'))) {
18569 var el = angular.element(elem)[0];
18570 if (elem.attr("sub-menu") === "true") {
18571 /* condition true when user navigates through Sub-menu*/
18572 if(el.nextElementSibling === null){ break;}
18573 if(el.nextElementSibling){
18574 el.nextElementSibling.querySelector("a").focus();
18578 if (el && el.nextSibling){
18579 el = el.nextSibling;
18584 } while (el && el.tagName !== 'LI');
18586 if (el.querySelector("a") == null){}
18588 el.querySelector("a").focus();}
18590 events.preventDefault(evt);
18591 events.stopPropagation(evt);
18594 else if (elem.attr("sub-menu") === undefined) {
18595 if(el.nextElementSibling === null) break;
18596 if(el.nextElementSibling){
18597 el.nextElementSibling.querySelector("a").focus();
18601 if (el && el.nextSibling){
18602 el = el.nextSibling;
18607 } while (el && el.tagName !== 'LI');
18609 if (el.querySelector("a") == null){}
18611 el.querySelector("a").focus();}
18619 if (elem.attr("menu-item") === "item") {
18620 /* When user navigates through on Mega menu*/
18622 var el = angular.element(elem)[0];
18624 if(el.nextElementSibling){
18625 if(el.nextElementSibling.querySelector("span") == null){
18628 el.nextElementSibling.querySelector("span").focus();
18633 if (el && el.nextSibling){
18634 el = el.nextSibling;
18639 } while (el && el.tagName !== 'LI');
18641 if(el.querySelector("span") === null){}
18643 el.querySelector("span").focus();
18646 events.preventDefault(evt);
18647 events.stopPropagation(evt);
18652 case keymap.KEY.DOWN:
18655 if (elem.attr('mega-menu')) {
18656 /* When user navigates from top menu to Sub-menu*/
18657 angular.element(elem)[0].querySelectorAll(".megamenu__items")[0].querySelector("a").focus();
18659 else if(elem.attr("sub-menu") === undefined) {
18660 /*When user navigates within Sub Items*/
18661 var el = document.activeElement;
18662 if(el.nextElementSibling === null) break;
18663 if(el.nextElementSibling) {
18664 el.nextElementSibling.focus();
18667 if (el && el.nextSibling){
18668 el = el.nextSibling;
18673 } while (el && el.tagName !== 'A');
18674 if(el.attributes !== null){
18677 events.stopPropagation(evt);
18681 else if (elem.attr("sub-menu")=== "true" ) {
18682 /* condition true when user navigates from sub menu to Sub Item*/
18683 var childItems = angular.element(elem)[0].querySelector("span").querySelector('a');
18684 if(childItems === null) break;
18685 childItems.focus();
18689 case keymap.KEY.LEFT:
18691 if (!(elem.attr('mega-menu'))) {
18692 var el = angular.element(elem)[0];
18693 if (elem.attr("sub-menu") === "true") {
18694 /* condition true when user navigates through Sub-menu*/
18695 if(el.previousElementSibling === null) break;
18696 if(el.previousElementSibling){
18697 el.previousElementSibling.querySelector("a").focus();
18701 if (el && el.previousSibling){
18702 el = el.previousSibling;
18707 } while (el && el.tagName !== 'LI');
18709 if (el.querySelector("a") == null){}
18711 el.querySelector("a").focus();}
18713 events.preventDefault(evt);
18714 events.stopPropagation(evt);
18717 /*el.previousElementSibling.querySelector("span").focus();
18718 events.stopPropagation(evt);
18721 else if (elem.attr("sub-menu") === undefined) {
18722 if(el.previousElementSibling === null) break;
18723 if(el.previousElementSibling){
18724 el.previousElementSibling.querySelector("a").focus();
18728 if (el && el.previousSibling){
18729 el = el.previousSibling;
18734 } while (el && el.tagName !== 'LI');
18736 if (el.querySelector("a") == null){}
18738 el.querySelector("a").focus();}
18745 if (elem.attr("menu-item") === "item") {
18746 /* Works when user on Mega menu*/
18748 var el = angular.element(elem)[0];
18749 if(el.previousElementSibling){
18751 if(el.previousElementSibling.querySelector("span") === null){
18754 el.previousElementSibling.querySelector("span").focus();
18760 if (el && el.previousSibling){
18761 el = el.previousSibling;
18766 } while (el && el.tagName !== 'LI');
18768 if (el.querySelector("span") === null) {
18771 el.querySelector("span").focus();
18774 events.preventDefault(evt);
18775 events.stopPropagation(evt);
18780 case keymap.KEY.UP:
18782 if (elem.attr("sub-menu") === "true") {
18783 var el = document.activeElement;
18784 var parent_menu = angular.element(elem.parent().parent().parent().parent())[0].querySelector("span");
18785 parent_menu.focus();
18786 parentCtrl.clearSubMenu();
18787 scope.menuItem.active = false;
18790 else if(elem.attr("sub-menu") === undefined) {
18791 /* condition true when user navigates within Sub Items*/
18792 var el = document.activeElement;
18793 var parent_menu = angular.element(elem.parent().parent().parent().parent())[0].querySelector("a");
18794 if(document.activeElement === angular.element(el).parent().parent()[0].querySelectorAll('a')[0]){
18795 parent_menu.focus();
18799 if(el.previousElementSibling) {
18800 var prev_a = el.previousElementSibling;
18801 (el.previousElementSibling != null)? el.previousElementSibling.focus(): parent_menu.focus();
18804 if (el && el.previousSibling){
18805 el = el.previousSibling;
18810 } while (el && el.tagName !== 'A');
18811 if(el && (el.nodeType !== 3)){
18814 events.preventDefault(evt);
18815 events.stopPropagation(evt);
18828 angular.module('att.abs.tagBadges', [])
18829 .directive('tagBadges', ['$parse', '$timeout', function($parse, $timeout) {
18834 templateUrl: 'app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html',
18839 link: function(scope, elem, attr) {
18840 scope.isSmall = false;
18841 scope.isIcon = false;
18842 scope.isColor = false;
18843 scope.display = true;
18844 scope.isClosable = false;
18845 scope.isHighlight = false;
18846 scope.customColor = false;
18848 if (attr.small === "") {
18849 scope.isSmall = true;
18851 if (scope.styleType === "icon") {
18852 scope.isIcon = true;
18854 else if (scope.styleType === "color") {
18855 scope.isColor = true;
18856 if(attr.color !== undefined && attr.color !== "") {
18857 scope.customColor = true;
18858 attr.$observe("color", function(val) {
18859 scope.border_type_borderColor = val;
18860 scope.background_type_backgroundColor = val;
18861 scope.background_type_borderColor = val;
18865 scope.activeHighlight = function(state){
18866 if(scope.customColor){
18868 scope.isHighlight = true;
18871 scope.isHighlight = false;
18875 if (attr.closable === "") {
18876 scope.isClosable = true;
18877 scope.closeMe = function() {
18878 scope.display = false;
18879 $timeout(function(){
18880 elem.attr("tabindex", "0");
18882 elem.bind('blur', function(){
18886 if(attr['onClose']){
18887 scope.onClose = $parse(scope.onClose);
18895 angular.module('att.abs.textOverflow', [])
18896 .constant('textDefaultOptions', {
18899 .directive('attTextOverflow', ['textDefaultOptions','$compile',function(textDefaultOptions,$compile)
18903 link: function(scope, elem, attrs)
18905 var tooltipText = elem.text();
18906 elem.addClass('text-ellipsis');
18907 attrs.$observe('attTextOverflow', function(val){
18909 elem.css({"width":val});
18912 elem.css({"width":textDefaultOptions.width});
18915 if(!(elem.attr('tooltip'))){
18916 elem.attr("tooltip", tooltipText);
18917 elem.attr("tooltip-placement", 'above');
18918 var newElem = angular.element(elem);
18919 $compile(newElem)(scope);
18925 angular.module('att.abs.toggle', ['angular-gestures', 'att.abs.position'])
18926 .directive('attToggleTemplate', ['$compile', '$log', '$position', function ($compile, $log, $position)
18930 require: 'ngModel',
18933 modelVal: "=ngModel"
18935 templateUrl: 'app/scripts/ng_js_att_tpls/toggle/demoToggle.html',
18936 link: function (scope, element, attr) {
18937 scope.initialDragPosition = 0;
18938 var dragStatus = 0;
18939 var switchMovementPath = ($position.offset(element.children().eq(1).children().eq(0)).width - 1);
18940 var updateModelVal = function () {
18941 if (scope.attrValue === attr.ngTrueValue || scope.attrValue)
18943 scope.modelVal = false;
18947 scope.modelVal = true;
18950 scope.updateModel = function (env) {
18952 if (dragStatus !== 1) {
18957 env.preventDefault();
18959 scope.drag = function (e) {
18961 if (e.type === 'dragstart') {
18962 scope.initialDragPosition = $position.position(element.children().eq(1)).left;
18963 element.children().eq(1).addClass('dragging');
18964 } else if (e.type === 'drag') {
18965 var left = Math.min(0, Math.max(scope.initialDragPosition + e.gesture.deltaX, -switchMovementPath));
18966 element.children().eq(1).css({
18969 } else if (e.type === 'dragend') {
18970 var isOn = $position.position(element.children().eq(1)).left > (switchMovementPath * -1) / 2;
18971 element.children().eq(1).removeClass('dragging');
18972 TweenMax.to(element.children().eq(1), .1, {left: isOn ? 0 : (switchMovementPath * -1), ease: Power4.easeOut,
18973 onComplete: function () {
18974 element.children().eq(1).css({left: ''});
18976 if (isOn || (!isOn && e.gesture.direction === "left")) {
18985 scope.directiveValue = attr.attToggleTemplate;
18986 scope.on = attr.trueValue;
18987 scope.off = attr.falseValue;
18988 var switchMovementPathPixels = ((switchMovementPath) * -1) + 'px';
18989 scope.$watch('modelVal', function (newVal) {
18990 scope.attrValue = newVal;
18991 if (newVal === attr.ngTrueValue || newVal) {
18992 element.children().eq(1).css({
18995 element.addClass('att-checkbox--on');
18996 var elem = element.find('div').find('div').eq(1);
18997 elem.attr("aria-checked", true);
19000 element.children().eq(1).css({
19001 left: switchMovementPathPixels
19003 element.removeClass('att-checkbox--on');
19004 var elem = element.find('div').find('div').eq(1);
19005 elem.attr("aria-checked", false);
19008 element.children().eq(1).css({
19017 .directive('attToggleMain', ['$compile', function ($compile)
19021 require: 'ngModel',
19025 modelValue: "=ngModel",
19026 trueValue: "=ngTrueValue",
19027 falseValue: "=ngFalseValue"
19029 link: function (scope, element, attr) {
19032 element.removeAttr('att-toggle-main');
19033 scope.on = attr.ngTrueValue;
19034 scope.off = attr.ngFalseValue;
19035 scope.largeValue = attr.attToggleMain;
19036 if (angular.isDefined(attr.ngTrueValue)) {
19037 html += ' true-value="{{on}}" false-value="{{off}}"';
19039 if (scope.largeValue !== undefined)
19041 attrVal += ' ="{{largeValue}}"';
19044 element.css({display: 'none'});
19045 var elm = angular.element('<div class="att-switch att-switch-alt" ng-class="{\'large\' : largeValue == \'large\'}" ng-model="modelValue"' + html + ' att-toggle-template' + attrVal + '>' + element.prop('outerHTML') + '</div>');
19046 elm = $compile(elm)(scope);
19047 element.replaceWith(elm);
19051 angular.module('att.abs.treeview', [])
19052 .directive('treeView', function() {
19055 link: function(scope, elem) {
19056 var el = elem.children('ul li');
19057 var list = TweenMax.from(el, .2, {display: 'none', paused: true, reversed: true});
19058 elem.attr("tabindex","0");
19059 function toggleBranch() {
19060 if (list.reversed())
19068 function toggleTree(e) {
19069 e.stopPropagation();
19070 if (angular.element(e.target).attr("tree-view") !== undefined)
19072 if (elem.hasClass('minus'))
19074 elem.removeClass('minus');
19078 elem.addClass('minus');
19083 elem.on('click', function(e) {
19086 elem.on('keypress', function (e) {
19087 var activeCode = e.keyCode ? e.keyCode : e.charCode;
19088 var keyCode = [13,32];
19089 if (keyCode.length > 0 && ((activeCode && keyCode.indexOf(activeCode) > -1))) {
19091 e.preventDefault();
19098 angular.module('att.abs.typeAhead', ['att.abs.tagBadges'])
19100 .directive('focusMe',['$timeout', '$parse', function($timeout, $parse) {
19102 link: function(scope, element, attrs) {
19103 var model = $parse(attrs.focusMe);
19104 scope.$watch(model, function(value) {
19106 $timeout(function() {
19107 element[0].focus();
19108 scope.inputActive=true;
19112 element.bind('blur', function() {
19113 model.assign(scope, false);
19114 scope.inputActive=false;
19121 .directive('typeAhead', ['$timeout','$log', function($timeout,$log) {
19124 templateUrl: 'app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html',
19135 link: function(scope, elem) {
19136 if(!angular.isDefined(scope.titleName) && angular.isDefined(scope.title)){
19137 $timeout(function(){
19138 scope.titleName = scope.title;
19139 $log.warn("title attribute is deprecated and title-name attribute is used instead as it is conflicting with html title attribute");
19142 scope.lineItems = [];
19143 scope.filteredListLength = -1;
19144 scope.filteredList = [];
19145 scope.setFocus = function() {
19146 scope.clickFocus = true;
19149 scope.handleSelection = function(selectedItem,emailItem) {
19150 scope.lineItems.push(selectedItem);
19151 scope.emailIdList.push(emailItem);
19154 scope.selected = true;
19155 scope.clickFocus = true;
19157 scope.theMethodToBeCalled = function(index) {
19158 var tempArr = scope.lineItems.slice();
19159 scope.emailIdList.splice(index, 1);
19160 tempArr.splice(index, 1);
19161 $timeout(function() {
19162 scope.lineItems = [];
19164 scope.lineItems = scope.lineItems.concat(tempArr);
19169 scope.selected = true;
19171 scope.isCurrent = function(index, itemName,itemEmail,dropdownLength) {
19172 if (scope.current === index) {
19173 scope.itemName = itemName;
19174 scope.itemEmail = itemEmail;
19176 scope.dropdownLength=dropdownLength;
19177 return scope.current === index;
19180 scope.setCurrent = function(index) {
19181 scope.current = index;
19184 scope.selectionIndex = function(evt) {
19185 if (evt.keyCode === 38 && scope.current > 0) {
19186 evt.preventDefault();
19187 scope.current = scope.current - 1;
19188 scope.isCurrent(scope.current);
19189 } else if (evt.keyCode === 9) {
19190 scope.selected = true;
19191 } else if (evt.keyCode === 13 && scope.dropdownLength!==scope.items.length) {
19192 scope.handleSelection(scope.itemName,scope.itemEmail);
19193 } else if ((evt.keyCode === 8 && scope.model.length === 0) || evt.keyCode === 46) {
19194 scope.theMethodToBeCalled(scope.lineItems.length - 1);
19195 } else if (evt.keyCode === 40 && scope.current < scope.dropdownLength-1) {
19196 evt.preventDefault();
19197 scope.current = scope.current + 1;
19198 scope.isCurrent(scope.current);
19200 elem[0].querySelector('.list-scrollable').scrollTop = (scope.current - 1) * 35;
19205 angular.module('att.abs.verticalSteptracker', ['ngSanitize'])
19206 .directive('verticalSteptracker', [ function(){
19212 template: '<div class="vertical-nav"><ul ng-transclude arial-label="step list" role="presentation" class="tickets-list-height"></ul></div>',
19213 link: function () {}
19216 .directive('verticalSteptrackerStep',[ function(){
19225 templateUrl: 'app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html',
19229 .directive('attAbsLink',[ function(){
19234 template: '<span ng-transclude class="view-log"></span>'
19237 angular.module('att.abs.videoControls', [])
19238 .config(['$compileProvider' , function ($compileProvider) {
19239 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|javascript):/);
19241 .directive('videoControls', [function() {
19246 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/videoControls.html'
19249 .directive('photoControls', [function() {
19254 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/photoControls.html',
19259 link: function(scope, elem, attr) {
19260 if(!attr['prevLink']){
19261 scope.prevLink = 'javascript:void(0)';
19263 if(!attr['nextLink']){
19264 scope.nextLink = 'javascript:void(0)';
19267 prevLink : scope.prevLink,
19268 nextLink : scope.nextLink
19273 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
19274 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion.html",
19275 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
19276 " <a ng-show=\"showicon\" \n" +
19277 " class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\" \n" +
19278 " aria-selected=\"{{focused}}\" \n" +
19279 " aria-controls=\"panel{{index}}\" \n" +
19280 " aria-expanded=\"{{isOpen}}\" \n" +
19281 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19282 " role=\"tab\" \n" +
19283 " ng-click=\"toggle()\" \n" +
19284 " accordion-transclude=\"heading\" \n" +
19285 " style=\"cursor:pointer; text-decoration:none\">\n" +
19286 " <span href=\"#\"><i class={{headingIconClass}}></i> {{heading}}</span>\n" +
19287 " <i i ng-show = 'childLength > 0' ng-class=\"{'ion-ios-arrow-down':!isOpen,'ion-ios-arrow-up':isOpen }\" class=\"pull-right\"></i>\n" +
19289 " <div ng-show=\"!showicon\" \n" +
19290 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19291 " style=\"text-decoration:none\" \n" +
19292 " accordion-transclude=\"heading\" \n" +
19293 " role=\"tab\" \n" +
19294 " aria-expanded=\"{{isOpen}}\"\n" +
19295 " aria-selected=\"{{focused}}\" \n" +
19296 " aria-controls=\"panel{{index}}\" \n" +
19297 " class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\">\n" +
19298 " <span>{{heading}}</span>\n" +
19300 " <div aria-label=\"{{heading}}\" \n" +
19301 " aria-hidden=\"{{!isOpen}}\" \n" +
19302 " role=\"tabpanel\" \n" +
19303 " collapse=\"!isOpen\" \n" +
19304 " class=\"att-accordion__body\" \n" +
19305 " id=\"panel{{index}}\" \n" +
19306 " ng-transclude>\n" +
19308 " <div class=\"att-accordion__bottom--border\"></div> \n" +
19312 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html", []).run(["$templateCache", function($templateCache) {
19313 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html",
19314 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
19315 " <a class=\"toggle-header att-accordion__heading att-accordion__toggle\" \n" +
19316 " aria-selected=\"{{focused}}\" \n" +
19317 " aria-controls=\"panel{{index}}\" \n" +
19318 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19319 " aria-expanded=\"{{isOpen}}\" \n" +
19320 " role=\"tab\" \n" +
19321 " ng-click=\"toggle()\" \n" +
19322 " accordion-transclude=\"heading\"> \n" +
19324 " <span>{{heading}}</span>\n" +
19325 " <div aria-label=\"{{heading}}\" \n" +
19326 " aria-hidden=\"{{!isOpen}}\" \n" +
19327 " role=\"tabpanel\" \n" +
19328 " collapse=\"!isOpen\" \n" +
19329 " class=\"att-accordion__body\" \n" +
19330 " id=\"panel{{index}}\" \n" +
19331 " ng-transclude>\n" +
19336 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccord.html", []).run(["$templateCache", function($templateCache) {
19337 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccord.html",
19338 "<div ng-transclude></div>");
19341 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html", []).run(["$templateCache", function($templateCache) {
19342 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html",
19343 "<div ng-transclude></div>");
19346 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html", []).run(["$templateCache", function($templateCache) {
19347 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html",
19348 "<div ng-click=\"clickFunc()\">\n" +
19349 " <div ng-transclude>\n" +
19350 " <i class=\"ion-ios-arrow-down\"></i>\n" +
19355 angular.module("app/scripts/ng_js_att_tpls/alert/alert.html", []).run(["$templateCache", function($templateCache) {
19356 $templateCache.put("app/scripts/ng_js_att_tpls/alert/alert.html",
19357 "<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" +
19358 " <div class=\"container\">\n" +
19359 " <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" +
19360 " <span ng-transclude> </span>\n" +
19365 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html", []).run(["$templateCache", function($templateCache) {
19366 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html",
19367 "<div tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
19368 " <i aria-hidden=\"true\" class=\"icon-add centered\"></i>\n" +
19370 " <div class=\"centered\">Add board</div>\n" +
19374 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attBoard.html", []).run(["$templateCache", function($templateCache) {
19375 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attBoard.html",
19376 "<li att-board-navigation tabindex=\"0\" aria-label=\"{{boardLabel}}\" att-accessibility-click=\"13,32\" ng-click=\"selectBoard(boardIndex)\" class=\"board-item\" ng-class=\"{'selected': getCurrentIndex()===boardIndex}\">\n" +
19377 " <div ng-transclude></div>\n" +
19378 " <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
19379 " <div class=\"board-caret-indicator\"></div>\n" +
19380 " <div class=\"board-caret-arrow-up\"></div>\n" +
19385 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html", []).run(["$templateCache", function($templateCache) {
19386 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html",
19387 "<div class=\"att-boardstrip\">\n" +
19388 " <div class=\"boardstrip-reel\">\n" +
19389 " <div class=\"prev-items\" ng-if=\"isPrevBoard()\">\n" +
19390 " <i tabindex=\"0\" aria-label=\"Scroll Boardstrip Left\" att-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" class=\"arrow icon-arrow-left-circle\"></i>\n" +
19392 " <div att-add-board on-add-board=\"onAddBoard()\"></div>\n" +
19393 " <div class=\"board-viewport\"><ul role=\"presentation\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
19394 " <div class=\"next-items\" ng-if=\"isNextBoard()\">\n" +
19395 " <i tabindex=\"0\" aria-label=\"Scroll Boardstrip Right\" att-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" class=\"arrow icon-arrow-right-circle\"></i>\n" +
19401 angular.module("app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html", []).run(["$templateCache", function($templateCache) {
19402 $templateCache.put("app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html",
19403 "<div class=\"att-btn-dropdown\">\n" +
19404 " <div class=\"buttons-dropdown--small btn-group\" ng-class=\"{'open': isOpen}\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\">\n" +
19406 " <button role=\"menu\" class=\"button button--secondary button--small buttons-dropdown__drop dropdown-toggle\" ng-if=\"type==='dots'\" alt=\"Click for Options\" >\n" +
19408 " <div class=\"circle\"></div>\n" +
19409 " <div class=\"circle\"></div>\n" +
19410 " <div class=\"circle\"></div>\n" +
19412 " <button role=\"menu\" class=\"button button--secondary button--small buttons-dropdown__drop dropdown-toggle ng-isolate-scope actions-title\" ng-if=\"type === 'actions'\" alt=\"Actions dropdown Buttons\">Actions</button>\n" +
19415 " <ul ng-class=\"{'dropdown-menu dots-dropdwn': type==='dots', 'dropdown-menu actions-dropdwn': type === 'actions'}\" ng-transclude></ul>\n" +
19422 angular.module("app/scripts/ng_js_att_tpls/colorselector/colorselector.html", []).run(["$templateCache", function($templateCache) {
19423 $templateCache.put("app/scripts/ng_js_att_tpls/colorselector/colorselector.html",
19424 "<div class=\"att-radio att-color-selector__item\" \n" +
19425 " ng-class=\"{'att-radio--on': (iconColor === selected)}\">\n" +
19426 " <div class=\"att-radio__indicator\" tabindex=\"0\" att-accessibility-click=\"32,13\" ng-click=\"selectedcolor(iconColor)\" \n" +
19427 " ng-style=\"applycolor\" ng-transclude></div>\n" +
19431 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html", []).run(["$templateCache", function($templateCache) {
19432 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html",
19433 "<div class=\"calendar\" ng-class=\"{'monthpicker':mode === 1}\">\n" +
19434 " <div class=\"select2-container\" ng-class=\"{'select2-container-active select2-dropdown-open': showDropdownList}\" style=\"width: 100%; z-index:0\">\n" +
19435 " <a tabindex=\"0\" id=\"select2-choice\" class=\"select2-choice\" href=\"javascript:void(0)\" att-element-focus=\"focusInputButton\" ng-show=\"!showCalendar\" att-accessibility-click=\"13,32\" ng-click=\"showDropdown()\" ng-blur=\"focusInputButton=false\">\n" +
19436 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
19437 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" aria-labelledby=\"select2-choice\" ng-change=\"getDropdownText()\" />\n" +
19438 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
19439 " <span ng-class=\"{'select2-arrow': mode !== 1, 'calendar-icon': mode === 1}\"><b></b></span>\n" +
19441 " <a id=\"select2-chosen\" class=\"select2-choice\" href=\"javascript:void(0)\" ng-show=\"showCalendar\">\n" +
19442 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
19443 " <input type=\"text\" ng-show=\"showCalendar\" ng-blur=\"untrackInputChange($event)\" att-input-deny=\"[^0-9\\/-]\" maxlength=\"{{maxLength}}\" ng-model=\"selectedOption\" aria-labelledby=\"select2-chosen\" ng-change=\"getDropdownText()\" />\n" +
19444 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
19445 " <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" +
19448 " <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" +
19449 " <div id=\"dateFilterList\" att-scrollbar ><ul class=\"select2-results options\" ng-transclude></ul></div>\n" +
19450 " <ul class=\"select2-results sttings\" style=\"margin-top:0px\">\n" +
19451 " <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" +
19452 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Single Date...</div>\n" +
19453 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom single month...</div>\n" +
19455 " <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" +
19456 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Range...</div>\n" +
19457 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom month range...</div>\n" +
19459 " <li class=\"select2-result select2-highlighted btnContainer\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
19460 " <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" +
19461 " <button tabindex=\"0\" att-button=\"\" btn-type=\"secondary\" size=\"small\" att-accessibility-click=\"13,32\" ng-click=\"cancel()\">Cancel</button>\n" +
19463 " <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" +
19464 " <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" +
19469 " <div class=\"datepicker-wrapper show-right\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
19470 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusSingleDateCalendar\" ng-show=\"checkCurrentSelection('Custom Single Date')\"></span>\n" +
19471 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusRangeCalendar\" ng-show=\"checkCurrentSelection('Custom Range')\"></span>\n" +
19477 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html", []).run(["$templateCache", function($templateCache) {
19478 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html",
19479 "<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" +
19480 " <div class=\"select2-result-label\" ng-class=\"{'disabled':disabled}\" ng-transclude></div>\n" +
19484 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
19485 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepicker.html",
19486 "<div id=\"datepicker\" class=\"datepicker\" ng-class=\"{'monthpicker': mode === 1}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\" aria-labelledby=\"datepicker\">\n" +
19487 " <div class=\"datepicker-days\" style=\"display: block;\">\n" +
19488 " <table class=\"table-condensed\">\n" +
19491 " <th id=\"month\" tabindex=\"0\" class=\"datepicker-switch\" colspan=\"{{(mode !== 1) && (currentRows[0].length - 2) || (currentRows[0].length)}}\" style=\"text-align:left\">{{currentTitle}}</th>\n" +
19492 " <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" +
19493 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-left-circle\" ng-class=\"{'disabled': disablePrev}\" alt=\"Left Arrow\"></i>\n" +
19494 " </div><span class=\"hidden-spoken\">Previous Month</span>\n" +
19496 " <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" +
19497 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-right-circle\" ng-class=\"{'disabled': disableNext}\" alt=\"Right Arrow\"></i>\n" +
19498 " </div><span class=\"hidden-spoken\">Next Month</span>\n" +
19501 " <tr ng-if=\"labels.length > 0\">\n" +
19502 " <th tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"><span>{{label.pre}}</span></th>\n" +
19507 " <td id=\"datepickerBody\" att-scrollbar colspan=\"{{currentRows[0].length}}\" style=\"padding: 0px;\" headers=\"\">\n" +
19508 " <table ng-class=\"{'table-condensed': mode === 0, 'monthtable-condensed': mode === 1}\" style=\"padding: 0px;\">\n" +
19509 " <thead class=\"hidden-spoken\">\n" +
19510 " <tr ng-show=\"labels.length > 0\">\n" +
19511 " <th id=\"{{label.post}}\" tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"></th>\n" +
19515 " <tr ng-repeat=\"row in currentRows\">\n" +
19516 " <td headers=\"{{(mode === 0) && dt.header || 'month'}}\" 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\" aria-label=\"{{dt.date | date : 'EEEE, MMMM d'}}\"><span class=\"day\">{{dt.label}}</span></td>\n" +
19518 " <tr ng-if=\"mode === 1\" class=\"divider\"><td colspan=\"{{nextRows[0].length}}\"><hr></td></tr>\n" +
19520 " <th id=\"month\" tabindex=\"0\" class=\"datepicker-switch internal\" colspan=\"{{nextRows[0].length}}\" style=\"text-align:left\">{{nextTitle}}</th>\n" +
19522 " <tr ng-repeat=\"row in nextRows\">\n" +
19523 " <td headers=\"{{(mode === 0) && dt.header || 'month'}}\" 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\" aria-label=\"{{dt.date | date : 'EEEE, MMMM d'}}\"><span class=\"day\">{{dt.label}}</span></td>\n" +
19536 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html", []).run(["$templateCache", function($templateCache) {
19537 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html",
19538 "<div class=\"calendar\">\n" +
19539 " <div class=\"box\" ng-class=\"{'active': isOpen}\">\n" +
19540 " <span ng-transclude></span>\n" +
19541 " <i class=\"calendar-icon\" tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\" alt=\"Calendar Icon\"></i>\n" +
19543 " <div class=\"datepicker-wrapper datepicker-wrapper-display-none\" ng-style=\"{display: (isOpen && 'block') || 'none'}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
19544 " <span datepicker></span>\n" +
19550 angular.module("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html", []).run(["$templateCache", function($templateCache) {
19551 $templateCache.put("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html",
19552 "<div class=\"divider-container\" ng-class=\"{'divider-container-light': lightContainer}\">\n" +
19553 " <hr ng-class=\"{'divider-light': lightContainer}\">\n" +
19559 angular.module("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html", []).run(["$templateCache", function($templateCache) {
19560 $templateCache.put("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html",
19561 "<label class=\"fileContainer\"><span ng-transclude></span><input type=\"file\" att-file-change></label>");
19564 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html", []).run(["$templateCache", function($templateCache) {
19565 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html",
19566 "<div class=\"form-field\" ng-class=\"{'error': errorMessage, 'warning': warningMessage}\">\n" +
19567 " <label class=\"form-field__label\" ng-class=\"{'form-field__label--show': showLabel, 'form-field__label--hide': hideLabel}\"></label>\n" +
19568 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
19572 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html", []).run(["$templateCache", function($templateCache) {
19573 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html",
19574 "<div class=\"form-field\" ng-class=\"{'error':hideErrorMsg}\">\n" +
19575 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
19576 " <div class=\"form-field__message error\" type=\"error\" ng-show=\"hideErrorMsg\" >\n" +
19577 " <i class=\"icon-info-alert\"></i>{{errorMessage}}\n" +
19583 angular.module("app/scripts/ng_js_att_tpls/formField/creditCardImage.html", []).run(["$templateCache", function($templateCache) {
19584 $templateCache.put("app/scripts/ng_js_att_tpls/formField/creditCardImage.html",
19585 "<span class=\"css-sprite pull-right\">\n" +
19586 "<span class=\"hidden-spoken\">We accept</span>\n" +
19587 "<ul class=\"{{newValCCI}}\">\n" +
19588 " <li class=\"css-sprite-mc\"><span class=\"hidden-spoken\">MasterCard</span></li>\n" +
19589 " <li class=\"css-sprite-visa\"><span class=\"hidden-spoken\">Visa</span></li>\n" +
19590 " <li class=\"css-sprite-amex\"><span class=\"hidden-spoken\">American Express</span></li>\n" +
19591 " <li class=\"css-sprite-discover\"><span class=\"hidden-spoken\">Discover</span></li> \n" +
19594 "<label for=\"ccForm.card\" class=\"pull-left\">Card number</label>");
19597 angular.module("app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html", []).run(["$templateCache", function($templateCache) {
19598 $templateCache.put("app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html",
19600 "<button type=\"button\" class=\"btn btn-alt btn-tooltip\" style=\"padding-top:16px\" title=\"Help\"><i class=\"hidden-spoken\">Help</i></button>\n" +
19601 "<div class=\"helpertext\" role=\"tooltip\">\n" +
19602 "<div class=\"popover-title\"></div>\n" +
19603 "<div class=\"popover-content\">\n" +
19604 " <p class=\"text-legal cvc-cc\">\n" +
19605 " <img ng-src=\"images/{{newValI}}.png\" alt=\"{{newValIAlt}}\">\n" +
19613 angular.module("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html", []).run(["$templateCache", function($templateCache) {
19614 $templateCache.put("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html",
19615 "<div class=\"hourpicker\">\n" +
19616 " <div class=\"dropdown-width\">\n" +
19617 " <div ng-model=\"showlist\" class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" >\n" +
19618 " <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" +
19619 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
19620 " <span class=\"select2-arrow\"><b></b></span>\n" +
19623 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultTopWidth\" ng-show=\"showlist\"> \n" +
19624 " <ul class=\"select2-results resultTopMargin\" > \n" +
19625 " <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" +
19629 " <div ng-show=\"showDaysSelector\" class=\"customdays-width\">\n" +
19630 " <div att-divider-lines class=\"divider-margin-f\"></div> \n" +
19631 " <div class=\"col-md-3 fromto-margin\">\n" +
19632 " <div>From</div> <br>\n" +
19633 " <div>To</div>\n" +
19635 " <div ng-repeat=\"day in days\">\n" +
19636 " <div class=\"col-md-3 col-md-days\">\n" +
19637 " <div class=\"col-md-1 daysselect-margin\">\n" +
19638 " <input type=\"checkbox\" ng-model=\"daysList[day]\" title=\"Day selection {{$index}}\" att-checkbox ng-change=\"addSelectedValue(day)\"> \n" +
19640 " <span>{{day}}</span><br>\n" +
19642 " <div class=\"dropDownMarginBottom\">\n" +
19643 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': FrtimeListDay[day]}\" >\n" +
19644 " <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" +
19645 " <span class=\"select2-chosen dropDownMarginRight\" >{{selectedFromOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"FrtimeListDay[day] ? 'ion-arrow-up-b' : 'ion-arrow-down-b'\"></i></span>\n" +
19649 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultFromDropDown\" ng-show=\"FrtimeListDay[day]\"> \n" +
19650 " <ul class=\"select2-results resultTopMargin\" > \n" +
19651 " <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" +
19656 " <div class=\"dropDownMarginBottom\">\n" +
19657 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': TotimeListDay[day]}\" >\n" +
19658 " <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], 'selectDropDown-error':daysList[day] && showToTimeErrorDay[day]}\" ng-keydown=\"daysList[day] && selectToDayOption(day , selectPrevNextValue($event,totime,selectedToOption[day]));daysList[day] && addSelectedValue(day);\">\n" +
19659 " <span class=\"select2-chosen dropDownMarginRight\">{{selectedToOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"TotimeListDay[day] ? 'ion-arrow-up-b' : 'ion-arrow-down-b'\" ></i></span>\n" +
19663 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultToDropDown\" ng-show=\"TotimeListDay[day]\"> \n" +
19664 " <ul class=\"select2-results resultTopMargin\" > \n" +
19665 " <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" +
19671 " <div att-divider-lines class=\"divider-margin-s\"></div>\n" +
19673 " <div ng-transclude></div>\n" +
19677 angular.module("app/scripts/ng_js_att_tpls/links/readMore.html", []).run(["$templateCache", function($templateCache) {
19678 $templateCache.put("app/scripts/ng_js_att_tpls/links/readMore.html",
19680 " <div ng-bind-html=\"textToDisplay\" ng-class=\"{'att--readMore': readFlag, 'att--readLess': !readFlag}\" ng-style=\"readLinkStyle\"></div>\n" +
19681 " <span class=\"att--readmore__link\" ng-show=\"readMoreLink\">… <a href=\"javascript:void(0);\" ng-click=\"readMore()\" att-accessbility-click=\"32,13\">Read More</a>\n" +
19684 "<span class=\"att--readless__link\" ng-show=\"readLessLink\">\n" +
19685 " <a href=\"javascript:void(0);\" ng-click=\"readLess()\" att-accessbility-click=\"32,13\">Read Less</a>\n" +
19689 angular.module("app/scripts/ng_js_att_tpls/loading/loading.html", []).run(["$templateCache", function($templateCache) {
19690 $templateCache.put("app/scripts/ng_js_att_tpls/loading/loading.html",
19691 "<div data-progress=\"{{progressStatus}}\" class=\"{{colorClass}}\" ng-class=\"{'att-loading-count':icon == 'count','loading--small':icon == 'small','loading': icon != 'count'}\" alt=\"Loading\">\n" +
19692 " <div class=\"att-loading-circle\" ng-if=\"icon == 'count'\">\n" +
19693 " <div class=\"att-loading-circle__mask att-loading-circle__full\">\n" +
19694 " <div class=\"att-loading-circle__fill\"></div>\n" +
19696 " <div class=\"att-loading-circle__mask att-loading-circle__half\">\n" +
19697 " <div class=\"att-loading-circle__fill\"></div>\n" +
19698 " <div class=\"att-loading-circle__fill att-loading-circle__fix\"></div>\n" +
19701 " <div ng-class=\"{'att-loading-inset':icon == 'count','loading__inside':icon != 'count'}\"><div class=\"att-loading-inset__percentage\" ng-if=\"icon == 'count'\" alt=\"Loading with Count\"></div></div>\n" +
19707 angular.module("app/scripts/ng_js_att_tpls/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
19708 $templateCache.put("app/scripts/ng_js_att_tpls/modal/backdrop.html",
19709 "<div class=\"overlayed\" ng-class=\"{show: animate}\" \n" +
19710 " ng-style=\"{'z-index': 2000 + index*10,'overflow':'scroll'}\"> \n" +
19714 angular.module("app/scripts/ng_js_att_tpls/modal/tabbedItem.html", []).run(["$templateCache", function($templateCache) {
19715 $templateCache.put("app/scripts/ng_js_att_tpls/modal/tabbedItem.html",
19717 " <ul class=\"tabs_overlay\">\n" +
19718 " <li ng-repeat=\"item in items\" class=\"tabs_overlay__item two__item\" ng-class=\"{'active':isActiveTab($index)}\" ng-click=\"clickTab($index)\">\n" +
19719 " <i class=\"{{item.iconClass}}\"></i>\n" +
19720 " {{item.title}} ({{item.number}})\n" +
19721 " <a class=\"viewLink\" att-link>Show</a>\n" +
19727 angular.module("app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html", []).run(["$templateCache", function($templateCache) {
19728 $templateCache.put("app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html",
19730 " <ul class=\"tabs_overlay\">\n" +
19731 " <li ng-repeat=\"item in items\" class=\"tabs_overlay__item two__item\" ng-class=\"{'active':isActiveTab($index)}\" ng-click=\"clickTab($index)\">\n" +
19732 " <i class=\"{{item.iconClass}}\"></i>\n" +
19733 " {{item.title}} ({{item.number}})\n" +
19734 " <a class=\"viewLink\" att-link>Show</a>\n" +
19740 angular.module("app/scripts/ng_js_att_tpls/modal/window.html", []).run(["$templateCache", function($templateCache) {
19741 $templateCache.put("app/scripts/ng_js_att_tpls/modal/window.html",
19742 "<div tabindex=\"-1\" role=\"dialog\" att-element-focus=\"focusModalFlag\" class=\"modals {{ windowClass }}\" ng-class=\"{show: animate}\" \n" +
19743 " ng-style=\"{'z-index': 2010 + index*10}\" ng-click=\"close($event)\" ng-transclude> \n" +
19748 angular.module("app/scripts/ng_js_att_tpls/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
19749 $templateCache.put("app/scripts/ng_js_att_tpls/pagination/pagination.html",
19750 "<div class=\"pager\">\n" +
19751 " <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" +
19752 " <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" +
19753 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage > 3\">...</span>\n" +
19754 " <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" +
19755 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage < totalPages - 2 && showInput !== true\">...</span>\n" +
19756 " <span ng-show=\"totalPages > 7 && showInput === true\"><input class=\"pager__item--input\" type=\"text\" placeholder=\"...\" maxlength=\"2\" ng-model=\"currentPage\" aria-label=\"Current page count\"/></span>\n" +
19757 " <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" +
19758 " <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" +
19762 angular.module("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html", []).run(["$templateCache", function($templateCache) {
19763 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html",
19764 "<div class='inner-pane' ng-transclude></div>");
19767 angular.module("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html", []).run(["$templateCache", function($templateCache) {
19768 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html",
19769 "<div class='pane-group' ng-transclude></div>");
19772 angular.module("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html", []).run(["$templateCache", function($templateCache) {
19773 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html",
19774 "<div class='side-pane' ng-transclude></div>");
19777 angular.module("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
19778 $templateCache.put("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html",
19779 "<div class=\"att-tooltip \" \n" +
19780 " ng-class=\"{ 'att-tooltip--on': isOpen, \n" +
19781 " 'att-tooltip--dark att-tooltip--dark--hover':stylett=='dark', \n" +
19782 " 'att-tooltip--light att-tooltip--light--hover':stylett=='light',\n" +
19783 " 'att-tooltip--left':placement=='left', \n" +
19784 " 'att-tooltip--above':placement=='above', \n" +
19785 " 'att-tooltip--right':placement=='right', \n" +
19786 " 'att-tooltip--below':placement=='below'}\" \n" +
19787 " ng-bind-html=\"content | unsafe\" ></div>");
19790 angular.module("app/scripts/ng_js_att_tpls/popOvers/popOvers.html", []).run(["$templateCache", function($templateCache) {
19791 $templateCache.put("app/scripts/ng_js_att_tpls/popOvers/popOvers.html",
19792 "<div class=\"att-popover popover-demo\" ng-style=\"{backgroundColor:popOverStyle}\"\n" +
19793 " ng-class=\"{'att-tooltip--dark':popOverStyle==='grey',\n" +
19794 " 'att-pop-over--left':popOverPlacement==='left', \n" +
19795 " 'att-pop-over--above':popOverPlacement==='above', \n" +
19796 " 'att-pop-over--right':popOverPlacement==='right'}\" \n" +
19797 " style='position: absolute; max-width: 490px;'>\n" +
19798 " <div class=\"pop-over-caret\"\n" +
19799 " ng-class=\"{'pop-over-caret-border--left':popOverPlacement==='left', \n" +
19800 " 'pop-over-caret-border--above':popOverPlacement==='above', \n" +
19801 " 'pop-over-caret-border--right':popOverPlacement==='right', \n" +
19802 " 'pop-over-caret-border--below':popOverPlacement==='below'}\">\n" +
19804 " <div class=\"pop-over-caret\" ng-style=\"popOverPlacement=='below' && {borderBottom:'6px solid ' +popOverStyle}||popOverPlacement=='left' && {borderLeft:'6px solid ' +popOverStyle}||popOverPlacement=='right' && {borderRight:'6px solid ' +popOverStyle}||popOverPlacement=='above' && {borderTop:'6px solid ' +popOverStyle}\"\n" +
19805 " ng-class=\"{'pop-over-caret--left':popOverPlacement==='left', \n" +
19806 " 'pop-over-caret--above':popOverPlacement==='above', \n" +
19807 " 'pop-over-caret--right':popOverPlacement==='right', \n" +
19808 " 'pop-over-caret--below':popOverPlacement==='below'}\"></div>\n" +
19810 " <div class=\"att-popover-content\">\n" +
19811 " <a ng-if=\"closeable\" href=\"javascript:void(0)\" class=\"icon-close att-popover__close\" ng-click=\"closeMe();$event.preventDefault()\"></a>\n" +
19812 " <div class=\"popover-packages__container\" ng-include=\"content\"></div>\n" +
19817 angular.module("app/scripts/ng_js_att_tpls/profileCard/addUser.html", []).run(["$templateCache", function($templateCache) {
19818 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/addUser.html",
19819 "<div class=\"col-md-9 profile-card add-user\">\n" +
19820 " <div class=\"atcenter\">\n" +
19821 " <div><i class=\"icon-add\"></i></div>\n" +
19822 " <span>add User</span>\n" +
19827 angular.module("app/scripts/ng_js_att_tpls/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
19828 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/profileCard.html",
19829 "<div class=\"col-md-9 profile-card\">\n" +
19830 " <div class=\"top-block\">\n" +
19831 " <div class=\"profile-image\">\n" +
19832 " <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
19833 " <span ng-hide=\"image\" class=\"default-img\">{{initials}}</span>\n" +
19834 " <p class=\"name\" tooltip-condition=\"{{profile.name}}\" height=\"true\"></p>\n" +
19835 " <p class=\"status\">\n" +
19836 " <span class=\"status-icon\" ng-class=\"{'icon-green':colorIcon==='green','icon-red':colorIcon==='red','icon-blue':colorIcon==='blue','icon-yellow':colorIcon==='yellow'}\"> \n" +
19838 " <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
19842 " <div class=\"bottom-block\">\n" +
19843 " <div class=\"profile-details\">\n" +
19844 " <label>Username</label>\n" +
19845 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.userName}}\">{{profile.userName}}</p>\n" +
19846 " <label>Email</label>\n" +
19847 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.email}}\">{{profile.email}}</p>\n" +
19848 " <label>Role</label>\n" +
19849 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.role}}\">{{profile.role}}</p>\n" +
19850 " <label>Last Login</label>\n" +
19851 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.lastLogin}}\">{{profile.lastLogin}}</p>\n" +
19857 angular.module("app/scripts/ng_js_att_tpls/progressBars/progressBars.html", []).run(["$templateCache", function($templateCache) {
19858 $templateCache.put("app/scripts/ng_js_att_tpls/progressBars/progressBars.html",
19859 "<div class=\"att-progress\">\n" +
19860 " <div class=\"att-progress-value\"> </div>\n" +
19864 angular.module("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html", []).run(["$templateCache", function($templateCache) {
19865 $templateCache.put("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html",
19866 "<div class=\"scroll-bar\" style=\"position: absolute\">\n" +
19867 " <div class=\"scroll-thumb\" style=\"position: absolute; overflow: hidden\"></div>\n" +
19869 "<div class=\"prev icons-list\" data-size=\"medium\" ng-show=\"navigation && prevAvailable\" ng-style=\"{height: scrollbarAxis === 'x' && position.height + 'px'}\">\n" +
19870 " <a href=\"javascript:void(0);\" ng-click=\"customScroll(false)\" aria-label=\"Scroll\" aria-hidden=\"true\">\n" +
19871 " <i ng-class=\"{'ion-ios-arrow-up': (scrollbarAxis === 'y'), 'icon-chevron-left': (scrollbarAxis === 'x')}\"></i>\n" +
19874 "<div class=\"scroll-viewport\" ng-style=\"{height: (scrollbarAxis === 'x' && position.height + 'px') || viewportHeight, width: viewportWidth}\" style=\"position: relative; overflow: hidden\">\n" +
19875 " <div class=\"scroll-overview\" style=\"position: absolute; display: table; width: 100%\" att-position=\"position\" ng-transclude></div>\n" +
19877 "<div class='next icons-list' data-size=\"medium\" ng-show=\"navigation && nextAvailable\" ng-style=\"{height: scrollbarAxis === 'x' && position.height + 'px'}\">\n" +
19878 " <a href=\"javascript:void(0);\" ng-click=\"customScroll(true)\" aria-label=\"Scroll\" aria-hidden=\"true\">\n" +
19879 " <i ng-class=\"{'ion-ios-arrow-down': (scrollbarAxis === 'y'), 'icon-chevron-right': (scrollbarAxis === 'x')}\"></i>\n" +
19885 angular.module("app/scripts/ng_js_att_tpls/search/search.html", []).run(["$templateCache", function($templateCache) {
19886 $templateCache.put("app/scripts/ng_js_att_tpls/search/search.html",
19887 "<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" +
19888 " <a href=\"javascript:void(0)\" class=\"select2-choice needsclick\" tabindex=\"0\" ng-click=\"showDropdown()\" ng-class=\"{'select2-chosen-disabled':isDisabled}\" role=\"combobox\" aria-expanded=\"{{showlist}}\" aria-owns=\"inList\" aria-label=\"{{selectedOption}} selected\" ng-focus=\"isact=true;\" ng-blur=\"isact=false;\">\n" +
19889 " <span class=\"select2-chosen needsclick\" aria-hidden = \"true\">{{selectedOption}}</span>\n" +
19890 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
19891 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
19892 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
19895 " <input class=\"select2-focusser select2-offscreen\" \n" +
19896 " tabindex=\"-1\" \n" +
19897 " type=\"text\" \n" +
19898 " aria-hidden=\"true\" \n" +
19899 " title=\"hidden\" \n" +
19900 " aria-haspopup=\"true\" \n" +
19901 " role=\"button\"> \n" +
19904 "<div class=\"select2-drop select2-with-searchbox select2-drop-auto-width select2-drop-active\" ng-class=\"{'select2-display-none':(!showlist || isDisabled)}\" style=\"width:100%;z-index: 10\">\n" +
19905 " <div class=\"select2-search\">\n" +
19906 " <label ng-if=\"!noFilter\" class=\"select2-offscreen\" aria-label=\"Inline Search Field\" aria-hidden=\"true\">Inline Search Field</label>\n" +
19907 " <input ng-if=\"!noFilter\" ng-model=\"title\" aria-label=\"title\" typeahead=\"c.title for c in cName | filter:$viewValue:startsWith\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"select2-input\" aria-autocomplete=\"list\" placeholder=\"\">\n" +
19909 " <ul id=\"inList\" class=\"select2-results\" role=\"listbox\">\n" +
19910 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\" tabindex=\"-1\">No matches found</li>\n" +
19911 " <li class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\" ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\" ng-click=\"selectOption(selectMsg, '-1')\" ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\" ng-mouseover=\"hoverIn(-1)\" aria-label=\"{{selectMsg}}\" tabindex=\"-1\">\n" +
19912 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
19913 " <span class=\"select2-match\"></span>\n" +
19915 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
19916 " <span class=\"select2-match\"></span>\n" +
19920 " <li role=\"menuitem\" ng-if=\"startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\" ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | startsWith:title:item)\" ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index,'disable': item.disabled}\" ng-click=\"item.disabled || selectOption(item.title,item.index)\" ng-mouseover=\"hoverIn(item.index)\" aria-label=\"{{item.title}}\" tabindex=\"-1\">\n" +
19921 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
19922 " <span class=\"select2-match\"></span>\n" +
19926 " <li role=\"menuitem\" ng-if=\"!startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\" ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\" ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index,'disable': item.disabled}\" ng-click=\"item.disabled || selectOption(item.title,item.index)\" ng-mouseover=\"hoverIn(item.index)\" aria-label=\"{{item.title}}\" tabindex=\"-1\">\n" +
19927 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
19928 " <span class=\"select2-match\"></span>\n" +
19935 angular.module("app/scripts/ng_js_att_tpls/select/select.html", []).run(["$templateCache", function($templateCache) {
19936 $templateCache.put("app/scripts/ng_js_att_tpls/select/select.html",
19937 "<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;\">\n" +
19938 " <span class=\"select2-choice needsclick\" tabindex=\"{{isDisabled ? -1 : 0}}\" ng-click=\"showDropdown()\" ng-class=\"{'select2-chosen-disabled':isDisabled}\" role=\"combobox\" aria-expanded=\"{{showlist}}\" aria-owns=\"inList\" aria-label=\"{{titleName}} dropdown {{selectedOption}} selected\" ng-focus=\"isact=true;\" ng-blur=\"isact=false;\">\n" +
19939 " <span class=\"select2-chosen needsclick\" aria-hidden=\"true\" ng-bind-html=\"selectedOption | unsafe\">{{selectedOption}}</span>\n" +
19940 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
19941 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
19942 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
19945 " <input class=\"select2-focusser select2-offscreen\" \n" +
19946 " tabindex=\"-1\" \n" +
19947 " type=\"text\" \n" +
19948 " aria-hidden=\"true\" \n" +
19949 " title=\"hidden\" \n" +
19950 " aria-haspopup=\"true\" \n" +
19951 " role=\"button\"> \n" +
19954 "<div class=\"select2-drop select2-with-searchbox select2-drop-auto-width select2-drop-active\" ng-class=\"{'select2-display-none':(!showlist || isDisabled)}\" style=\"width:100%;z-index: 10\">\n" +
19955 " <div class=\"select2-search\">\n" +
19956 " <label ng-if=\"!noFilter\" class=\"select2-offscreen\" aria-label=\"Inline Search Field\" aria-hidden=\"true\">Inline Search Field</label>\n" +
19957 " <input ng-if=\"!noFilter\" ng-model=\"title\" aria-label=\"title\" typeahead=\"c.title for c in cName | filter:$viewValue:startsWith\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"select2-input\" aria-autocomplete=\"list\" placeholder=\"\">\n" +
19959 " <ul id=\"inList\" class=\"select2-results\" role=\"listbox\">\n" +
19960 " <li ng-if=\"!noFilter\" ng-show=\"filteredName.length === 0\" class=\"select2-no-results\" tabindex=\"-1\">No matches found</li>\n" +
19961 " <li ng-if=\"!noFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" role=\"presentation\" ng-model=\"ListType\" ng-show=\"selectMsg && filteredName.length > 0\" ng-click=\"selectOption(selectMsg, '-1')\" ng-class=\"{'select2-result-current': selectedOption === selectMsg, 'hovstyle': selectedIndex === -1}\" ng-mouseover=\"hoverIn(-1)\" aria-label=\"{{selectMsg}}\" tabindex=\"-1\">\n" +
19962 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
19963 " <span class=\"select2-match\"></span>\n" +
19965 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
19966 " <span class=\"select2-match\"></span>\n" +
19970 " <li role=\"menuitem\" ng-if=\"startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | startsWith:title:item)\" ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index,'disable': item.disabled}\" ng-click=\"item.disabled || selectOption(item.title,item.index)\" ng-mouseover=\"hoverIn(item.index)\" tabindex=\"-1\">\n" +
19971 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
19972 " <span class=\"select2-match\"></span>\n" +
19976 " <li role=\"menuitem\" ng-if=\"!startsWithFilter\" class=\"select2-results-dept-0 select2-result select2-result-selectable\" ng-model=\"ListType\" ng-repeat=\"(fIndex, item) in filteredName = (cName | filter:title)\" ng-class=\"{'select2-result-current': selectedOption === item.title,'hovstyle': selectedIndex === item.index,'disable': item.disabled}\" ng-click=\"item.disabled || selectOption(item.title,item.index)\" ng-mouseover=\"hoverIn(item.index)\" tabindex=\"-1\">\n" +
19977 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
19978 " <span class=\"select2-match\"></span>\n" +
19985 angular.module("app/scripts/ng_js_att_tpls/select/textDropdown.html", []).run(["$templateCache", function($templateCache) {
19986 $templateCache.put("app/scripts/ng_js_att_tpls/select/textDropdown.html",
19987 "<div tabindex=\"0\" class=\"text-dropdown\">\n" +
19988 " <div class=\"dropdown\" ng-class=\"{'not-visible': isActionsShown}\" ng-click=\"toggle()\">\n" +
19989 " <span class=\"action--selected\" ng-bind=\"currentAction\"></span>\n" +
19990 " <i ng-class=\"isActionsShown ? 'ion-arrow-up-b' : 'ion-arrow-down-b'\"></i>\n" +
19992 " <ul ng-class=\"isActionsShown ? 'actionsOpened' : 'actionsClosed'\" ng-show=\"isActionsShown\">\n" +
19993 " <li ng-class=\"{'highlight': selectedIndex==$index}\" ng-repeat=\"action in actions track by $index\" ng-click=\"chooseAction($event, action, $index)\" ng-mouseover=\"hoverIn($index)\">{{action}}<i ng-class=\"{'icon-included-checkmark': isCurrentAction(action)}\" att-accessibility-click=\"13,32\"></i></li>\n" +
19998 angular.module("app/scripts/ng_js_att_tpls/slider/maxContent.html", []).run(["$templateCache", function($templateCache) {
19999 $templateCache.put("app/scripts/ng_js_att_tpls/slider/maxContent.html",
20000 "<div class=\"att-slider__label att-slider__label--max att-slider__label--below\" ng-transclude></div>");
20003 angular.module("app/scripts/ng_js_att_tpls/slider/minContent.html", []).run(["$templateCache", function($templateCache) {
20004 $templateCache.put("app/scripts/ng_js_att_tpls/slider/minContent.html",
20005 "<div class=\"att-slider__label att-slider__label--min att-slider__label--below\" ng-transclude></div>");
20008 angular.module("app/scripts/ng_js_att_tpls/slider/slider.html", []).run(["$templateCache", function($templateCache) {
20009 $templateCache.put("app/scripts/ng_js_att_tpls/slider/slider.html",
20010 "<div class=\"att-slider\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\">\n" +
20011 " <div class=\"att-slider__track\">\n" +
20012 " <div class=\"att-slider__range att-slider__range--disabled\" ng-style=\"disabledStyle\"></div>\n" +
20013 " <div class=\"att-slider__range\" ng-style=\"rangeStyle\"></div>\n" +
20015 " <div class=\"att-slider__handles-container\">\n" +
20016 " <div role=\"menuitem\" aria-label=\"{{ngModelSingle}}\" 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" +
20017 " <div role=\"menuitem\" aria-label=\"Minimum Value- {{ngModelLow}}\" class=\"att-slider__handle\" ng-style=\"minHandleStyle\" ng-mousedown=\"mouseDown($event,'ngModelLow')\" ng-focus=\"focus($event,'ngModelLow')\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\" tabindex=\"0\" ng-keyup=\"keyUp($event,'ngModelLow')\" ng-keydown=\"keyDown($event,'ngModelLow')\"></div>\n" +
20018 " <div role=\"menuitem\" aria-label=\"Maximum Value- {{ngModelHigh}}\" class=\"att-slider__handle\" ng-style=\"maxHandleStyle\" ng-mousedown=\"mouseDown($event,'ngModelHigh')\" ng-focus=\"focus($event,'ngModelHigh')\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\" tabindex=\"0\" ng-keyup=\"keyUp($event,'ngModelHigh')\" ng-keydown=\"keyDown($event,'ngModelHigh')\"></div>\n" +
20020 " <div ng-transclude></div>\n" +
20024 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html", []).run(["$templateCache", function($templateCache) {
20025 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html",
20026 "<div class=\" btn-group\" \n" +
20027 " ng-class=\"{'buttons-dropdown--large':!isSmall, \n" +
20028 " 'buttons-dropdown--small':isSmall, \n" +
20029 " 'action-dropdown':(isActionDropdown), \n" +
20030 " 'open':isDropDownOpen}\">\n" +
20031 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"button btn buttons-dropdown__split\" \n" +
20032 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
20033 " 'button--secondary':btnType=='secondary', \n" +
20034 " 'button--disabled':btnType=='disabled', \n" +
20035 " 'button--small':isSmall}\" \n" +
20036 " ng-if=\"!isActionDropdown\"\n" +
20037 " ng-click=\"btnType==='disabled'?undefined:clickFxn()\" att-accessibility-click=\"13,32\">{{btnText}}</a>\n" +
20038 " <a tabindex=\"0\" href=\"javascript:void(0)\" role=\"button\" aria-label=\"Toggle Dropdown\" aria-haspopup=\"true\" class=\"button buttons-dropdown__drop dropdown-toggle\" \n" +
20039 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
20040 " 'button--secondary':btnType=='secondary', \n" +
20041 " 'button--disabled':btnType=='disabled', \n" +
20042 " 'button--small':isSmall}\" ng-click=\"toggleDropdown()\" att-accessibility-click=\"13,32\">{{toggleTitle}} </a>\n" +
20043 " <ul class=\"dropdown-menu\" ng-class=\"{'align-right':multiselect ===true}\" aria-expanded=\"{{isDropDownOpen}}\" ng-click=\"hideDropdown()\" role=\"menu\" ng-transclude></ul>\n" +
20047 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html", []).run(["$templateCache", function($templateCache) {
20048 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html",
20049 "<li role=\"menuitem\" att-element-focus=\"sFlag\" tabindex=\"0\" ng-transclude></li>");
20052 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html", []).run(["$templateCache", function($templateCache) {
20053 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html",
20054 "<div class='split-icon-button-container'>\n" +
20056 " <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" +
20057 " <a class='{{icon}}' title='{{iconTitle}}' tabindex=\"0\"></a>\n" +
20058 " <i ng-if=\"isRight && !isMiddle && !isLeftNextDropdown && !isNextToDropDown\" \n" +
20059 " ng-class=\"isDropDownOpen ? 'ion-arrow-up-b' : 'ion-arrow-down-b'\"> </i>\n" +
20062 " <ul ng-if='isDropdown' class='dropdown-menu {{dropDownId}}' ng-show='\n" +
20063 " isDropDownOpen' ng-click='toggleDropdown(false)' role=\"presentation\" ng-transclude>\n" +
20069 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html", []).run(["$templateCache", function($templateCache) {
20070 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html",
20072 " <div ng-if='isLeftLineShown' dir-type='{{iconStateConstants.DIR_TYPE.LEFT}}' expandable-line></div>\n" +
20073 " <div ng-click='clickHandler()' att-split-icon icon='{{icon}}' title='{{title}}' dir-type='{{iconStateConstants.DIR_TYPE.BUTTON}}' hover-watch='isHovered' drop-down-watch='dropDownWatch' drop-down-id='{{dropDownId}}'>\n" +
20074 " <div ng-transclude>\n" +
20077 " <div ng-if='isRightLineShown' dir-type='{{iconStateConstants.DIR_TYPE.RIGHT}}' expandable-line></div>\n" +
20081 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html", []).run(["$templateCache", function($templateCache) {
20082 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html",
20083 "<div ng-transclude>\n" +
20087 angular.module("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html", []).run(["$templateCache", function($templateCache) {
20088 $templateCache.put("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html",
20089 "<span ng-class=\"mainSliderClass\">\n" +
20093 " <div class=\"jslider-bg\">\n" +
20094 " <i class=\"l\"></i>\n" +
20095 " <i class=\"r\"></i>\n" +
20096 " <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" +
20098 " <div class=\"jslider-pointer\" id=\"left-pointer\"></div>\n" +
20099 " <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" +
20100 " <div class=\"jslider-label\"><span ng-bind=\"from\"></span><span ng-bind=\"options.dimension\"></span></div>\n" +
20101 " <div class=\"jslider-label jslider-label-to\"><span ng-bind=\"toStr\"></span><span ng-bind=\"endDimension\"></span></div>\n" +
20102 " <div class=\"jslider-value\" id=\"jslider-value-left\"><span></span>{{options.dimension}}</div>\n" +
20103 " <div class=\"jslider-value jslider-value-to\"><span></span>{{toolTipDimension}}</div>\n" +
20104 " <div class=\"jslider-scale\" ng-class=\"{'show-dividers': showDividers, 'cutoff-slider-dividers':isCutOffSlider}\">\n" +
20106 " <div class=\"jslider-cutoff\">\n" +
20107 " <div class=\"jslider-label jslider-label-cutoff\">\n" +
20108 " <span ng-bind=\"cutOffVal\"></span>\n" +
20118 angular.module("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html", []).run(["$templateCache", function($templateCache) {
20119 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html",
20120 "<div class=\"steptracker1\">\n" +
20121 " <div class=\"steptracker-bg\">\n" +
20122 " <div tabindex=\"0\" ng-click=\"stepclick($event, $index);\" att-accessibility-click=\"13,23\" class=\"steptracker-track size-onethird\" ng-repeat=\"step in sdata\"\n" +
20123 " ng-style=\"set_width($index)\"\n" +
20124 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index), 'incomplete': isIncomplete($index), 'disabled': disableClick}\">\n" +
20125 " <div class=\"circle\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
20126 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
20132 angular.module("app/scripts/ng_js_att_tpls/steptracker/step.html", []).run(["$templateCache", function($templateCache) {
20133 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step.html",
20134 "<div class=\"steptracker1\">\n" +
20135 " <div class=\"steptracker-bg\">\n" +
20136 " <div class=\"steptracker-track size-onethird\" \n" +
20137 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index)}\">\n" +
20138 " <div class=\"circle\" tabindex=\"0\" \n" +
20139 " ng-click=\"stepclick($event, $index);\" \n" +
20140 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
20141 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
20148 angular.module("app/scripts/ng_js_att_tpls/steptracker/timeline.html", []).run(["$templateCache", function($templateCache) {
20149 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timeline.html",
20150 "<div class='att-timeline'>\n" +
20151 " <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" +
20153 " <div ng-repeat=\"m in middleSteps track by $index\">\n" +
20154 " <div timeline-bar order='{{$index}}'></div>\n" +
20155 " <div timeline-dot order='{{$index + 1}}' title='{{m.title}}' description='{{m.description}}' by='{{m.by}}' date='{{m.date}}' type='{{m.type}}'>\n" +
20162 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html", []).run(["$templateCache", function($templateCache) {
20163 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html",
20164 "<div class='timeline-bar'>\n" +
20165 " <div class='progress-bar' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20171 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html", []).run(["$templateCache", function($templateCache) {
20172 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html",
20173 "<div class='timeline-dot'>\n" +
20175 " <div class='bigger-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20178 " <div class='inactive-circle'>\n" +
20181 " <div class='expandable-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20184 " <div ng-class=\"{'below-info-box':isBelowInfoBoxShown, 'above-info-box': !isBelowInfoBoxShown}\" tabindex=\"0\">\n" +
20186 " <div ng-if='isBelowInfoBoxShown' class='vertical-line'>\n" +
20189 " <div class='info-container' ng-init='isContentShown=false'>\n" +
20190 " <div ng-class=\"{'current-step-title':isCurrentStep, 'title':!isCurrentStep,'completed-color-text':isCompleted,'cancelled-color-text':isCancelled,'alert-color-text':isAlert, 'inactive-color-text':isInactive}\" ng-mouseover='titleMouseover(1)' ng-mouseleave='titleMouseleave()' ng-bind='title' ></div>\n" +
20191 " <div class='content'>\n" +
20192 " <div class='description' ng-bind='description'></div>\n" +
20193 " <div class='submitter' ng-bind='by'></div>\n" +
20195 " <div class='date' ng-mouseover='titleMouseover(2)' ng-mouseleave='titleMouseleave()' ng-bind='date'></div>\n" +
20198 " <div ng-if='!isBelowInfoBoxShown' class='vertical-line'>\n" +
20205 angular.module("app/scripts/ng_js_att_tpls/table/attTable.html", []).run(["$templateCache", function($templateCache) {
20206 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTable.html",
20207 "<table class=\"tablesorter tablesorter-default\" ng-transclude></table>\n" +
20211 angular.module("app/scripts/ng_js_att_tpls/table/attTableBody.html", []).run(["$templateCache", function($templateCache) {
20212 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableBody.html",
20213 "<td ng-transclude></td>\n" +
20217 angular.module("app/scripts/ng_js_att_tpls/table/attTableHeader.html", []).run(["$templateCache", function($templateCache) {
20218 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableHeader.html",
20219 "<th role=\"columnheader\" scope=\"col\" aria-live=\"polite\" aria-sort=\"{{sortPattern !== 'null' && '' || sortPattern}}\" aria-label=\"{{headerName}} {{sortable !== 'false' && ': activate to sort' || ' '}} {{sortPattern !== 'null' && '' || sortPattern}}\" tabindex=\"{{sortable !== 'false' && '0' || '-1'}}\" class=\"tablesorter-header\" ng-class=\"{'tablesorter-headerAsc': sortPattern === 'ascending', 'tablesorter-headerDesc': sortPattern === 'descending', 'tablesort-sortable': sortable !== 'false', 'sorter-false': sortable === 'false'}\" att-accessibility-click=\"13,32\" ng-click=\"(sortable !== 'false') && sort();\"><div class=\"tablesorter-header-inner\" ng-transclude></div></th>");
20222 angular.module("app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html", []).run(["$templateCache", function($templateCache) {
20223 $templateCache.put("app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html",
20224 "<div class=\"att-table-message\">\n" +
20225 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.noMatching\">\n" +
20226 " <div class=\"img-magnify-glass\"></div> \n" +
20228 " <div ng-transclude></div>\n" +
20231 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.errorLoading\">\n" +
20232 " <div class=\"img-oops-exclamation\" tabindex=\"0\" aria-label=\"Oops! The information could not load at this time. Please click link to refresh the page.\"></div> \n" +
20233 " <div>Oops!</div>\n" +
20234 " <div>The information could not load at this time.</div>\n" +
20235 " <div>Please <a href=\"javascript:void(0)\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
20238 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.magnifySearch\">\n" +
20239 " <div class=\"img-magnify-glass\"></div>\n" +
20241 " <p class=\"title\" tabindex=\"0\">Please input values to <br/> begin your search.</p>\n" +
20244 " <div class=\"message loading-message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.isLoading\">\n" +
20245 " <div class=\"img-loading-dots\"></div>\n" +
20246 " <div ng-transclude></div>\n" +
20251 angular.module("app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html", []).run(["$templateCache", function($templateCache) {
20252 $templateCache.put("app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html",
20253 "<div class=\"att-user-message\">\n" +
20254 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.error && trigger ? 'message-wrapper-error' : 'hidden'\">\n" +
20255 " <div class=\"message-icon-error\"> <i class=\"icon-info-alert\"></i> </div>\n" +
20257 " <div class=\"message-body-wrapper\">\n" +
20258 " <div class=\"message-title-error\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\" tabindex=\"0\" aria-label=\"{{thetitle}}\"></span> </div>\n" +
20259 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\" tabindex=\"0\"></div>\n" +
20260 " <div class=\"message-bottom\">\n" +
20261 " <div ng-transclude></div>\n" +
20266 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.success && trigger ? 'message-wrapper-success' : 'hidden'\">\n" +
20267 " <div class=\"message-icon-success\"> <i class=\"icon-included-checkmark\"></i></div>\n" +
20269 " <div class=\"message-body-wrapper\">\n" +
20270 " <div class=\"message-title-success\" ng-if=\"thetitle && thetitle.length > 0\" >\n" +
20271 " <span ng-bind=\"thetitle\" tabindex=\"0\" aria-label=\"{{thetitle}}\"></span>\n" +
20273 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\" tabindex=\"0\"></div>\n" +
20274 " <div class=\"message-bottom\">\n" +
20275 " <div ng-transclude></div>\n" +
20284 angular.module("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html", []).run(["$templateCache", function($templateCache) {
20285 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html",
20286 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
20287 " <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" +
20288 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
20293 angular.module("app/scripts/ng_js_att_tpls/tabs/genericTabs.html", []).run(["$templateCache", function($templateCache) {
20294 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/genericTabs.html",
20295 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
20296 " <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" +
20297 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
20303 angular.module("app/scripts/ng_js_att_tpls/tabs/menuTab.html", []).run(["$templateCache", function($templateCache) {
20304 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/menuTab.html",
20305 "<li class=\"megamenu__item\" ng-mouseover=\"showHoverChild($event)\" ng-class=\"{'tabs__item--active': menuItem.active==true && !hoverChild==true}\">\n" +
20306 " <span role=\"menuitem\" att-accessibility-click=\"13,32\" tabindex=\"0\" ng-click=\"showChildren($event);!clickInactive||resetMenu($event)\">{{tabName}}</span>\n" +
20307 " <div ng-transclude></div>\n" +
20312 angular.module("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html", []).run(["$templateCache", function($templateCache) {
20313 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html",
20314 "<div ng-class=\"{'megamenu-tabs': megaMenu,'submenu-tabs': !megaMenu}\">\n" +
20315 " <ul class=\"megamenu__items\" role=\"presentation\" ng-transclude>\n" +
20320 angular.module("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html", []).run(["$templateCache", function($templateCache) {
20321 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html",
20322 "<div class=\"simplified-tabs\">\n" +
20323 "<ul class=\"simplified-tabs__items\" role=\"tablist\">\n" +
20324 " <li ng-repeat=\"tab in tabs\" role=\"tab\" 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" +
20325 " <li class=\"tabs__pointer\"></li>\n" +
20330 angular.module("app/scripts/ng_js_att_tpls/tabs/submenuTab.html", []).run(["$templateCache", function($templateCache) {
20331 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/submenuTab.html",
20332 "<li class=\"tabsbid__item megamenu__item\" ng-class=\"{'subMenuHover': menuItem.active==true}\">\n" +
20333 "<a ng-href=\"{{tabUrl}}\" role=\"menuitem\" ng-if=\"subMenu === true\" ng-mouseover=\"!subMenu || showChildren($event)\" ng-focus=\"!subMenu ||showChildren($event)\" tabindex=\"{{subMenu=='true'?0:-1}}\" ng-click=\"!subMenu ||showMenuClick($event) ; subMenu ||showSubMenuClick($event)\" att-accessibility-click=\"13,32\">{{tabName}}</a>\n" +
20334 "<a ng-href=\"{{tabUrl}}\" role=\"menuitem\" ng-if=\"!menuItem.leafNode && subMenu !== true\" ng-mouseover=\"!subMenu || showChildren($event)\" ng-focus=\"!subMenu ||showChildren($event)\" tabindex=\"{{subMenu=='true'?0:-1}}\" ng-click=\"!subMenu ||showMenuClick($event) ; subMenu ||showSubMenuClick($event)\" att-accessibility-click=\"13,32\">{{tabName}}</a>\n" +
20335 "<span ng-transclude></span>\n" +
20340 angular.module("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html", []).run(["$templateCache", function($templateCache) {
20341 $templateCache.put("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html",
20342 "<div class=\"tags__item\" \n" +
20343 " ng-class=\"{'tags__item--small':isSmall, \n" +
20344 " 'tags__item--color':isColor, \n" +
20345 " 'tags__item--cloud':!isClosable && !isColor,'active':applyActiveClass}\"\n" +
20346 " ng-if=\"display\" \n" +
20347 " ng-style=\"{borderColor: border_type_borderColor, background: isHighlight?'#bbb':undefined, color: isHighlight?'#444':undefined }\"\n" +
20348 " ng-mousedown=\"activeHighlight(true)\" role=\"presentation\" ng-mouseup=\"activeHighlight(false)\">\n" +
20349 " <i class=\"icon-filter tags__item--icon\" ng-if=\"isIcon\"> </i>\n" +
20350 " <i class=\"tags__item--color-icon\" ng-if=\"isColor\" ng-style=\"{backgroundColor: background_type_backgroundColor, borderColor: background_type_borderColor}\"></i>\n" +
20351 " <span class=\"tags__item--title\" role=\"presentation\" tabindex=0 ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\" ng-transclude></span>\n" +
20352 " <a href=\"javascript:void(0)\" title=\"Dismiss Link\" class=\"tags__item--action\" ng-click=\"closeMe();$event.preventDefault()\" ng-if=\"isClosable\"\n" +
20353 " ng-style=\"{color: (isHighlight && '#444') || '#888' , borderLeft: (isHighlight && '1px solid #444')|| '1px solid #888' }\">\n" +
20354 " <i class=\"icon-erase\"> </i>\n" +
20359 angular.module("app/scripts/ng_js_att_tpls/toggle/demoToggle.html", []).run(["$templateCache", function($templateCache) {
20360 $templateCache.put("app/scripts/ng_js_att_tpls/toggle/demoToggle.html",
20361 "<span ng-transclude></span>\n" +
20362 "<div 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" +
20363 " <div class=\"att-switch-onText\" ng-style=\"\" ng-class=\"{'icon-included-checkmark ico' : on === undefined,'large' : directiveValue == 'large'}\">{{on}}<span class=\"hidden-spoken\">{{directiveValue}} when checked.</span></div>\n" +
20364 " <div class=\"att-switch-thumb\" tabindex=\"0\" title=\"Toggle switch\" role=\"checkbox\" ng-class=\"{'large' : directiveValue == 'large'}\"></div>\n" +
20365 " <div class=\"att-switch-offText\" ng-class=\"{'icon-erase ico' : on === undefined,'large' : directiveValue == 'large'}\">{{off}}<span class=\"hidden-spoken\">{{directiveValue}} when unchecked.</span></div>\n" +
20370 angular.module("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html", []).run(["$templateCache", function($templateCache) {
20371 $templateCache.put("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html",
20372 "<div class=\"typeahead mainContainerOuter\">\n" +
20373 " <span class=\"message\">To</span>\n" +
20374 " <div class='maincontainer' ng-click=\"setFocus()\" ng-focus=\"inputActive=true\" ng-class =\"{'typeahed_active':inputActive || (lineItems.length && inputActive)}\">\n" +
20375 " <span tag-badges closable ng-repeat =\"lineItem in lineItems track by $index\" on-close=\"theMethodToBeCalled($index)\" >{{lineItem}}</span>\n" +
20376 " <input type=\"text\" focus-me=\"clickFocus\" ng-focus=\"inputActive=true\" ng-model=\"model\" ng-keydown=\"selected = false; selectionIndex($event)\"/><br/> \n" +
20378 " <div ng-hide=\"!model.length || selected\">\n" +
20379 " <div class=\"filtercontainer list-scrollable\" ng-show=\"( items | filter:model).length\">\n" +
20380 " <div class=\"item\" ng-repeat=\"item in items| filter:model track by $index\" ng-click=\"handleSelection(item[titleName],item[subtitle])\" att-accessibility-click=\"13,32\" ng-class=\"{active:isCurrent($index,item[titleName],item[subtitle],( items | filter:model).length)}\"ng-mouseenter=\"setCurrent($index)\">\n" +
20381 " <span class=\"title\" >{{item[titleName]}}</span>\n" +
20382 " <span class=\"subtitle\">{{item[subtitle]}}</span>\n" +
20387 " <div class=\"textAreaEmailContentDiv\">\n" +
20388 " <span class=\"message\">Message</span>\n" +
20389 " <textarea rows=\"4\" cols=\"50\" role=\"textarea\" class=\"textAreaEmailContent\" ng-model=\"emailMessage\">To send \n" +
20390 " a text, picture, or video message1 to a wireless device from your email:my message.</textarea>\n" +
20398 angular.module("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html", []).run(["$templateCache", function($templateCache) {
20399 $templateCache.put("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html",
20401 " <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" +
20402 " <span ng-transclude></span>\n" +
20408 angular.module("app/scripts/ng_js_att_tpls/videoControls/photoControls.html", []).run(["$templateCache", function($templateCache) {
20409 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/photoControls.html",
20411 " <a title=\"{{links.prevLink}}\" aria-label=\"Previous Link\" ng-href=\"{{links.prevLink}}\"><i alt=\"previous\" class=\"icon-arrow-left\"> </i></a>\n" +
20412 " <span ng-transclude></span>\n" +
20413 " <a title=\"{{links.nextLink}}\" aria-label=\"Next Link\" ng-href=\"{{links.nextLink}}\"><i alt=\"next\" class=\"icon-arrow-right\"> </i></a>\n" +
20417 angular.module("app/scripts/ng_js_att_tpls/videoControls/videoControls.html", []).run(["$templateCache", function($templateCache) {
20418 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/videoControls.html",
20419 "<div class=\"video-player\">\n" +
20420 " <div class=\"video-player__control video-player__play-button\">\n" +
20421 " <a class=\"video-player__button gigant-play\" data-toggle-buttons=\"icon-play, icon-pause\" data-target=\"i\"><i class=\"icon-play\" alt=\"Play/Pause Button\"></i></a>\n" +
20423 " <div class=\"video-player__control video-player__track\">\n" +
20425 " <div class=\"video-player__track--inner\">\n" +
20426 " <div class=\"video-player__track--loaded\" style=\"width: 75%\"></div>\n" +
20427 " <div class=\"video-player__track--played\" style=\"width: 40%\">\n" +
20428 " <div class=\"att-tooltip att-tooltip--on att-tooltip--dark att-tooltip--above video-player__track-tooltip\" ng-transclude></div>\n" +
20429 " <div class=\"video-player__track-handle\"></div>\n" +
20433 " <a class=\"video-player__time\" ng-transclude></a>\n" +
20434 " <div class=\"video-player__control video-player__volume_icon\">\n" +
20435 " <a class=\"video-player__button\" data-toggle-buttons=\"icon-volume-mute, icon-volume-up\" data-target=\"i\"><i class=\"icon-volume-up\" alt=\"Volume Button\"></i></a>\n" +
20437 " <ul class=\"video-player__control video-player__volume\">\n" +
20438 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
20439 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
20440 " <li class=\"video-player__volume-bar\"> </li>\n" +
20441 " <li class=\"video-player__volume-bar\"> </li>\n" +
20442 " <li class=\"video-player__volume-bar\"> </li>\n" +
20444 " <div class=\"video-player__control video-player__toggle-fullscreen-button\">\n" +
20445 " <a class=\"video-player__button\" data-toggle-buttons=\"icon-full-screen, icon-normal-screen\" data-target=\"i\"><i class=\"icon-full-screen\" alt=\"Full Screen Button\"> </i></a>\n" +
20451 })(angular, window);