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);
7887 scope.setFocus = false;
7889 var handleKeydown = function (ev) {
7890 var boolFlag = true;
7894 ev.preventDefault();
7900 ev.preventDefault();
7901 accordionCtrl.cycle(scope, false);
7905 ev.preventDefault();
7906 accordionCtrl.cycle(scope, true);
7912 ev.stopPropagation();
7916 if (angular.isUndefined(scope.isOpen)) {
7917 scope.isOpen = false;
7920 tab.bind("keydown", handleKeydown);
7922 accordionCtrl.addGroup(scope);
7924 if (scope.index === 0) {
7925 scope.focused = true;
7928 accordionGroupCtrl.toggle = scope.toggle = function () {
7929 scope.isOpen = !scope.isOpen;
7930 accordionCtrl.focus(scope);
7931 return scope.isOpen;
7934 scope.$watch('isOpen', function (value) {
7936 accordionCtrl.closeOthers(scope);
7940 scope.$watch("focused", function (value) {
7942 tab.attr("tabindex", "0");
7948 scope.setFocus = false;
7949 tab.attr("tabindex", "-1");
7955 // Use accordion-heading below an accordion-group to provide a heading containing HTML
7956 // <accordion-group>
7957 // <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
7958 // </accordion-group>
7959 .directive('accordionToggle', function () {
7962 require: '^accordionGroup',
7967 link: function (scope, element, attr, accordionCtrl)
7969 var setIcon = function (isOpen) {
7970 if (scope.expandIcon && scope.collapseIcon)
7973 element.removeClass(scope.expandIcon);
7974 element.addClass(scope.collapseIcon);
7977 element.removeClass(scope.collapseIcon);
7978 element.addClass(scope.expandIcon);
7982 element.bind('click', function ()
7984 accordionCtrl.toggle();
7987 scope.$watch(function () {
7988 return accordionCtrl.isIsOpen();
7989 }, function (value) {
7994 }).directive('accordionHeading', function () {
7999 require: '^accordionGroup',
8000 compile: function (element, attr, transclude) {
8001 var link = function (scope, element, attr, accordionGroupCtrl) {
8002 // Pass the heading to the accordion-group controller
8003 // so that it can be transcluded into the right place in the template
8004 // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
8005 transclude(scope, function (clone) {
8006 element.append(clone);
8007 accordionGroupCtrl.setHeading(element);
8014 // Use in the accordion-group template to indicate where you want the heading to be transcluded
8015 // You must provide the property on the accordion-group controller that will hold the transcluded element
8016 .directive('accordionTransclude', function () {
8018 require: '^accordionGroup',
8019 link: function (scope, element, attr, controller) {
8020 scope.$watch(function () {
8021 return controller[attr.accordionTransclude];
8022 }, function (heading) {
8024 element.find("span").eq(0).prepend(heading);
8030 .directive('attGoTop', ['$scrollTo', function ($scrollTo) {
8034 link: function (scope, elem, attrs)
8036 elem.bind('click', function ()
8038 $scrollTo(0, attrs["attGoTop"]);
8043 .directive('attGoTo', ['$anchorScroll', '$location', function ($anchorScroll, $location) {
8047 link: function (scope, elem, attrs)
8049 elem.bind('click', function ()
8051 var newHash = attrs["attGoTo"];
8052 if ($location.hash() !== newHash)
8054 $location.hash(attrs["attGoTo"]);
8064 .directive('freeStanding', function () {
8070 template: "<div><span class='att-accordion__freestanding' ng-show='showAccordion'></span>\n" +
8071 "<div class='section-toggle'>\n" +
8072 "<button class='section-toggle__button' ng-click='fsToggle()'>\n" +
8073 " {{btnText}}<i style='font-size:0.875rem' ng-class='{\"icon-chevron-up\": showAccordion,\"icon-chevron-down\": !showAccordion, }'></i> \n" +
8076 compile: function (element, attr, transclude)
8078 var link = function (scope, elem, attrs) {
8080 transclude(scope, function (clone)
8082 elem.find("span").append(clone);
8084 scope.showAccordion = false;
8085 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
8086 scope.fsToggle = function ()
8088 scope.showAccordion = !scope.showAccordion;
8089 scope.btnText = scope.showAccordion ? attrs.hideMsg : attrs.showMsg;
8095 }).directive('expanders', function () {
8100 template: "<div ng-transclude></div>",
8101 controller: ['$scope', function ($scope){
8102 var bodyScope = null;
8103 this.setScope = function (scope) {
8106 this.toggle = function () {
8107 $scope.isOpen = bodyScope.isOpen = !bodyScope.isOpen;
8108 return bodyScope.isOpen;
8111 link: function (scope)
8113 scope.isOpen = false;
8116 }).directive('expanderHeading', function () {
8118 require: "^expanders",
8123 template: "<div style='padding:10px !important' ng-transclude></div>"
8125 }).directive('expanderBody', function () {
8128 require: "^expanders",
8132 template: "<div collapse='!isOpen'><div ng-transclude></div></div>",
8133 link: function (scope, elem, attr, myCtrl) {
8134 scope.isOpen = false;
8135 myCtrl.setScope(scope);
8138 }).directive('expanderToggle', function () {
8141 require: "^expanders",
8146 link: function (scope, element, attr, myCtrl)
8149 var setIcon = function () {
8150 if (scope.expandIcon && scope.collapseIcon)
8153 element.removeClass(scope.expandIcon);
8154 element.addClass(scope.collapseIcon);
8157 element.removeClass(scope.collapseIcon);
8158 element.addClass(scope.expandIcon);
8162 element.bind("keydown", function (e) {
8163 if (e.keyCode === 13)
8168 element.bind('click', function ()
8172 scope.toggleit = function ()
8174 isOpen = myCtrl.toggle();
8181 }).directive('collapse', ['$transition', function ($transition) {
8182 // CSS transitions don't work with height: auto, so we have to manually change the height to a
8183 // specific value and then once the animation completes, we can reset the height to auto.
8184 // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
8185 // "collapse") then you trigger a change to height 0 in between.
8186 // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
8192 paddingBottom: null,
8203 var fixUpHeight = function (scope, element, height) {
8204 // We remove the collapse CSS class to prevent a transition when we change to height: auto
8205 element.removeClass('collapse');
8206 element.css({height: height});
8207 //adjusting for any margin or padding
8209 element.css(props.closed);
8211 element.css(props.open);
8213 // It appears that reading offsetWidth makes the browser realise that we have changed the
8214 // height already :-/
8215 element.addClass('collapse');
8218 link: function (scope, element, attrs) {
8220 var initialAnimSkip = true;
8221 scope.$watch(function () {
8222 return element[0].scrollHeight;
8224 //The listener is called when scrollHeight changes
8225 //It actually does on 2 scenarios:
8226 // 1. Parent is set to display none
8227 // 2. angular bindings inside are resolved
8228 //When we have a change of scrollHeight we are setting again the correct height if the group is opened
8229 if (element[0].scrollHeight !== 0 && !isCollapsed) {
8230 if (initialAnimSkip) {
8231 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
8233 fixUpHeight(scope, element, 'auto');
8237 var currentTransition;
8238 var doTransition = function (change) {
8239 if (currentTransition) {
8240 currentTransition.cancel();
8242 currentTransition = $transition(element, change);
8243 currentTransition.then(
8245 currentTransition = undefined;
8248 currentTransition = undefined;
8251 return currentTransition;
8253 var expand = function () {
8254 scope.postTransition = true;
8255 if (initialAnimSkip) {
8256 initialAnimSkip = false;
8258 fixUpHeight(scope, element, 'auto');
8261 doTransition(angular.extend({height: element[0].scrollHeight + 'px'}, props.open))
8263 // This check ensures that we don't accidentally update the height if the user has closed
8264 // the group while the animation was still running
8267 fixUpHeight(scope, element, 'auto');
8271 isCollapsed = false;
8273 var collapse = function () {
8275 if (initialAnimSkip) {
8276 initialAnimSkip = false;
8277 fixUpHeight(scope, element, 0);
8279 fixUpHeight(scope, element, element[0].scrollHeight + 'px');
8280 doTransition(angular.extend({height: 0}, props.closed)).then(function () {
8281 scope.postTransition = false;
8285 scope.$watch(attrs.collapse, function (value) {
8295 .directive('attAccord', function () {
8301 controller: 'AttAccordCtrl',
8302 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html'
8305 .controller('AttAccordCtrl', [function () {
8306 this.type = 'attAccord';
8310 this.toggleBody = function () {
8315 this.collapseBody();
8319 this.expandBody = function () {
8320 this.bodyCtrl.expand();
8322 this.collapseBody = function () {
8323 this.bodyCtrl.collapse();
8326 .controller('AttAccordHeaderCtrl', [function () {
8327 this.type = 'header';
8329 .directive('attAccordHeader', ['keymap', 'events', function (keymap, events) {
8334 require: ['^attAccord', 'attAccordHeader'],
8335 controller: 'AttAccordHeaderCtrl',
8336 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html',
8337 link: function (scope, element, attr, ctrls) {
8338 var attAccordCtrl = ctrls[0];
8339 var attAccordHeaderCtrl = ctrls[1];
8340 attAccordCtrl.headerCtrl = attAccordHeaderCtrl;
8341 var tab = element.children().eq(0);
8343 scope.clickFunc = function () {
8344 attAccordCtrl.toggleBody();
8347 var handleKeydown = function (ev) {
8348 var boolFlag = true;
8351 case keymap.KEY.ENTER:
8352 ev.preventDefault();
8360 ev.stopPropagation();
8364 if (angular.isUndefined(scope.isOpen)) {
8365 scope.isOpen = false;
8368 tab.bind("keydown", handleKeydown);
8372 .controller('AttAccordBodyCtrl', ['$scope', function ($scope) {
8374 this.expand = function () {
8377 this.collapse = function () {
8381 .directive('attAccordBody', ['$timeout', '$height', function ($timeout, $height) {
8386 require: ['^attAccord', 'attAccordBody'],
8387 controller: 'AttAccordBodyCtrl',
8388 templateUrl: 'app/scripts/ng_js_att_tpls/accordion/attAccordBody.html',
8389 link: function (scope, element, attr, ctrls) {
8390 var attAccordCtrl = ctrls[0];
8391 var attAccordBodyCtrl = ctrls[1];
8392 attAccordCtrl.bodyCtrl = attAccordBodyCtrl;
8394 $timeout(function () {
8395 originalHeight = element[0].offsetHeight;
8396 $height(element, 0, 0, 0);
8398 scope.expand = function () {
8399 $height(element, 0.05, originalHeight, 1);
8401 scope.collapse = function () {
8402 $height(element, 0.25, 0, 0);
8407 angular.module('att.abs.alert', [])
8408 .directive('attAlert', [function()
8415 alertType : "@type",
8416 showTop : "@topPos",
8419 templateUrl : 'app/scripts/ng_js_att_tpls/alert/alert.html',
8420 link: function(scope)
8422 if(scope.showTop === 'true'){
8423 scope.cssStyle = {'top':'50px'};
8426 scope.cssStyle = {'top':'0px'};
8428 scope.close = function(){
8429 scope.showAlert = false;
8435 angular.module('att.abs.boardStrip', ['att.abs.utilities'])
8436 .constant('BoardStripConfig', {
8437 'maxVisibleBoards': 4,
8438 'boardsToScroll': 1,
8439 /* These parameters are non-configurable and remain unaltered, until there is a change in corresponding SCSS */
8443 .directive('attBoard', [function() {
8448 require: '^attBoardStrip',
8453 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attBoard.html',
8454 link: function(scope, element, attrs, ctrls) {
8456 var parentCtrl = ctrls;
8458 scope.getCurrentIndex = function() {
8459 return parentCtrl.getCurrentIndex();
8461 scope.selectBoard = function(boardIndex) {
8462 if (!isNaN(boardIndex)) {
8463 parentCtrl.setCurrentIndex(boardIndex);
8466 scope.isInView = function(boardIndex) {
8467 return parentCtrl.isInView(boardIndex);
8472 .directive('attBoardStrip', ['BoardStripConfig', '$timeout', '$ieVersion', function(BoardStripConfig, $timeout, $ieVersion) {
8478 currentIndex: '=selectedIndex',
8479 boardsMasterArray : '=',
8482 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html',
8483 controller: function($scope) {
8484 if(!angular.isDefined($scope.boardsMasterArray)){
8485 $scope.boardsMasterArray = [];
8488 this.rectifyMaxVisibleBoards = function() {
8489 if (this.maxVisibleIndex >= $scope.boardsMasterArray.length) {
8490 this.maxVisibleIndex = $scope.boardsMasterArray.length - 1;
8493 if (this.maxVisibleIndex < 0) {
8494 this.maxVisibleIndex = 0;
8498 this.resetBoardStrip = function(){
8499 $scope.currentIndex = 0;
8501 this.maxVisibleIndex = BoardStripConfig.maxVisibleBoards-1;
8502 this.minVisibleIndex = 0;
8504 this.rectifyMaxVisibleBoards();
8508 if ($scope.currentIndex > 0) {
8509 var index = $scope.currentIndex;
8510 this.resetBoardStrip();
8511 if (index > $scope.boardsMasterArray.length) {
8512 $scope.currentIndex = $scope.boardsMasterArray.length-1;
8514 $scope.currentIndex = index;
8517 this.resetBoardStrip();
8521 this.getCurrentIndex = function() {
8522 return $scope.currentIndex;
8524 this.setCurrentIndex = function(indx) {
8525 $scope.currentIndex = indx;
8528 this.isInView = function(index) {
8529 return (index <= this.maxVisibleIndex && index >= this.minVisibleIndex);
8532 this.getBoardsMasterArrayLength = function() {
8533 return $scope.boardsMasterArray.length;
8536 link: function(scope, element, attrs, ctrl) {
8537 var ieVersion = $ieVersion();
8540 var animationTimeout = 1000;
8542 if(ieVersion && ieVersion < 10) {
8543 animationTimeout = 0;
8546 var getBoardViewportWidth = function (numberOfVisibleBoards) {
8547 return numberOfVisibleBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
8549 if(element[0].querySelector(".board-viewport")) {
8550 angular.element(element[0].querySelector(".board-viewport")).css({"width": getBoardViewportWidth(BoardStripConfig.maxVisibleBoards) + "px"});
8553 var getBoardstripContainerWidth = function (totalNumberOfBoards) {
8554 return totalNumberOfBoards * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin);
8556 if(element[0].querySelector(".boardstrip-container")) {
8557 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8558 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": "0px"});
8561 var calculateAndGetBoardstripContainerAdjustment = function () {
8563 var calculatedAdjustmentValue;
8565 if(ctrl.getBoardsMasterArrayLength() <= BoardStripConfig.maxVisibleBoards) {
8566 calculatedAdjustmentValue = 0;
8569 calculatedAdjustmentValue = (ctrl.minVisibleIndex * (BoardStripConfig.boardLength + BoardStripConfig.boardMargin))* -1;
8572 return calculatedAdjustmentValue;
8575 var updateBoardsTabIndex = function(boardArray, minViewIndex, maxViewIndex) {
8576 for (var i = 0; i < boardArray.length; i++) {
8577 angular.element(boardArray[i]).attr('tabindex', '-1');
8579 for (var i = minViewIndex; i <= maxViewIndex; i++) {
8580 angular.element(boardArray[i]).attr('tabindex', '0');
8584 scope.$watchCollection('boardsMasterArray', function(newVal, oldVal){
8585 if(newVal !== oldVal){
8586 /* When a board is removed */
8587 if(newVal.length < oldVal.length){
8588 ctrl.resetBoardStrip();
8589 $timeout(function(){
8591 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8592 if(currentBoardArray.length !== 0) {
8594 var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
8595 var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
8596 if(oldContainerAdjustment !== containerAdjustment+'px') {
8597 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": containerAdjustment + "px"});
8599 $timeout.cancel(oldTimeout);
8600 oldTimeout = $timeout(function(){
8601 currentBoardArray[0].focus();
8602 }, animationTimeout);
8605 currentBoardArray[0].focus();
8609 element[0].querySelector('div.boardstrip-item--add').focus();
8612 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8615 /* When a board is added */
8617 ctrl.maxVisibleIndex = ctrl.getBoardsMasterArrayLength()-1;
8618 ctrl.minVisibleIndex = Math.max(ctrl.maxVisibleIndex - BoardStripConfig.maxVisibleBoards + 1, 0);
8620 ctrl.setCurrentIndex(ctrl.maxVisibleIndex);
8622 $timeout(function(){
8623 angular.element(element[0].querySelector(".boardstrip-container")).css({"width": getBoardstripContainerWidth(ctrl.getBoardsMasterArrayLength()) + "px"});
8625 var oldContainerAdjustment = angular.element(element[0].querySelector(".boardstrip-container"))[0].style.left;
8626 var containerAdjustment = calculateAndGetBoardstripContainerAdjustment();
8627 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8628 if(oldContainerAdjustment !== containerAdjustment+'px') {
8629 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": containerAdjustment + "px"});
8631 $timeout.cancel(oldTimeout);
8632 oldTimeout = $timeout(function(){
8633 currentBoardArray[currentBoardArray.length-1].focus();
8634 }, animationTimeout);
8637 currentBoardArray[currentBoardArray.length-1].focus();
8639 /* Update tabindecies to ensure keyboard navigation behaves correctly */
8640 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8646 scope.nextBoard = function() {
8647 ctrl.maxVisibleIndex += BoardStripConfig.boardsToScroll;
8648 ctrl.rectifyMaxVisibleBoards();
8649 ctrl.minVisibleIndex = ctrl.maxVisibleIndex - (BoardStripConfig.maxVisibleBoards-1);
8651 $timeout.cancel(oldTimeout);
8652 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": calculateAndGetBoardstripContainerAdjustment() + "px"});
8654 $timeout(function(){
8655 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8657 /* Remove tabindex from non-visible boards */
8658 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8660 if (!(scope.isNextBoard())) {
8662 currentBoardArray[currentBoardArray.length-1].focus();
8665 }, animationTimeout);
8667 scope.prevBoard = function() {
8669 ctrl.minVisibleIndex -= BoardStripConfig.boardsToScroll;
8670 if (ctrl.minVisibleIndex < 0) {
8671 ctrl.minVisibleIndex = 0;
8674 ctrl.maxVisibleIndex = ctrl.minVisibleIndex + BoardStripConfig.maxVisibleBoards-1;
8675 ctrl.rectifyMaxVisibleBoards();
8677 $timeout.cancel(oldTimeout);
8678 angular.element(element[0].querySelector(".boardstrip-container")).css({"left": calculateAndGetBoardstripContainerAdjustment() + "px"});
8680 $timeout(function(){
8681 var currentBoardArray = element[0].querySelectorAll('[att-board]');
8683 /* Remove tabindex from non-visible boards */
8684 updateBoardsTabIndex(currentBoardArray, ctrl.minVisibleIndex, ctrl.maxVisibleIndex);
8686 if (ctrl.minVisibleIndex === 0) {
8688 element[0].querySelector('div.boardstrip-item--add').focus();
8689 } catch (e) {} /* IE8 may throw exception */
8694 scope.isPrevBoard = function() {
8695 return (ctrl.minVisibleIndex > 0);
8697 scope.isNextBoard = function() {
8698 return (ctrl.getBoardsMasterArrayLength()-1 > ctrl.maxVisibleIndex);
8703 .directive('attAddBoard', ['BoardStripConfig', '$parse', '$timeout', function(BoardStripConfig, $parse, $timeout) {
8707 require: '^attBoardStrip',
8711 templateUrl: 'app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html',
8712 link: function(scope, element, attrs, ctrls) {
8713 var parentCtrl = ctrls;
8714 scope.addBoard = function() {
8715 if (attrs['onAddBoard'] ) {
8716 scope.onAddBoard = $parse(scope.onAddBoard);
8723 .directive('attBoardNavigation', ['keymap', 'events', function(keymap, events) {
8726 link: function(scope, elem) {
8728 var prevElem = keymap.KEY.LEFT;
8729 var nextElem = keymap.KEY.RIGHT;
8731 elem.bind('keydown', function (ev) {
8733 if (!(ev.keyCode)) {
8734 ev.keyCode = ev.which;
8737 switch (ev.keyCode) {
8739 events.preventDefault(ev);
8740 events.stopPropagation(ev);
8742 if (elem[0].nextElementSibling && parseInt(angular.element(elem[0].nextElementSibling).attr('tabindex')) >= 0) {
8743 angular.element(elem[0])[0].nextElementSibling.focus();
8746 var el = angular.element(elem[0])[0];
8748 if (el.nextSibling){
8749 el = el.nextSibling;
8754 } while (el && el.tagName !== 'LI');
8756 if (el.tagName && el.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0){
8763 events.preventDefault(ev);
8764 events.stopPropagation(ev);
8766 if (elem[0].previousElementSibling && parseInt(angular.element(elem[0].previousElementSibling).attr('tabindex')) >= 0) {
8767 angular.element(elem[0])[0].previousElementSibling.focus();
8770 var el1 = angular.element(elem[0])[0];
8772 if (el1.previousSibling){
8773 el1 = el1.previousSibling;
8778 } while (el1 && el1.tagName !== 'LI');
8780 if (el1.tagName && el1.tagName === 'LI' && parseInt(angular.element(el).attr('tabindex')) >= 0){
8793 angular.module('att.abs.breadCrumbs', [])
8794 .constant("classConstant",{
8795 "defaultClass" : "breadcrumbs__link",
8796 "activeClass": "breadcrumbs__link--active"
8798 .directive('attCrumb', ['classConstant', function(classConstant) {
8801 link: function(scope, elem, attr) {
8802 elem.addClass(classConstant.defaultClass);
8803 if(attr.attCrumb === 'active'){
8804 elem.addClass(classConstant.activeClass);
8806 if(!elem.hasClass('last')){
8807 elem.after('<i class="breadcrumbs__item"></i>');
8813 angular.module('att.abs.buttons', ['att.abs.position', 'att.abs.utilities'])
8814 .constant('btnConfig', {
8816 btnPrimaryClass: 'button--primary',
8817 btnSecondaryClass: 'button--secondary',
8818 btnDisabledClass: 'button--inactive',
8819 btnSmallClass: 'button--small'
8821 .directive('attButton', ['btnConfig', function (btnConfig) {
8824 link: function (scope, element, attrs) {
8825 element.addClass(btnConfig.btnClass);
8826 if (attrs.size === 'small') {
8827 element.addClass(btnConfig.btnSmallClass);
8829 attrs.$observe('btnType', function (value) {
8830 if (value === 'primary') {
8831 element.addClass(btnConfig.btnPrimaryClass);
8832 element.removeClass(btnConfig.btnSecondaryClass);
8833 element.removeClass(btnConfig.btnDisabledClass);
8834 element.removeAttr('disabled');
8835 } else if (value === 'secondary') {
8836 element.addClass(btnConfig.btnSecondaryClass);
8837 element.removeClass(btnConfig.btnPrimaryClass);
8838 element.removeClass(btnConfig.btnDisabledClass);
8839 element.removeAttr('disabled');
8840 } else if (value === 'disabled') {
8841 element.addClass(btnConfig.btnDisabledClass);
8842 element.removeClass(btnConfig.btnPrimaryClass);
8843 element.removeClass(btnConfig.btnSecondaryClass);
8844 element.attr('disabled', 'disabled');
8850 .directive('attButtonLoader', [function () {
8857 template: '<div ng-class="{\'button--loading\': size === \'large\',\'button--loading__small\': size === \'small\'}"><i></i><i class="second__loader"></i><i></i></div>',
8858 link: function (scope, element) {
8859 element.addClass('button button--inactive');
8863 .directive('attButtonHero', [function () {
8871 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>',
8872 link: function (scope, element) {
8873 element.addClass('button button--hero');
8874 element.attr("tabindex", "0");
8878 .directive('attBtnDropdown', ['$document', '$timeout', '$isElement', '$documentBind', 'keymap', 'events', function ($document, $timeout, $isElement, $documentBind, keymap, events) {
8882 type: "@dropdowntype"
8886 templateUrl: 'app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html',
8887 link: function (scope, element) {
8888 scope.isOpen = false;
8889 var currentIndex = -1;
8890 // Capture all the li elements after compilation
8891 var list = [], button = undefined;
8892 $timeout(function() {
8893 list = element.find('li');
8894 button = element.find('button')[0];
8896 var toggle = scope.toggle = function (show) {
8897 if (angular.isUndefined(show) || show === '') {
8898 scope.isOpen = !scope.isOpen;
8901 scope.isOpen = show;
8904 var selectNext = function() {
8905 if (currentIndex+1 < list.length) {
8907 list[currentIndex].focus();
8910 var selectPrev = function() {
8911 if (currentIndex-1 >= 0) {
8913 list[currentIndex].focus();
8916 element.bind("keydown", function($event) {
8917 var keyCode = $event.keyCode;
8918 if (keymap.isAllowedKey(keyCode) || keymap.isControl($event) || keymap.isFunctionKey($event)) {
8920 case keymap.KEY.ENTER:
8921 if (currentIndex > 0) {
8926 case keymap.KEY.ESC:
8932 case keymap.KEY.DOWN:
8935 events.preventDefault($event);
8936 events.stopPropagation($event);
8941 events.preventDefault($event);
8942 events.stopPropagation($event);
8947 } else if (keyCode === keymap.KEY.TAB) {
8953 var outsideClick = function (e) {
8954 var isElement = $isElement(angular.element(e.target), element, $document);
8958 for (var i = 0; i < list.length; i++) {
8959 angular.element(list[i]).removeClass('selected');
8965 $documentBind.click('isOpen', outsideClick, scope);
8969 angular.module('att.abs.checkbox', [])
8970 .constant("attCheckboxConfig", {
8971 activeClass : "att-checkbox--on",
8972 disabledClass : "att-checkbox--disabled"
8974 .directive('checkboxLimit', function () {
8982 require:'checkboxLimit',
8983 controller: ['$scope',function($scope)
8986 this.getMaxLimits=function(){
8987 return $scope.limit;
8989 this.setMaxLimits=function(value){
8992 this.maxCheckboxSelected=function(){
8993 $scope.maxSelected();
8996 link: function (scope, element, attribute, ctrl) {
8997 scope.$watch('checkboxLimit', function()
9000 for (var keys in scope.checkboxLimit) {
9001 if (scope.checkboxLimit.hasOwnProperty(keys) && scope.checkboxLimit[keys]) {
9002 countTrue = countTrue + 1;
9005 if(countTrue>=parseInt(scope.selectLimit)){
9006 ctrl.setMaxLimits(false);
9009 ctrl.setMaxLimits(true);
9015 .directive('attCheckbox', ['$compile', "attCheckboxConfig", function ($compile, attCheckboxConfig) {
9019 require: ['ngModel','^?checkboxLimit'],
9020 link: function (scope, element, attribute, ctrl) {
9021 var ngCtrl = ctrl[0];
9022 var checkboxLimitCtrl = ctrl[1];
9023 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);
9024 element.css({display:'none'});
9025 element.wrap(parentDiv);
9026 element.parent().append('<div class="att-checkbox__indicator"></div>');
9027 element.parent().attr("title", attribute.title);
9028 element.parent().attr("aria-label", attribute.title);
9029 element.parent().attr("id", attribute.id);
9030 element.removeAttr("id");
9031 //element.removeAttr("title");
9033 ngCtrl.$render = function () {
9034 var selected = ngCtrl.$modelValue ? true : false;
9035 element.parent().toggleClass(attCheckboxConfig.activeClass, selected);
9036 element.parent().attr("aria-checked", selected);
9040 scope.updateModel = function (evt) {
9041 if (!scope.disabled) {
9042 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? false : true);
9043 if(checkboxLimitCtrl && !(checkboxLimitCtrl.getMaxLimits())){
9044 if(!ngCtrl.$modelValue){
9048 checkboxLimitCtrl.maxCheckboxSelected();
9049 ngCtrl.$setViewValue(element.parent().hasClass(attCheckboxConfig.activeClass) ? true : false);
9056 evt.preventDefault();
9059 attribute.$observe('disabled', function(val) {
9060 scope.disabled = (val || val === "disabled" || val === "true");
9061 element.parent().toggleClass(attCheckboxConfig.disabledClass, scope.disabled);
9062 element.parent().attr("tabindex", scope.disabled ? "-1" : "0");
9067 .directive('checkboxGroup', ['$compile',function($compile) {
9071 checkboxGroupValue: "=?"
9074 link: function(scope, element, attribute){
9075 scope.checkboxState = 'none';
9076 if (scope.checkboxGroupValue === undefined) {
9077 scope.checkboxGroupValue = "indeterminate";
9079 element.css({display:'none'});
9080 element.wrap($compile('<div tabindex="0" role="checkbox" att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-checkbox"></div>')(scope));
9081 element.parent().append('<div class="att-checkbox__indicator"></div>');
9082 element.parent().attr("title", attribute.title);
9083 element.parent().attr("aria-label", attribute.title);
9084 scope.$watch('checkboxState', function(val) {
9085 if (val === 'all') {
9086 element.parent().addClass('att-checkbox--on');
9087 element.parent().removeClass('att-checkbox--indeterminate');
9088 element.parent().attr("aria-checked", true);
9090 else if (val === 'none') {
9091 element.parent().removeClass('att-checkbox--on');
9092 element.parent().removeClass('att-checkbox--indeterminate');
9093 element.parent().attr("aria-checked", false);
9095 else if (val === 'indeterminate') {
9096 element.parent().removeClass('att-checkbox--on');
9097 element.parent().addClass('att-checkbox--indeterminate');
9098 element.parent().attr("aria-checked", true);
9101 scope.updateModel = function(evt){
9102 if (element.parent().hasClass('att-checkbox--on')) {
9103 element.parent().removeClass('att-checkbox--on');
9104 for (var keys in scope.checkboxGroup) {
9105 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9106 scope.checkboxGroup[keys] = false;
9111 element.parent().addClass('att-checkbox--on');
9112 for (var key in scope.checkboxGroup) {
9113 if (scope.checkboxGroup.hasOwnProperty(key)) {
9114 scope.checkboxGroup[key] = true;
9118 evt.preventDefault();
9120 scope.$watch('checkboxGroupValue', function (value) {
9121 if (value===false) {
9122 element.parent().removeClass('att-checkbox--on');
9123 for (var keys in scope.checkboxGroup) {
9124 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9125 scope.checkboxGroup[keys] = false;
9129 else if (value === true){
9130 element.parent().addClass('att-checkbox--on');
9131 for (var key in scope.checkboxGroup) {
9132 if (scope.checkboxGroup.hasOwnProperty(key)) {
9133 scope.checkboxGroup[key] = true;
9138 scope.$watch('checkboxGroup', function(){
9142 for (var keys in scope.checkboxGroup) {
9143 if (scope.checkboxGroup.hasOwnProperty(keys)) {
9145 if (scope.checkboxGroup[keys]) {
9146 countTrue = countTrue + 1;
9148 else if (!scope.checkboxGroup[keys]) {
9149 countFalse = countFalse + 1;
9153 if (count === countTrue) {
9154 scope.checkboxState = "all";
9155 scope.checkboxGroupValue=true;
9157 else if (count === countFalse) {
9158 scope.checkboxState = "none";
9159 scope.checkboxGroupValue=false;
9162 scope.checkboxState = "indeterminate";
9163 scope.checkboxGroupValue="indeterminate";
9170 angular.module('att.abs.colorselector', [])
9171 .directive('colorSelectorWrapper', [function() {
9180 templateUrl: 'app/scripts/ng_js_att_tpls/colorselector/colorselector.html',
9181 link: function(scope) {
9182 scope.applycolor = {'background-color': scope.iconColor};
9183 scope.selectedcolor = function(iconColor) {
9184 scope.selected = iconColor;
9189 .directive('colorSelector', ['$compile', function($compile) {
9196 link: function(scope, element, attr) {
9197 element.removeAttr('color-selector');
9198 var colorTitle = attr.title;
9199 var wrapcont = angular.element('<color-selector-wrapper selected="ngModel" title="' + colorTitle + '" icon-color="{{colorSelector}}">' + element.prop('outerHTML') + '</color-selector-wrapper>');
9200 var newWrapcont = $compile(wrapcont)(scope);
9201 element.replaceWith(newWrapcont);
9205 angular.module('att.abs.datepicker', ['att.abs.position', 'att.abs.utilities'])
9207 .constant('datepickerConfig', {
9208 dateFormat: 'MM/dd/yyyy',
9210 monthFormat: 'MMMM',
9212 dayHeaderFormat: 'EEEE',
9213 dayTitleFormat: 'MMMM yyyy',
9214 disableWeekend: false,
9215 disableSunday: false,
9221 defaultText: 'Select from list'
9223 datepickerEvalAttributes: ['dateFormat', 'dayFormat', 'monthFormat', 'yearFormat', 'dayHeaderFormat', 'dayTitleFormat', 'disableWeekend', 'disableSunday', 'startingDay', 'mode'],
9224 datepickerWatchAttributes: ['min', 'max']
9227 .factory('datepickerService', ['datepickerConfig', 'dateFilter', function (datepickerConfig, dateFilter) {
9228 var setAttributes = function (attr, elem) {
9229 if (angular.isDefined(attr) && attr !== null && angular.isDefined(elem) && elem !== null) {
9230 var attributes = datepickerConfig.datepickerEvalAttributes.concat(datepickerConfig.datepickerWatchAttributes);
9231 for (var key in attr) {
9232 var val = attr[key];
9233 if (attributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9234 elem.attr(key.toSnakeCase(), key);
9240 var bindScope = function (attr, scope) {
9241 if (angular.isDefined(attr) && attr !== null && angular.isDefined(scope) && scope !== null) {
9242 var evalFunction = function (key, val) {
9243 scope[key] = scope.$parent.$eval(val);
9246 var watchFunction = function (key, val) {
9247 scope.$parent.$watch(val, function (value) {
9250 scope.$watch(key, function (value) {
9251 scope.$parent[val] = value;
9255 var evalAttributes = datepickerConfig.datepickerEvalAttributes;
9256 var watchAttributes = datepickerConfig.datepickerWatchAttributes;
9257 for (var key in attr) {
9258 var val = attr[key];
9259 if (evalAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9260 evalFunction(key, val);
9261 } else if (watchAttributes.indexOf(key) !== -1 && angular.isDefined(val)) {
9262 watchFunction(key, val);
9268 var validateDateString = function (dateString, dateFormat) {
9269 if (dateString && dateFormat) {
9271 if (dateFormat.indexOf('/') !== -1) {
9273 } else if (dateFormat.indexOf('-') !== -1) {
9275 } else if (dateFormat.indexOf('.') !== -1) {
9279 var dateStringArray = dateString.split(delimiter);
9280 var dateFormatArray = dateFormat.split(delimiter);
9281 if (dateStringArray.length !== dateFormatArray.length) {
9285 for (var i = 0; i < dateStringArray.length; i++) {
9286 dateStringArray[i] = dateStringArray[i].lPad(dateFormatArray[i].length, '0');
9288 var intermediateDateString = dateStringArray.join(delimiter);
9290 var actualDateString = dateFilter(new Date(intermediateDateString), dateFormat);
9291 return intermediateDateString === actualDateString;
9296 setAttributes: setAttributes,
9297 bindScope: bindScope,
9298 validateDateString: validateDateString
9302 .controller('DatepickerController', ['$scope', '$attrs', 'dateFilter', 'datepickerConfig', function($scope, $attrs, dateFilter, dtConfig) {
9304 date: getValue($attrs.dateFormat, dtConfig.dateFormat),
9305 day: getValue($attrs.dayFormat, dtConfig.dayFormat),
9306 month: getValue($attrs.monthFormat, dtConfig.monthFormat),
9307 year: getValue($attrs.yearFormat, dtConfig.yearFormat),
9308 dayHeader: getValue($attrs.dayHeaderFormat, dtConfig.dayHeaderFormat),
9309 dayTitle: getValue($attrs.dayTitleFormat, dtConfig.dayTitleFormat),
9310 disableWeekend: getValue($attrs.disableWeekend, dtConfig.disableWeekend),
9311 disableSunday: getValue($attrs.disableSunday, dtConfig.disableSunday)
9313 startingDay = getValue($attrs.startingDay, dtConfig.startingDay);
9314 $scope.mode = getValue($attrs.mode, dtConfig.mode);
9316 $scope.minDate = dtConfig.minDate ? $scope.resetTime(dtConfig.minDate) : null;
9317 $scope.maxDate = dtConfig.maxDate ? $scope.resetTime(dtConfig.maxDate) : null;
9319 function getValue(value, defaultValue) {
9320 return angular.isDefined(value) ? $scope.$parent.$eval(value) : defaultValue;
9323 function getDaysInMonth(year, month) {
9324 return new Date(year, month, 0).getDate();
9327 function getDates(startDate, n) {
9329 var current = startDate, i = 0;
9331 dates[i++] = new Date(current);
9332 current.setDate(current.getDate() + 1);
9337 var compare = this.compare = function(date1, date2) {
9338 return (new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate()));
9341 function isSelected(dt) {
9342 if (dt && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
9348 function isFromDate(dt) {
9349 if (dt && angular.isDate($scope.fromDate) && compare(dt, $scope.fromDate) === 0) {
9355 function isToDate(dt) {
9356 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && compare(dt, $scope.currentDate) === 0) {
9362 function isDateRange(dt) {
9363 if (dt && angular.isDate($scope.fromDate) && angular.isDate($scope.currentDate) && (compare(dt, $scope.fromDate) >= 0) && (compare(dt, $scope.currentDate) <= 0)) {
9369 function isWeekend(date) {
9370 if (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday") {
9376 function isToday(date) {
9377 if (compare(date, $scope.resetTime(new Date())) === 0) {
9382 function isFocused(date) {
9383 if (date && angular.isDate($scope.focusedDate) && compare(date, $scope.focusedDate) === 0) {
9389 var isDisabled = this.isDisabled = function(date) {
9390 if (format.disableWeekend === true && (dateFilter(date, format.dayHeader) === "Saturday" || dateFilter(date, format.dayHeader) === "Sunday")) {
9393 if (format.disableSunday === true && (dateFilter(date, format.dayHeader) === "Sunday")) {
9396 return (($scope.minDate && compare(date, $scope.minDate) < 0) || ($scope.maxDate && compare(date, $scope.maxDate) > 0));
9400 function isMinDateAvailable(startDate, endDate) {
9401 return ($scope.minDate && $scope.minDate.getTime() >= startDate.getTime()) && ($scope.minDate.getTime() <= endDate.getTime());
9404 function isMaxDateAvailable(startDate, endDate) {
9405 return ($scope.maxDate && $scope.maxDate.getTime() >= startDate.getTime()) && ($scope.maxDate.getTime() <= endDate.getTime());
9408 function getLabel(label) {
9412 pre: label.substr(0, 3),
9419 function makeDate(dateobj) {
9420 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};
9426 getVisibleDates: function(date, calendar) {
9427 var year = date.getFullYear(), month = date.getMonth(), firstDayOfMonth = new Date(year, month, 1), lastDayOfMonth = new Date(year, month+1, 0);
9428 var difference = startingDay - firstDayOfMonth.getDay(),
9429 numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference,
9430 firstDate = new Date(firstDayOfMonth), numDates = 0;
9432 if (numDisplayedFromPreviousMonth > 0) {
9433 firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
9434 numDates += numDisplayedFromPreviousMonth; // Previous
9436 numDates += getDaysInMonth(year, month + 1); // Current
9437 numDates += (7 - numDates % 7) % 7; // Next
9439 var days = getDates(firstDate, numDates), labels = [];
9440 for (var i = 0; i < numDates; i++) {
9441 var dt = new Date(days[i]);
9442 days[i] = makeDate({date:dt,
9443 formatDay:format.day,
9444 formatHeader:format.dayHeader,
9445 isFocused:isFocused(dt),
9446 isSelected:isSelected(dt),
9447 isFromDate:isFromDate(dt),
9448 isToDate:isToDate(dt),
9449 isDateRange:isDateRange(dt),
9450 oldMonth:(new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() < new Date(year, month, 1, 0, 0, 0).getTime()),
9451 newMonth:(new Date(dt.getFullYear(), dt.getMonth(), 1, 0, 0, 0).getTime() > new Date(year, month, 1, 0, 0, 0).getTime()),
9452 isDisabled:isDisabled(dt),
9453 isToday:isToday(dt),
9454 isWeakend:isWeekend(dt)});
9456 for (var j = 0; j < 7; j++) {
9457 labels[j] = getLabel(dateFilter(days[j].date, format.dayHeader));
9459 if (calendar === 'top') {
9460 $scope.disablePrevTop = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9461 $scope.disableNextTop = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9462 } else if (calendar === 'bottom') {
9463 $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9464 $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9466 $scope.disablePrevTop = $scope.disablePrevBottom = isMinDateAvailable(firstDayOfMonth, lastDayOfMonth);
9467 $scope.disableNextTop = $scope.disableNextBottom = isMaxDateAvailable(firstDayOfMonth, lastDayOfMonth);
9469 $scope.disablePrev = $scope.disablePrevTop || $scope.disablePrevBottom;
9470 $scope.disableNext = $scope.disableNextTop || $scope.disableNextBottom;
9471 return {objects: days, title: dateFilter(date, format.dayTitle), labels: labels};
9478 getVisibleDates: function(date) {
9479 var months = [], labels = [], year = date.getFullYear();
9480 for (var i = 0; i < 12; i++) {
9481 var dt = new Date(year,i,1);
9482 months[i] = makeDate({date:dt,
9483 formatDay:format.month,
9484 formatHeader:format.month,
9485 isFocused:isFocused(dt),
9486 isSelected:isSelected(dt),
9487 isFromDate:isFromDate(dt),
9488 isToDate:isToDate(dt),
9489 isDateRange:isDateRange(dt),
9492 isDisabled:isDisabled(dt),
9493 isToday:isToday(dt),
9496 return {objects: months, title: dateFilter(date, format.year), labels: labels};
9505 .directive('datepicker', ['$timeout', function ($timeout) {
9510 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepicker.html',
9512 currentDate: "=?current",
9515 require: 'datepicker',
9516 controller: 'DatepickerController',
9517 link: function(scope, element, attrs, ctrl) {
9518 var datepickerCtrl = ctrl;
9519 var selected, calendarSelected = false;
9522 scope.resetTime = function(date) {
9524 if (!isNaN(new Date(date))) {
9525 dt = new Date(date);
9526 if(scope.mode === 1){
9527 dt = new Date(dt.getFullYear(), dt.getMonth());
9529 dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9538 scope.$parent.$watch(attrs.min, function(value) {
9539 scope.minDate = value ? scope.resetTime(value) : null;
9544 scope.$parent.$watch(attrs.max, function(value) {
9545 scope.maxDate = value ? scope.resetTime(value) : null;
9550 // Split array into smaller arrays
9551 function split(arr, size) {
9553 while (arr.length > 0) {
9554 arrays.push(arr.splice(0, size));
9558 var moveMonth = function(selectedDate, direction) {
9559 var step = datepickerCtrl.modes[scope.mode].step;
9560 selectedDate.setDate(1);
9561 selectedDate.setMonth(selectedDate.getMonth() + direction * (step.months || 0));
9562 selectedDate.setFullYear(selectedDate.getFullYear() + direction * (step.years || 0));
9564 return selectedDate;
9567 function refill(date) {
9568 if (angular.isDate(date) && !isNaN(date)) {
9569 selected = new Date(date);
9572 selected = new Date();
9577 var selectedCalendar;
9578 if(scope.mode === 1){
9579 selected = new Date();
9580 selectedCalendar = moveMonth(angular.copy(selected), -1);
9582 selectedCalendar = angular.copy(selected);
9585 var currentMode = datepickerCtrl.modes[scope.mode];
9586 var currentData = currentMode.getVisibleDates(selectedCalendar, 'top');
9587 scope.currentRows = split(currentData.objects, currentMode.split);
9588 scope.currentTitle = currentData.title;
9589 scope.labels = currentData.labels || [];
9591 var nextData = currentMode.getVisibleDates(moveMonth(angular.copy(selectedCalendar), 1), 'bottom');
9592 scope.nextRows = split(nextData.objects, currentMode.split);
9593 scope.nextTitle = nextData.title;
9597 var selectCurrentDate = function(date) {
9598 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
9599 scope.currentDate = dt;
9602 var selectFromDate = function(date) {
9603 var dt = new Date(date.getFullYear(), date.getMonth(), date.getDate());
9604 scope.fromDate = dt;
9607 scope.select = function(date) {
9608 calendarSelected = true;
9610 if(!(angular.isDate(scope.fromDate) && angular.isDate(scope.currentDate))) {
9611 if(angular.isDate(scope.fromDate)) {
9612 selectCurrentDate(date);
9613 } else if(!angular.isDate(scope.fromDate)) {
9614 selectFromDate(date);
9618 selectCurrentDate(date);
9620 scope.focusedDate = date;
9623 var swapDate = function(fromDate, currentDate) {
9624 selectFromDate(currentDate);
9625 $timeout(function () {
9626 calendarSelected = true;
9627 scope.focusedDate = currentDate;
9628 selectCurrentDate(fromDate);
9632 scope.move = function(direction) {
9633 selected = moveMonth(angular.copy(selected), direction);
9637 scope.$watch('currentDate', function (value) {
9638 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
9639 scope.currentDate = null;
9643 if (attrs.from && !isNaN(value) && !isNaN(scope.fromDate) && datepickerCtrl.compare(value, scope.fromDate) < 0) {
9644 swapDate(scope.fromDate, value);
9648 if (calendarSelected) {
9650 calendarSelected = false;
9652 if (angular.isDefined(value) && value !== null) {
9658 scope.focusedDate = undefined;
9661 scope.$watch('fromDate', function (value) {
9662 if(angular.isDate(value) && !isNaN(value) && datepickerCtrl.isDisabled(value)) {
9663 scope.fromDate = null;
9667 if (!isNaN(scope.currentDate) && !isNaN(value) && datepickerCtrl.compare(scope.currentDate, value) < 0) {
9668 swapDate(value, scope.currentDate);
9671 if (calendarSelected) {
9673 calendarSelected = false;
9675 if (angular.isDefined(value) && value !== null) {
9682 scope.focusedDate = undefined;
9687 .directive('datepickerPopup', ['$document', 'datepickerService', '$isElement', '$documentBind', function($document, datepickerService, $isElement, $documentBind) {
9688 var link = function (scope, elem, attr) {
9689 datepickerService.bindScope(attr, scope);
9691 scope.isOpen = false;
9693 var toggle = scope.toggle = function (show) {
9694 if(show === true || show === false) {
9695 scope.isOpen = show;
9697 scope.isOpen = !scope.isOpen;
9701 scope.$watch('current', function () {
9705 var outsideClick = function (e) {
9706 var isElement = $isElement(angular.element(e.target), elem, $document);
9713 $documentBind.click('isOpen', outsideClick, scope);
9720 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html',
9724 compile: function (elem, attr) {
9725 var wrapperElement = elem.find('span').eq(1);
9726 wrapperElement.attr('current', 'current');
9727 datepickerService.setAttributes(attr, wrapperElement);
9734 .directive('attDatepicker', ['$log', function($log) {
9739 controller: ['$scope', '$element', '$attrs', '$compile', 'datepickerConfig', 'datepickerService', function($scope, $element, $attrs, $compile, datepickerConfig, datepickerService) {
9740 var dateFormatString = angular.isDefined($attrs.dateFormat) ? $scope.$parent.$eval($attrs.dateFormat) : datepickerConfig.dateFormat;
9741 var selectedDateMessage = '<div class="sr-focus hidden-spoken" tabindex="-1">the date you selected is {{$parent.current | date : \'' + dateFormatString + '\'}}</div>';
9743 $element.removeAttr('att-datepicker');
9744 $element.removeAttr('ng-model');
9745 $element.attr('ng-model', '$parent.current');
9746 $element.attr('aria-describedby', 'datepicker');
9747 $element.attr('format-date', dateFormatString);
9748 $element.attr('att-input-deny', '[^0-9\/-]');
9749 $element.attr('maxlength', 10);
9751 var wrapperElement = angular.element('<div></div>');
9752 wrapperElement.attr('datepicker-popup', '');
9753 wrapperElement.attr('current', 'current');
9755 datepickerService.setAttributes($attrs, wrapperElement);
9756 datepickerService.bindScope($attrs, $scope);
9758 wrapperElement.html('');
9759 wrapperElement.append($element.prop('outerHTML'));
9760 if (navigator.userAgent.match(/MSIE 8/) === null) {
9761 wrapperElement.append(selectedDateMessage);
9763 var elm = wrapperElement.prop('outerHTML');
9764 elm = $compile(elm)($scope);
9765 $element.replaceWith(elm);
9767 link: function(scope, elem, attr, ctrl) {
9769 // do nothing if no ng-model
9770 $log.error("ng-model is required.");
9774 scope.$watch('current', function(value) {
9775 ctrl.$setViewValue(value);
9777 ctrl.$render = function() {
9778 scope.current = ctrl.$viewValue;
9784 .directive('formatDate', ['dateFilter', 'datepickerService', function(dateFilter, datepickerService) {
9788 link: function(scope, elem, attr, ctrl) {
9789 var formatDate = "";
9790 attr.$observe('formatDate', function (value) {
9793 var dateToString = function(value) {
9795 ctrl.$setValidity('invalidDate', true);
9796 return dateFilter(value, formatDate);
9798 ctrl.$setValidity('invalidDate', false);
9802 var stringToDate = function(value) {
9803 if(datepickerService.validateDateString(value, formatDate)) {
9804 ctrl.$setValidity('invalidDate', true);
9805 return new Date(value);
9807 ctrl.$setValidity('invalidDate', false);
9811 ctrl.$formatters.unshift(dateToString);
9812 ctrl.$parsers.unshift(stringToDate);
9817 .directive('attDateFilter', ['$document', 'dateFilter', 'datepickerConfig', 'datepickerService', '$isElement', '$documentBind', function($document, dateFilter, datepickerConfig, datepickerService, $isElement, $documentBind) {
9819 var link = function (scope, elem, attr, ctrl) {
9820 datepickerService.bindScope(attr, scope);
9822 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
9823 scope.showDropdownList = false;
9824 scope.showCalendar = false;
9825 scope.applyButtonType = "disabled";
9827 scope.currentSelection = "";
9828 var dateFormatString = angular.isDefined(attr.dateFormat) ? scope.$parent.$eval(attr.dateFormat) : datepickerConfig.dateFormat;
9829 var inputChange = false;
9831 var setDropdownText = function(value) {
9836 var fromDateText = dateFormatString.toUpperCase();
9837 var currentDateText = dateFormatString.toUpperCase();
9839 if(!isNaN(new Date(scope.fromDate))) {
9840 fromDateText = dateFilter(scope.fromDate, dateFormatString);
9842 if(!isNaN(new Date(scope.currentDate))) {
9843 currentDateText = dateFilter(scope.currentDate, dateFormatString);
9846 if(value === 'Custom Single Date') {
9847 ctrl.$setValidity('invalidDate', true);
9848 scope.maxLength = 10;
9849 scope.selectedOption = currentDateText;
9850 } else if(value === 'Custom Range') {
9851 ctrl.$setValidity('invalidDate', true);
9852 ctrl.$setValidity('invalidDateRange', true);
9853 scope.maxLength = 21;
9854 scope.selectedOption = fromDateText + '-' + currentDateText;
9858 var clear = scope.clear = function(partial) {
9859 scope.fromDate = undefined;
9860 scope.currentDate = undefined;
9861 scope.applyButtonType = "disabled";
9863 ctrl.$setValidity('invalidDate', true);
9864 ctrl.$setValidity('invalidDateRange', true);
9865 setDropdownText(scope.currentSelection);
9869 var showCalendar = function() {
9870 scope.showCalendar = true;
9873 var hideCalendar = function() {
9874 scope.showCalendar = false;
9875 if(scope.currentSelection !== 'Custom Single Date' && scope.currentSelection !== 'Custom Range') {
9880 var showDropdown = scope.showDropdown = function (show) {
9881 if(show === true || show === false) {
9882 scope.showDropdownList = show;
9884 scope.showDropdownList = !scope.showDropdownList;
9887 if (!scope.showDropdownList) {
9888 scope.focusInputButton = true;
9891 if (scope.currentSelection === 'Custom Single Date' || scope.currentSelection === 'Custom Range') {
9897 scope.resetTime = function(date) {
9899 if (!isNaN(new Date(date))) {
9900 dt = new Date(date);
9904 return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
9907 scope.getDropdownText = function () {
9909 var dropdownText = scope.selectedOption;
9911 if (scope.currentSelection === 'Custom Single Date') {
9912 if (!isNaN(new Date(dropdownText)) && datepickerService.validateDateString(dropdownText, dateFormatString)) {
9913 ctrl.$setValidity('invalidDate', true);
9914 scope.fromDate = undefined;
9915 scope.currentDate = new Date(dropdownText);
9917 ctrl.$setValidity('invalidDate', false);
9920 } else if (scope.currentSelection === 'Custom Range') {
9921 if (dropdownText.indexOf('-') !== -1 && (dropdownText.split('-').length === 2 || dropdownText.split('-').length === 6)) {
9922 ctrl.$setValidity('invalidDateRange', true);
9923 var resultDropdownText = dropdownText.split('-');
9924 if (resultDropdownText.length === 2) {
9925 resultDropdownText[0] = resultDropdownText[0].trim();
9926 resultDropdownText[1] = resultDropdownText[1].trim();
9927 } else if (resultDropdownText.length === 6) {
9928 var firstDateString = resultDropdownText[0].trim() + '-' + resultDropdownText[1].trim() + '-' + resultDropdownText[2].trim();
9929 var secondDateString = resultDropdownText[3].trim() + '-' + resultDropdownText[4].trim() + '-' + resultDropdownText[5].trim();
9930 resultDropdownText[0] = firstDateString;
9931 resultDropdownText[1] = secondDateString;
9934 if (!isNaN(new Date(resultDropdownText[0])) && !isNaN(new Date(resultDropdownText[1])) && datepickerService.validateDateString(resultDropdownText[0], dateFormatString) && datepickerService.validateDateString(resultDropdownText[1], dateFormatString)) {
9935 ctrl.$setValidity('invalidDate', true);
9936 var fromDate = new Date(resultDropdownText[0]);
9937 var currentDate = new Date(resultDropdownText[1]);
9938 if(fromDate.getTime() < currentDate.getTime()) {
9939 ctrl.$setValidity('invalidDateRange', true);
9940 scope.fromDate = fromDate;
9941 scope.currentDate = currentDate;
9943 ctrl.$setValidity('invalidDateRange', false);
9947 ctrl.$setValidity('invalidDate', false);
9951 ctrl.$setValidity('invalidDateRange', false);
9957 scope.untrackInputChange = function() {
9958 inputChange = false;
9961 scope.selectAdvancedOption = function (value, notClearFlag) {
9962 scope.currentSelection = value;
9967 scope.$watch('currentDate', function(val) {
9968 if(!isNaN(new Date(val))) {
9969 scope.applyButtonType = "primary";
9970 setDropdownText(value);
9972 scope.focusApplyButton = true;
9976 scope.$watch('fromDate', function(val) {
9977 if(!isNaN(new Date(val))) {
9978 setDropdownText(value);
9981 if (value === 'Custom Single Date') {
9982 scope.focusSingleDateCalendar = true;
9983 } else if (value === 'Custom Range') {
9984 scope.focusRangeCalendar = true;
9988 scope.resetFocus = function () {
9989 scope.focusSingleDateCalendar = false;
9990 scope.focusRangeCalendar = false;
9991 scope.focusApplyButton = false;
9994 scope.apply = function() {
9995 scope.dateRange.selection = scope.selectedOption;
9996 if(!isNaN(new Date(scope.fromDate))) {
9997 scope.from = scope.fromDate;
9998 scope.dateRange.from = scope.fromDate;
10000 scope.from = undefined;
10001 scope.dateRange.from = undefined;
10003 if(!isNaN(new Date(scope.currentDate))) {
10004 scope.current = scope.currentDate;
10005 scope.dateRange.current = scope.currentDate;
10007 scope.current = undefined;
10008 scope.dateRange.current = undefined;
10014 scope.$watchCollection(function() {
10015 return scope.dateRange;
10016 }, function(value) {
10018 var finalDateRange = angular.copy(value);
10019 ctrl.$setViewValue(finalDateRange);
10023 ctrl.$render = function () {
10024 if (ctrl.$viewValue) {
10025 var inputRange = ctrl.$viewValue;
10026 scope.selectedOption = inputRange.selection;
10027 scope.fromDate = inputRange.from;
10028 scope.currentDate = inputRange.current;
10029 if (scope.fromDate !== undefined && scope.currentDate !== undefined) {
10030 scope.selectAdvancedOption('Custom Range', true);
10031 scope.dateRange.from = scope.fromDate;
10032 scope.dateRange.current = scope.currentDate;
10033 } else if (scope.currentDate !== undefined) {
10034 scope.selectAdvancedOption('Custom Single Date', true);
10035 scope.dateRange.from = undefined;
10036 scope.dateRange.current = scope.currentDate;
10041 scope.cancel = function() {
10042 scope.currentSelection = "";
10043 scope.selectedOption = datepickerConfig.dateFilter.defaultText;
10047 var outsideClick = function (e) {
10048 var isElement = $isElement(angular.element(e.target), elem, $document);
10054 $documentBind.click('showDropdownList', outsideClick, scope);
10061 current: "=?current"
10064 require: '?ngModel',
10066 templateUrl: 'app/scripts/ng_js_att_tpls/datepicker/dateFilter.html',
10067 controller:['$scope', '$element', '$attrs',function($scope){
10068 $scope.dateRange = {
10069 selection: undefined,
10073 this.selectOption = function (fromDate,toDate,caption) {
10074 $scope.selectedOption = caption;
10075 $scope.currentSelection =caption;
10076 $scope.dateRange.selection = caption;
10077 $scope.dateRange.current = $scope.resetTime(toDate);
10078 $scope.dateRange.from = $scope.resetTime(fromDate);
10079 $scope.showDropdown();
10081 $scope.checkCurrentSelection=this.checkCurrentSelection = function(value) {
10082 if(value === $scope.currentSelection) {
10088 compile: function(elem, attr) {
10089 var singleDateCalendar = elem.find('span').eq(4);
10090 var rangeCalendar = elem.find('span').eq(5);
10091 rangeCalendar.attr('from', 'fromDate');
10092 singleDateCalendar.attr('current', 'currentDate');
10093 rangeCalendar.attr('current', 'currentDate');
10094 datepickerService.setAttributes(attr, singleDateCalendar);
10095 datepickerService.setAttributes(attr, rangeCalendar);
10101 .directive('attDateFilterList',function(){
10105 fromDate:'=fromDate',
10107 caption:'=caption',
10108 disabled:'=disabled'
10110 require:'^attDateFilter',
10113 templateUrl:'app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html',
10114 link:function(scope,elem,attr,ctrl){
10115 scope.selectOption=function(fromDate,toDate,caption){
10116 ctrl.selectOption(fromDate,toDate,caption);
10118 scope.checkCurrentSelection=ctrl.checkCurrentSelection;
10122 angular.module('att.abs.devNotes', [])
10124 .directive('attDevNotes', function() {
10129 controller: function($scope){
10130 var panes = $scope.panes = [];
10131 $scope.select = function(pane)
10133 angular.forEach(panes, function(pane)
10135 pane.selected = false;
10137 pane.selected = true;
10139 this.addPane = function(pane) {
10140 if (panes.length === 0) {
10141 $scope.select(pane);
10147 '<ul class="tabs">' +
10148 '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
10149 '<a href="javascript:void(0)" ng-click="select(pane)">{{pane.title}}</a>' +
10152 '<div ng-transclude></div>'+
10158 .directive('pane', function() {
10160 require: '^attDevNotes',
10166 link: function(scope, element, attrs, tabsCtrl) {
10167 tabsCtrl.addPane(scope);
10170 '<div class="tab-pane" ng-class="{active: selected}">' +
10171 '<pre ng-class="{\'language-markup\':title==\'HTML\',\'language-javascript\':title==\'JavaScript\',\'language-json\':title==\'JSON\'}" class=" line-numbers">' +
10172 '<code ng-transclude></code>' +
10179 angular.module('att.abs.dividerLines', [])
10180 .directive('attDividerLines', [function()
10184 attDividerLines: '@'
10188 templateUrl: 'app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html',
10189 link: function(scope, element, attribute)
10191 scope.lightContainer = attribute.attDividerLines;
10196 angular.module('att.abs.dragdrop', [])
10197 .directive('attFileDrop', ['$parse', function($parse) {
10205 controller: ['$scope', '$attrs', function($scope, $attrs){
10206 if($attrs.attFileDrop!==""){
10207 $scope.onDrop=$scope.attFileDrop;
10209 this.onDrop = $scope.onDrop;
10211 link: function(scope, element) {
10212 element.addClass('dragdrop');
10216 if(e.originalEvent){
10217 e.dataTransfer = e.originalEvent.dataTransfer;
10219 e.dataTransfer.dropEffect = 'move';
10220 // allows us to drop
10221 if (e.preventDefault) {
10222 e.preventDefault();
10224 element.addClass('dragdrop-over');
10231 // allows us to drop
10232 if (e.preventDefault) {
10233 e.preventDefault();
10235 element.addClass('dragdrop-over');
10242 element.removeClass('dragdrop-over');
10249 // Stops some browsers from redirecting.
10250 if(e.preventDefault) {
10251 e.preventDefault();
10253 if (e.stopPropagation) {
10254 e.stopPropagation();
10256 if(e.originalEvent){
10257 e.dataTransfer = e.originalEvent.dataTransfer;
10259 element.removeClass('dragdrop-over');
10260 if(e.dataTransfer.files && e.dataTransfer.files.length > 0){
10261 scope.fileModel = e.dataTransfer.files[0];
10263 if(typeof scope.onDrop === "function"){
10264 scope.onDrop = $parse(scope.onDrop);
10274 .directive('attFileLink', [ function() {
10277 require: '^?attFileDrop',
10280 templateUrl: 'app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html',
10283 onFileSelect : '&',
10286 controller: ['$scope', '$parse', function($scope, $parse){
10287 this.setFileModel= function(fileModel){
10288 if($scope.takeFileModelFromParent){
10289 $scope.$parent.fileModel = fileModel;
10290 $scope.$parent.$apply();
10293 $scope.fileModel = fileModel;
10297 this.callbackFunction= function(){
10298 if(typeof $scope.onFileSelect === "function"){
10299 $scope.onFileSelect = $parse($scope.onFileSelect);
10300 $scope.onFileSelect();
10305 link: function(scope, element, attr, attFileDropCtrl) {
10306 scope.takeFileModelFromParent = false;
10307 if(!(attr.fileModel) && attFileDropCtrl){
10308 scope.takeFileModelFromParent = true;
10310 if(attr.attFileLink!==""){
10311 scope.onFileSelect=scope.attFileLink;
10313 else if(!(attr.onFileSelect) && attFileDropCtrl){
10314 scope.onFileSelect = attFileDropCtrl.onDrop;
10319 .directive('attFileChange', ['$log','$rootScope',function($log,$rootScope) {
10322 require: '^attFileLink',
10323 link: function(scope, element, attr, attFileLinkCtrl) {
10324 element.bind('change',changeFileModel);
10325 function changeFileModel(e) {
10326 if (e.target.files && e.target.files.length > 0) {
10327 attFileLinkCtrl.setFileModel(e.target.files[0]);
10328 attFileLinkCtrl.callbackFunction();
10331 var strFileName = e.target.value;
10333 var objFSO = new ActiveXObject("Scripting.FileSystemObject");
10334 attFileLinkCtrl.setFileModel(objFSO.getFile(strFileName));
10335 attFileLinkCtrl.callbackFunction();
10338 var errMsg = "Error: Please follow the guidelines of Drag and Drop component on Sandbox demo page.";
10339 $log.error(errMsg);
10340 $rootScope.$broadcast('att-file-link-failure', errMsg);
10347 angular.module("att.abs.drawer", ['att.abs.utilities'])
10348 .directive('attDrawer', ['$document', '$timeout', 'DOMHelper', function ($document, $timeout, DOMHelper) {
10355 drawerAutoClose: "&?"
10357 template: '<div><div class="att-drawer" ng-transclude></div><div ng-class="{\'drawer-backdrop\':drawerOpen}"></div></div>',
10358 link: function ($scope, element, attrs) {
10360 // First Element in Drawer component
10361 var firstElement = undefined;
10362 // Element drawer is toggled from
10363 var drawerLaunchingElement = undefined;
10364 // Override default parameters
10365 param.side = attrs.drawerSlide || 'top';
10366 param.speed = attrs.drawerSpeed || '0.25';
10367 param.size = attrs.drawerSize || '300px';
10368 param.zindex = attrs.drawerZindex || 1000;
10369 param.className = attrs.drawerClass || 'att-drawer';
10370 var slider = element.eq(0).children()[0];
10371 var content = angular.element(slider).children()[0];
10372 slider.className = param.className;
10374 slider.style.transitionDuration = param.speed + 's';
10375 slider.style.webkitTransitionDuration = param.speed + 's';
10376 slider.style.zIndex = param.zindex;
10377 slider.style.position = 'fixed';
10378 slider.style.width = 0;
10379 slider.style.height = 0;
10380 slider.style.transitionProperty = 'width, height';
10381 if(param.side==='right' || param.side==='left'){
10382 slider.style.height = attrs.drawerCustomHeight || '100%';
10383 slider.style.top = attrs.drawerCustomTop || '0px';
10384 slider.style.bottom = attrs.drawerCustomBottom || '0px';
10385 slider.style.right = attrs.drawerCustomRight || '0px';
10387 else if(param.side==='top' || param.side==='bottom'){
10388 slider.style.width = attrs.drawerCustomWidth || '100%';
10389 slider.style.left = attrs.drawerCustomLeft || '0px';
10390 slider.style.top = attrs.drawerCustomTop || '0px';
10391 slider.style.right = attrs.drawerCustomRight || '0px';
10393 $timeout(function() {
10394 firstElement = DOMHelper.firstTabableElement(element[0]);
10397 function drawerClose(slider, param) {
10398 if (slider && slider.style.width !== 0 && slider.style.height !== 0){
10399 content.style.display = 'none';
10400 if(param.side==='right' || param.side==='left'){
10401 slider.style.width = '0px';
10403 else if(param.side==='top' || param.side==='bottom'){
10404 slider.style.height = '0px';
10407 $scope.drawerOpen = false;
10409 if (angular.isDefined(drawerLaunchingElement) && drawerLaunchingElement != null) {
10410 drawerLaunchingElement.focus();
10414 function drawerOpen(slider, param) {
10415 // Before opening drawer, find the focused element
10416 drawerLaunchingElement = document.activeElement;
10417 if (slider.style.width !== 0 && slider.style.height !== 0){
10418 if(param.side==='right' || param.side==='left'){
10419 slider.style.width = param.size;
10421 else if(param.side==='top' || param.side==='bottom'){
10422 slider.style.height = param.size;
10424 $timeout(function() {
10425 content.style.display = 'block';
10427 if (angular.isDefined(firstElement) && firstElement != null) {
10428 firstElement.focus();
10430 },(param.speed * 1000));
10433 function isFunction(functionToCheck) {
10435 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
10440 if(attrs.drawerSize) {
10441 $scope.$watch(function() {
10442 return attrs.drawerSize;
10443 }, function(newVal) {
10444 param.size = newVal;
10445 if($scope.drawerOpen) {
10446 drawerOpen(slider,param);
10450 $scope.$watch("drawerOpen", function (value){
10453 drawerOpen(slider,param);
10456 drawerClose(slider,param);
10459 // close panel on location change
10460 if($scope.drawerAutoClose) {
10461 $scope.$on("$locationChangeStart", function(){
10462 drawerClose(slider, param);
10463 if(isFunction($scope.drawerAutoClose)) {
10464 $scope.drawerAutoClose();
10467 $scope.$on("$stateChangeStart", function(){
10468 drawerClose(slider, param);
10469 if(isFunction($scope.drawerAutoClose)) {
10470 $scope.drawerAutoClose();
10478 angular.module('att.abs.message', [])
10480 .directive('attMessages', [function() {
10486 controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
10487 $scope.messageScope = [];
10488 this.registerScope = function(messageScope) {
10489 $scope.messageScope.push(messageScope);
10491 $scope.$parent.$watchCollection($attrs['for'], function(errors) {
10492 for (var key in errors) {
10494 $scope.error = key;
10497 $scope.error = null;
10500 for (var i = 0; i < $scope.messageScope.length; i++) {
10501 if($scope.messageScope[i].when === $scope.error) {
10502 $scope.messageScope[i].show();
10503 $scope.setMessageType($scope.messageScope[i].type);
10505 $scope.messageScope[i].hide();
10508 if($scope.error === null) {
10509 $scope.setMessageType(null);
10512 $scope.setMessageType = this.setMessageType = function(messageType) {
10513 if($attrs.messageType) {
10514 $scope.messageType = messageType;
10521 .directive('attMessage', [function() {
10525 require: '^attMessages',
10526 link: function(scope, elem, attr, ctrl) {
10527 ctrl.registerScope(scope);
10528 scope.when = attr.when || attr.attMessage;
10529 scope.type = attr.type;
10530 scope.show = function() {
10531 elem.css({display: 'block'});
10533 scope.hide = function() {
10534 elem.css({display: 'none'});
10541 angular.module('att.abs.formField', ['att.abs.message', 'att.abs.utilities'])
10542 .directive('attFormField', [function() {
10546 controller:function() {
10548 link: function(scope, elem, attr) {
10549 elem.wrap('<div class="form-field"></div>');
10550 elem.parent().append('<label class="form-field__label">' + attr.placeholder || attr.attFormField + '</label>');
10551 elem.wrap('<div class="form-field-input-container"></div>');
10553 elem.bind('keyup', function() {
10554 if (this.value !== '') {
10555 elem.parent().parent().find('label').addClass('form-field__label--show').removeClass('form-field__label--hide');
10557 elem.parent().parent().find('label').addClass('form-field__label--hide').removeClass('form-field__label--show');
10561 elem.bind('blur', function() {
10562 if (this.value === '') {
10563 elem.parent().parent().find('label').removeClass('form-field__label--hide');
10569 .directive('attFormFieldValidation', ['$compile', '$log', function($compile, $log) {
10574 require: ['?ngModel', '?attFormField'],
10575 link: function(scope, elem, attr, ctrl) {
10576 var ngCtrl = ctrl[0];
10577 var attFormFieldCtrl = ctrl[1];
10580 $log.error("att-form-field-validation :: ng-model directive is required.");
10583 if (!attFormFieldCtrl) {
10584 $log.error("att-form-field-validation :: att-form-field directive is required.");
10588 elem.parent().append($compile(angular.element('<i class="icon-info-alert error" ng-show="valid===false"> </i>'))(scope));
10589 elem.parent().append($compile(angular.element('<i class="icon-info-success success" ng-show="valid===true"> </i>'))(scope));
10591 scope.$watch('valid', function(value) {
10593 elem.parent().parent().addClass('success');
10594 } else if (value === false) {
10595 elem.parent().parent().addClass('error');
10597 elem.parent().parent().removeClass('success').removeClass('error');
10601 elem.bind('keyup', function() {
10602 if (ngCtrl.$valid) {
10603 scope.valid = true;
10604 } else if (ngCtrl.$invalid) {
10605 scope.valid = false;
10614 .directive('attFormFieldValidationAlert', ['$timeout', function($timeout) {
10622 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html',
10623 link: function(scope, elem, attr, ctrl) {
10624 scope.showLabel = false;
10625 scope.hideLabel = false;
10626 scope.errorMessage = false;
10627 scope.warningMessage = false;
10628 var checkMessageType = function() {
10629 var messageType = scope.messageType;
10630 if (messageType === 'error') {
10631 scope.errorMessage = true;
10632 scope.warningMessage = false;
10633 } else if (messageType === 'warning') {
10634 scope.errorMessage = false;
10635 scope.warningMessage = true;
10637 scope.errorMessage = false;
10638 scope.warningMessage = false;
10641 var oldIE = navigator.userAgent.toLowerCase().indexOf('msie 8.0') !== -1;
10642 elem.find('label').text(elem.find('input').attr('placeholder'));
10643 elem.find('input').bind('keyup', function() {
10644 if (this.value !== '') {
10645 scope.showLabel = true;
10646 scope.hideLabel = false;
10648 elem.find('label').css({top: '-20px'});
10651 scope.showLabel = false;
10652 scope.hideLabel = true;
10654 elem.find('label').css({top: '0px'});
10657 checkMessageType();
10661 elem.find('input').bind('blur', function() {
10662 if (this.value === '') {
10663 scope.showLabel = false;
10664 scope.hideLabel = false;
10668 $timeout(function() {
10669 checkMessageType();
10674 .constant("CoreFormsUiConfig", {
10675 phoneMask: '(___) ___-____'
10677 .directive('attPhoneMask', ['$parse', 'CoreFormsUiConfig', function($parse, CoreFormsUiConfig) {
10679 require: 'ngModel',
10683 link: function(scope, iElement, iAttrs, ctrl) {
10684 var B = navigator.userAgent.toLowerCase(), C = B.indexOf("android") > -1,
10685 oldIE = B.indexOf('msie 8.0') !== -1;;
10687 var validPhoneNumber = false;
10692 A = CoreFormsUiConfig.phoneMask;
10694 iElement.attr("maxlength", A.length);
10695 var checkValidity = function(unmaskedValue) {
10697 if (unmaskedValue){
10698 valid = (unmaskedValue.length === 10);}
10699 ctrl.$setValidity('invalidPhoneNumber', validPhoneNumber);
10700 ctrl.$setValidity('mask', valid);
10704 var handleKeyup = function() {
10705 var E,D = ctrl.$modelValue;
10713 L = D.substring(0, A.length);
10714 K = D.replace(/[^0-9]/g, "").split("");
10715 for (E = 0; E < I; E++) {
10716 J.push(G[E] === "_" ? K.shift() : G[E]);
10717 if (K.length === 0) {
10724 ctrl.$setViewValue(D);
10730 // since we are only allowing 0-9, why even let the keypress go forward?
10731 // also added in delete... in case they want to delete :)
10732 var handlePress = function(e) {
10734 if ((e.which < 48 || e.which > 57) && (e.which < 96 || e.which > 105)) {
10735 if (e.which !== 8 && e.which !== 9 && e.which !== 46 && e.which !== 13 && e.which !== 37 && e.which !== 39 &&
10737 (e.ctrlKey !== true && (e.which !== '118' || e.which !== '86'))&&
10739 (e.ctrlKey !== true && (e.which !== '99' || e.which !== '67'))&&
10741 (e.ctrlKey !== true && (e.which !== '120' || e.which !== '88')))
10743 e.preventDefault ? e.preventDefault() : e.returnValue = false;
10744 iElement.attr("aria-label","Only numbers are allowed");
10745 validPhoneNumber = false;
10748 iElement.removeAttr("aria-label");
10749 validPhoneNumber = true;
10754 // i moved this out because i thought i might need focus as well..
10755 // to handle setting the model as the view changes
10756 var parser = function(fromViewValue) {
10757 var letters = /^[A-Za-z]+$/;
10758 var numbers = /^[0-9]+$/;
10759 if(fromViewValue.match(letters))
10760 {validPhoneNumber = false;}
10761 if(fromViewValue.match(numbers))
10762 {validPhoneNumber = true;}
10764 if (fromViewValue && fromViewValue.length > 0) {
10765 clean = fromViewValue.replace(/[^0-9]/g, '');
10767 checkValidity(clean);
10771 //to handle reading the model and formatting it
10772 var formatter = function(fromModelView) {
10774 checkValidity(fromModelView);
10775 if (fromModelView){
10776 input = handleKeyup();}
10779 ctrl.$parsers.push(parser);
10780 ctrl.$formatters.push(formatter);
10781 iElement.bind('keyup', handleKeyup);
10782 iElement.bind('keydown', handlePress);
10783 iElement.bind('input', function(e){
10790 .constant('validationTypeInt', {
10791 validationNum: {'number':'1','text':'2','email':'3'}
10793 .directive('attFormFieldPrv', [ 'keyMapAc', 'validationTypeInt', function( keyMapAc, validationTypeInt ) {
10797 controller:['$scope', function($scope) {
10798 this.showHideErrorMessage = function ( booleanValue ){
10799 if( $scope.$$prevSibling != null && angular.isDefined( $scope.$$prevSibling )
10800 && angular.isDefined( $scope.$$prevSibling.hideErrorMsg ) ){
10801 $scope.$$prevSibling.hideErrorMsg = booleanValue;
10805 this.findAllowedCharactor = function( keyCode ){
10806 var keyMapSc = keyMapAc.keys;
10807 if( angular.isDefined( $scope.allowedSpecialCharacters )
10808 && angular.isDefined( $scope.allowedSpecialCharacters.length )
10809 && $scope.allowedSpecialCharacters.length > 0 ){
10810 var allowedCharList = $scope.allowedSpecialCharacters;
10811 var charFound = false;
10812 for( var i=0 ; i < allowedCharList.length ; i++){
10813 if( allowedCharList[i] === keyMapSc[keyCode] ){
10823 this.validateText = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10824 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10825 var expAlphanumeric = /^[a-zA-Z0-9]*$/i;
10826 return expAlphanumeric.test( validationInput );
10828 var expAlphanumericSpecialChar = '^[a-zA-Z0-9' + outputSpecialChars + ']*$';
10829 var regularExp = new RegExp( expAlphanumericSpecialChar, 'i' );
10830 return regularExp.test( validationInput );
10833 this.validateNumber = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10834 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10835 var expNumber = /^[0-9\.]+$/;
10836 return expNumber.test( validationInput );
10838 var expNumberSpecial = '^[0-9\.' + outputSpecialChars + ']*$';
10839 var regularExp = new RegExp( expNumberSpecial, 'i' );
10840 return regularExp.test( validationInput );
10843 this.validateEmail = function( validationType, allowedChars, validationInput, outputSpecialChars ){
10844 if( angular.isDefined( allowedChars ) && allowedChars.length === 0 ){
10845 var expEmail = /(([a-zA-Z0-9\-?\.?]+)@(([a-zA-Z0-9\-_]+\.)+)([a-z]{2,3}))+$/;
10846 return expEmail.test( validationInput );
10848 var expEmailSpecial = '(([a-z' + outputSpecialChars + 'A-Z0-9\-?\.?]+)@(([a-z'
10849 + outputSpecialChars + 'A-Z0-9\-_]+\.)+)([' + outputSpecialChars + 'a-z]{2,3}))+$';
10850 var regularExp = new RegExp( expEmailSpecial, 'i' );
10851 return regularExp.test( validationInput );
10854 this.validateInput = function( validationType, allowedChars, validationInput ){
10855 var outputSpecialChars = '';
10856 var result = false;
10857 if( angular.isDefined( allowedChars ) && angular.isDefined( allowedChars.length )
10858 && allowedChars.length > 0 ){
10859 for( var i = 0; i < allowedChars.length; i++){
10860 outputSpecialChars += '\\'+allowedChars[i];
10863 switch ( validationTypeInt.validationNum[ validationType ] ) {
10864 case validationTypeInt.validationNum["text"]:
10865 result = this.validateText( validationType, allowedChars, validationInput, outputSpecialChars );
10867 case validationTypeInt.validationNum["number"]:
10868 result = this.validateNumber( validationType, allowedChars, validationInput, outputSpecialChars );
10870 case validationTypeInt.validationNum["email"]:
10871 result = this.validateEmail( validationType, allowedChars, validationInput, outputSpecialChars );
10879 link: function(scope, elem, attr ) {
10880 elem.parent().prepend('<label class="form-field__label">' + attr.placeholder + '</label>');
10881 elem.wrap('<div class="form-field-input-container"></div>');
10882 elem.parent().parent().find('label').addClass('form-field__label--show');
10886 .directive('attFormFieldValidationPrv', [ 'keyMapAc','validationTypeInt' , function( keyMapAc, validationTypeInt ) {
10890 validationType: '=',
10894 require: ['?ngModel', '^attFormFieldPrv'],
10895 link: function(scope, elem, attr, ctrl) {
10896 var attFormFieldCtrl = ctrl[1];
10897 elem.bind('keyup', function() {
10898 /* email validation has tobe done on keyup */
10899 if( attFormFieldCtrl.validateInput( scope.validationType, scope.allowedChars, elem[0].value ) ){
10900 attFormFieldCtrl.showHideErrorMessage(false);
10903 attFormFieldCtrl.showHideErrorMessage(true);
10906 var keyMapSc = keyMapAc.keyRange;
10907 var allowedKeys = keyMapAc.allowedKeys;
10908 var validateTextCode = function( charFound,event ){
10909 var resultOne = (event.which < keyMapSc['startNum'] || event.which > keyMapSc['endNum'] );
10910 var resultTwo = (event.which < keyMapSc['startCapitalLetters'] || event.which > keyMapSc['endCapitalLetters'] );
10911 var resultThree = (event.which < keyMapSc['startSmallLetters'] || event.which > keyMapSc['endSmallLetters'] );
10912 var result = ( resultOne && resultTwo && resultThree );
10913 return ( result && ( !charFound ) );
10915 var validateNumberCode = function( charFound,event ){
10916 return ( ( event.which < keyMapSc['startNum'] || event.which > keyMapSc['endNum'] ) && ( !charFound ) );
10918 var validateEmailCode = function( charFound,event ){
10919 var condOne = String.fromCharCode( event.which ) !== '-' && String.fromCharCode( event.which ) !== '_';
10920 var condTwo = String.fromCharCode( event.which ) !== '@' && String.fromCharCode( event.which ) !== '.';
10921 var ifAllowedChars = condOne && condTwo;
10922 var ifCharRange = validateTextCode( charFound,event );
10923 return ( ( !charFound ) && ifAllowedChars && ifCharRange );
10925 var validateSwitch = function( validationTypeSwitch, charFound, event ){
10926 switch ( validationTypeSwitch ) {
10927 case validationTypeInt.validationNum["text"]:
10928 /* 97-122 65-90 48-57 if keyCode is outside range of alphanumeric chars and not found in list then prevent */
10929 if( validateTextCode( charFound, event ) ){
10933 case validationTypeInt.validationNum["number"]:
10934 /* if key code is outside number range and notfound then prevent */
10935 if( validateNumberCode( charFound, event ) ){
10939 case validationTypeInt.validationNum["email"]:
10940 /* if keyCode is outside charactor/number range and not _-@. then prevent */
10941 if( validateEmailCode( charFound, event ) ){
10950 /* key stroke prevention has to be happen on numeric and alphanumeric fields */
10951 elem.bind('keypress', function( event ){
10952 if(!(event.which)){
10954 event.which = event.keyCode;
10956 else if(event.charCode){
10957 event.which = event.charCode;
10960 var charFound = attFormFieldCtrl.findAllowedCharactor( event.which );
10961 var insideCondOne = ( angular.isDefined( scope.validationType ) && scope.validationType !== '');
10962 var insideCondTwo = ( event.which !== allowedKeys['TAB']
10963 && event.which !== allowedKeys['BACKSPACE'] && event.which!== allowedKeys['DELETE'] );
10964 var goInside = insideCondOne && insideCondTwo;
10965 if( goInside && validateSwitch( validationTypeInt.validationNum[ scope.validationType ], charFound, event ) ){
10966 event.preventDefault();
10972 .directive('attFormFieldValidationAlertPrv', [ function() {
10975 scope : { errorMessage : '=' },
10977 templateUrl: 'app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html',
10978 link: function( scope ) {
10979 scope.errorMessage = scope.errorMessage;
10980 if( angular.isDefined( scope.$parent.hideErrorMsg ) ){
10981 scope.hideErrorMsg = scope.$parent.hideErrorMsg;
10984 scope.hideErrorMsg = true;
10989 //Credit card validation directives starts here
10990 .factory('Cards', [function() {
10991 var defaultFormat = /(\d{1,4})/g;
10992 var defaultInputFormat = /(?:^|\s)(\d{4})$/;
10996 pattern: /^(6011|65|64[4-9]|622)/,
10997 format: defaultFormat,
10998 inputFormat: defaultInputFormat,
11001 cvcSecurityImg: 'visaI',
11007 pattern: /^5[1-5]/,
11008 format: defaultFormat,
11009 inputFormat: defaultInputFormat,
11012 cvcSecurityImg: 'visaI',
11019 format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
11020 inputFormat: /^(\d{4}|\d{4}\s\d{6})$/,
11023 cvcSecurityImg: 'amexI',
11030 format: defaultFormat,
11031 inputFormat: defaultInputFormat,
11034 cvcSecurityImg: 'visaI',
11040 var _fromNumber = function(num) {
11043 num = (num + '').replace(/\D/g, '');
11045 for (i = 0, len = cards.length; i < len; i++) {
11049 if (card.pattern.test(num)) {
11056 var _fromType = function(type) {
11059 for (i = 0, len = cards.length; i < len; i++) {
11063 if (card.type === type) {
11071 fromNumber: function(val) {
11072 return _fromNumber(val);
11074 fromType: function(val) {
11075 return _fromType(val);
11077 defaultFormat: function() {
11078 return defaultFormat;
11080 defaultInputFormat: function() {
11081 return defaultInputFormat;
11086 .factory('_Validate', ['Cards', '$parse', function(Cards, $parse) {
11087 var __indexOf = [].indexOf || function(item)
11089 for (var i = 0, l = this.length; i < l; i++)
11091 if (i in this && this[i] === item)
11099 var _luhnCheck = function(num) {
11100 var digit, digits, odd, sum, i, len;
11104 digits = (num + '').split('').reverse();
11106 for (i = 0, len = digits.length; i < len; i++) {
11109 digit = parseInt(digit, 10);
11111 if ((odd = !odd)) {
11123 return sum % 10 === 0;
11126 var _validators = {};
11128 _validators['cvc'] = function(cvc, ctrl, scope, attr) {
11131 // valid if empty - let ng-required handle empty
11132 if ((angular.isUndefined(cvc)) || (cvc === null) || (cvc.length === 0))
11137 if (!/^\d+$/.test(cvc)) {
11142 if (attr.paymentsTypeModel) {
11143 var typeModel = $parse(attr.paymentsTypeModel);
11144 type = typeModel(scope);
11149 ref1 = Cards.fromType(type);
11150 return (ref = cvc.length, __indexOf.call((ref1 !== null) ? ref1.cvcLength : void 0, ref)) >= 0;
11154 return cvc.length >= 3 && cvc.length <= 4;
11157 _validators['zip'] = function(zip, ctrl, scope, attr) {
11160 // valid if empty - let ng-required handle empty
11161 if ((angular.isUndefined(zip)) || (zip === null) || (zip.length === 0))
11166 if (!/^\d+$/.test(zip)) {
11171 if (attr.paymentsTypeModel) {
11172 var typeModel = $parse(attr.paymentsTypeModel);
11173 type = typeModel(scope);
11177 ref1 = Cards.fromType(type);
11178 return (ref = zip.length, __indexOf.call(ref1 !== null ? ref1.zipLength : void 0, ref)) >= 0;
11182 return zip.length < 6;
11185 _validators['card'] = function(num, ctrl, scope, attr) {
11186 var card, ref, typeModel;
11188 if (attr.paymentsTypeModel) {
11189 typeModel = $parse(attr.paymentsTypeModel);
11192 var clearCard = function() {
11194 typeModel.assign(scope, null);
11199 // valid if empty - let ng-required handle empty
11200 if ((angular.isUndefined(num)) || (num === null) || (num.length === 0)) {
11205 num = (num + '').replace(/\s+|-/g, '');
11207 if (!/^\d+$/.test(num)) {
11212 card = Cards.fromNumber(num);
11217 ctrl.$card = angular.copy(card);
11220 typeModel.assign(scope, card.type);
11223 ret = (ref = num.length, __indexOf.call(card.length, ref) >= 0) && (card.luhn === false || _luhnCheck(num));
11226 return function(type, val, ctrl, scope, attr) {
11227 if (!_validators[type]) {
11229 types = Object.keys(_validators);
11231 errstr = 'Unknown type for validation: "' + type + '". ';
11232 errstr += 'Should be one of: "' + types.join('", "') + '"';
11236 return _validators[type](val, ctrl, scope, attr);
11239 .factory('_ValidateWatch', ['_Validate', function(_Validate) {
11241 var _validatorWatches = {};
11243 _validatorWatches['cvc'] = function(type, ctrl, scope, attr) {
11244 if (attr.paymentsTypeModel) {
11245 scope.$watch(attr.paymentsTypeModel, function(newVal, oldVal) {
11246 if (newVal !== oldVal) {
11247 var valid = _Validate(type, ctrl.$modelValue, ctrl, scope, attr);
11248 ctrl.$setValidity(type, valid);
11253 _validatorWatches['zip'] = function(type, ctrl, scope, attr) {
11254 if (attr.paymentsTypeModel) {
11255 scope.$watch(attr.paymentsTypeModel, function(newVal, oldVal) {
11256 if (newVal !== oldVal) {
11257 var valid = _Validate(type, ctrl.$modelValue, ctrl, scope, attr);
11258 ctrl.$setValidity(type, valid);
11263 return function(type, ctrl, scope, attr) {
11264 if (_validatorWatches[type]) {
11265 return _validatorWatches[type](type, ctrl, scope, attr);
11269 .directive('validateCard', ['$window', '_Validate', '_ValidateWatch', function($window, _Validate, _ValidateWatch) {
11272 require: 'ngModel',
11273 link: function(scope, elem, attr, ctrl) {
11275 var type = attr.validateCard;
11276 _ValidateWatch(type, ctrl, scope, attr);
11277 var validateFn = function(val) {
11278 var valid = _Validate(type, val, ctrl, scope, attr);
11279 ctrl.$setValidity(type, valid);
11280 if (type === 'card')
11282 if (ctrl.$card === null)
11284 if ((val == null) || (val === "") || (val === ''))
11286 scope.invalidCardError = '';
11287 scope.invalidCard = "";
11289 else if (val.length >= 1)
11291 scope.invalidCardError = 'error';
11292 scope.invalidCard = "The number entered is not a recognized credit card number.";
11299 if (ctrl.$card.length.indexOf(val.length) >= 0)
11301 scope.invalidCardError = 'error';
11302 scope.invalidCard = "The number entered is not a recognized credit card number.";
11306 scope.invalidCardError = '';
11307 scope.invalidCard = "";
11312 scope.invalidCardError = '';
11313 scope.invalidCard = "";
11316 elem.bind("blur", function()
11318 if ((!valid) || (ctrl.$card === null))
11320 scope.invalidCardError = 'error';
11321 scope.invalidCard = "The number entered is not a recognized credit card number.";
11325 scope.invalidCardError = '';
11326 scope.invalidCard = "";
11330 return valid ? val : undefined;
11332 ctrl.$formatters.push(validateFn);
11333 ctrl.$parsers.push(validateFn);
11337 .directive('creditCardImage', function() {
11339 templateUrl: 'app/scripts/ng_js_att_tpls/formField/creditCardImage.html',
11342 link: function(scope, element, attr)
11344 scope.$watch(attr.creditCardImage, function(newVal, oldVal)
11346 if (newVal !== oldVal)
11349 if (!angular.isUndefined(newVal) && newVal !== null)
11351 scope.newValCCI = 'show-' + newVal;
11353 if (newVal === null)
11355 scope.newValCCI = '';
11362 .directive('securityCodeImage', ['$document', function($document) {
11364 templateUrl: 'app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html',
11367 link: function(scope, element, attr)
11369 scope.$watch(attr.securityCodeImage, function(newVal, oldVal)
11371 if (newVal !== oldVal)
11373 if (!angular.isUndefined(newVal) && newVal !== null)
11375 if (newVal === 'amexI')
11377 scope.newValI = 'ccv2-security-amex';
11378 scope.newValIAlt = "The 4 digit CVC security code is on the front of the card.";
11379 scope.cvcPlaceholder = "4 digits";
11380 scope.cvcMaxlength = 4;
11382 else if (newVal === 'visaI')
11384 scope.newValI = 'ccv2-security';
11385 scope.newValIAlt = "The CVC security code is on the back of your card right after the credit card number.";
11386 scope.cvcPlaceholder = "3 digits";
11387 scope.cvcMaxlength = 3;
11390 if (newVal === null)
11392 scope.newValI = 'ccv2-security';
11393 scope.cvcPlaceholder = "3 digits";
11394 scope.cvcMaxlength = 3;
11395 scope.newValIAlt = "The CVC security code is on the back of your card right after the credit card number.";
11400 element.bind("click", function(ev) {
11401 ev.preventDefault();
11402 if (element.find("button").hasClass("active")) {
11403 element.find("button").removeClass("active");
11406 element.find("button").addClass("active");
11410 var window = angular.element($document);
11411 window.bind("click", function(ev) {
11412 var targetClassname = ev.target.className;
11413 if ((targetClassname !== "btn btn-alt btn-tooltip active")) {
11414 if (element.find("button").hasClass("active")) {
11415 element.find("button").removeClass("active");
11424 angular.module('att.abs.hourpicker', ['att.abs.utilities'])
11425 .constant('hourpickerConfig', {
11426 days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
11427 customOption: 'Custom'
11430 .controller('hourPickerController', ['$scope', function ($scope) {
11432 $scope.options = [];
11433 this.setOptions = function (value, fromtime, totime, preselect, uncheckedFromTime, uncheckedToTime) {
11434 $scope.options.push(value);
11436 if (preselect !== undefined) {
11437 $scope.preselect = preselect;
11442 if (fromtime !== undefined) {
11443 $scope.fromtime = fromtime;
11444 for (daycount in $scope.days) {
11445 if ($scope.days.hasOwnProperty(daycount)) {
11446 $scope.FrtimeList[$scope.days[daycount]] = {};
11447 if (uncheckedFromTime !== undefined) {
11448 $scope.FrtimeList[$scope.days[daycount]].value = uncheckedFromTime;
11449 $scope.selectedFromOption[$scope.days[daycount]] = uncheckedFromTime;
11451 $scope.FrtimeList[$scope.days[daycount]].value = fromtime[0].value;
11452 $scope.selectedFromOption[$scope.days[daycount]] = fromtime[0].value;
11457 if (totime !== undefined) {
11458 $scope.totime = totime;
11459 for (daycount in $scope.days) {
11460 if ($scope.days.hasOwnProperty(daycount)) {
11461 $scope.TotimeList[$scope.days[daycount]] = {};
11462 if (uncheckedToTime !== undefined) {
11463 $scope.TotimeList[$scope.days[daycount]].value = uncheckedToTime;
11464 $scope.selectedToOption[$scope.days[daycount]] = uncheckedToTime;
11466 $scope.TotimeList[$scope.days[daycount]].value = totime[0].value;
11467 $scope.selectedToOption[$scope.days[daycount]] = totime[0].value;
11469 $scope.showToTimeErrorDay[$scope.days[daycount]] = false;
11474 if (uncheckedFromTime !== undefined) {
11475 $scope.uncheckedFromTime = uncheckedFromTime;
11477 if (uncheckedToTime !== undefined) {
11478 $scope.uncheckedToTime = uncheckedToTime;
11482 this.getSelectedOption = function () {
11483 return $scope.selectedOption;
11486 this.setToTimeErrorDay = function (day, flag) {
11487 $scope.showToTimeErrorDay[day] = flag;
11491 .directive('attHourpickerOption', [function () {
11494 require: '^attHourpicker',
11497 fromtime: "=fromtime",
11499 preselect: "=preselect",
11500 uncheckedFromTime: "=",
11501 uncheckedToTime: "="
11503 link: function (scope, element, attr, ctrl) {
11504 ctrl.setOptions(scope.option,
11508 scope.uncheckedFromTime,
11509 scope.uncheckedToTime);
11514 .directive('attHourpicker', ["hourpickerConfig", "$document", "$log", "$documentBind", "$timeout", function (hourpickerConfig, $document, $log, $documentBind, $timeout) {
11516 require: 'ngModel',
11518 controller: 'hourPickerController',
11524 templateUrl: 'app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html',
11525 link: function (scope, element, attr, ctrl) {
11527 scope.isFromDropDownOpen = false;
11528 scope.isToDropDownOpen = false;
11529 var dropDownOpenValue = "";
11531 scope.days = hourpickerConfig.days;
11532 scope.daysList = {};
11533 scope.FrtimeList = {};
11534 scope.FrtimeListDay = {};
11535 scope.TotimeListDay = {};
11536 scope.selectedFromOption = {};
11537 scope.selectedToOption = {};
11538 scope.TotimeList = {};
11539 scope.selectedIndex = 0;
11540 scope.selectedOption = "Select from list";
11541 scope.customTime = [];
11543 scope.resetFlag = false;
11544 scope.showToTimeErrorDay = {};
11545 scope.validatedCustomPreselect = [];
11547 scope.$watch('resetFlag', function (newVal, oldVal) {
11548 if (newVal !== oldVal) {
11549 if (newVal && scope.selectedOption === hourpickerConfig.customOption) {
11550 //disable and reset all days checkbox
11551 for (day in scope.daysList) {
11552 if (scope.daysList.hasOwnProperty(day)) {
11553 scope.daysList[day] = false;
11554 scope.addSelectedValue(day);
11557 scope.preselectUpdateFxn(scope.preselect);
11559 scope.resetFlag = false;
11563 scope.$watch('selCategory', function (value) {
11565 ctrl.$setViewValue(value);
11569 scope.updateData = function (value) {
11570 if (value.constructor === Array) {
11571 scope.showDaysSelector = true;
11572 scope.selectedOption = hourpickerConfig.customOption;
11573 for (var arry in value) {
11574 if (value.hasOwnProperty(arry)) {
11575 var day = value[arry].day;
11577 if (typeof value[arry].preEnabled === 'boolean' && value[arry].preEnabled) {
11578 scope.daysList[day] = true;
11580 scope.daysList[day] = false;
11583 for (var fromcount in scope.fromtime) {
11584 if (scope.fromtime[fromcount].value === value[arry].FromTime && !scope.uncheckedFromTime) {
11585 scope.FrtimeList[day].value = scope.fromtime[fromcount].value;
11586 scope.selectedFromOption[day] = scope.FrtimeList[day].value;
11589 for (var tocount in scope.totime) {
11590 if (scope.totime[tocount].value === value[arry].ToTime && !scope.uncheckedToTime) {
11591 scope.TotimeList[day].value = scope.totime[tocount].value;
11592 scope.selectedToOption[day] = scope.TotimeList[day].value;
11596 scope.addSelectedValue(day, value[arry].FromTime, value[arry].ToTime);
11599 if (parseInt(arry) + 1 === value.length) {
11605 scope.selectOption(value.day);
11609 scope.$watch('preselect', function (value) {
11610 scope.preselectUpdateFxn(value);
11613 scope.preselectUpdateFxn = function (value) {
11614 if (value !== undefined) {
11615 if (scope.options) {
11616 value = scope.validatePreselectData(value);
11618 if (value === "") {
11621 scope.updateData(value);
11625 scope.validatePreselectData = function (value) {
11626 if (value.constructor === Array) {
11627 for (var arry in value) {
11628 if (value.hasOwnProperty(arry)) {
11629 var day = value[arry].day;
11630 var isDayFound = false;
11631 var isFrmFound = false;
11632 var isToFound = false;
11633 for (var daycount in scope.days) {
11634 if (scope.days[daycount] === day) {
11640 value.splice(arry, 1);
11643 for (var fromcount in scope.fromtime) {
11644 if (scope.fromtime[fromcount].value === value[arry].FromTime) {
11650 value[arry].FromTime = scope.fromtime[0].value;
11652 for (var tocount in scope.totime) {
11653 if (scope.totime[tocount].value === value[arry].ToTime) {
11659 value[arry].ToTime = scope.totime[0].value;
11662 if (typeof value[arry].preEnabled === 'boolean' && value[arry].preEnabled) {
11663 value[arry].preEnabled = true;
11665 value[arry].preEnabled = false;
11668 scope.validatedCustomPreselect[day] = {};
11669 scope.validatedCustomPreselect[day].FromTime = value[arry].FromTime;
11670 scope.validatedCustomPreselect[day].ToTime = value[arry].ToTime;
11673 if (parseInt(arry) + 1 === value.length) {
11679 var isOptionFound = false;
11680 for (var optcount in scope.options) {
11681 if (scope.options[optcount] === value.day) {
11682 isOptionFound = true;
11686 if (!isOptionFound) {
11693 scope.selectPrevNextValue = function ($event, arrayValues, currValue) {
11697 if ($event.keyCode === 38) {
11699 } else if ($event.keyCode === 40) {
11705 if (arrayValues.indexOf(currValue) !== -1) {
11706 index = arrayValues.indexOf(currValue) + value;
11708 for (var count in arrayValues) {
11709 if (arrayValues[count].value === currValue) {
11710 index = parseInt(count) + value;
11716 if (index === arrayValues.length) {
11718 } else if (index === -1) {
11722 $event.preventDefault();
11723 if (arrayValues[index].value) {
11724 return arrayValues[index].value;
11726 return arrayValues[index];
11730 scope.showDropdown = function () {
11731 scope.showlist = !scope.showlist;
11735 scope.showfromDayDropdown = function (value) {
11736 //close dropdown if any other From drop down is opened
11737 for (count in scope.FrtimeListDay) {
11738 if (count !== value && scope.FrtimeListDay[count]) {
11739 scope.FrtimeListDay[count] = false;
11742 for (count in scope.TotimeListDay) {
11743 if (scope.TotimeListDay[count]) {
11744 scope.TotimeListDay[count] = false;
11747 scope.FrtimeListDay[value] = !scope.FrtimeListDay[value];
11749 scope.showlist = false;
11751 //save model value so we can close current dropdown on click of other part of the document
11752 if (scope.FrtimeListDay[value]) {
11753 scope.isFromDropDownOpen = true;
11754 dropDownOpenValue = value;
11756 scope.isFromDropDownOpen = false;
11759 $timeout(function () {
11760 if (scope.FrtimeListDay[value]) {
11761 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
11762 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
11763 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
11764 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
11769 scope.showtoDayDropdown = function (value) {
11770 //close dropdown if any other To drop down is opened
11771 for (count in scope.TotimeListDay) {
11772 if (count !== value && scope.TotimeListDay[count]) {
11773 scope.TotimeListDay[count] = false;
11776 for (count in scope.FrtimeListDay) {
11777 if (scope.FrtimeListDay[count]) {
11778 scope.FrtimeListDay[count] = false;
11781 scope.TotimeListDay[value] = !scope.TotimeListDay[value];
11783 scope.showlist = false;
11785 //save model value so we can close current dropdown on click of other part of the document
11786 if (scope.TotimeListDay[value]) {
11787 scope.isToDropDownOpen = true;
11788 dropDownOpenValue = value;
11791 scope.isToDropDownOpen = false;
11794 $timeout(function () {
11795 if (scope.TotimeListDay[value]) {
11796 var daysContainerDIV = angular.element(element)[0].querySelector(".customdays-width");
11797 var containerUL = angular.element(daysContainerDIV.querySelector('.select2-container-active')).parent()[0].querySelector("ul");
11798 var selectedElemTopPos = angular.element(containerUL.querySelector('.selectedItemInDropDown'))[0].offsetTop;
11799 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
11804 scope.selectFromDayOption = function (day, value) {
11805 scope.selectedFromOption[day] = value;
11806 scope.FrtimeList[day].value = value;
11807 scope.FrtimeListDay[day] = false;
11808 scope.isFromDropDownOpen = false;
11811 scope.selectToDayOption = function (day, value) {
11812 scope.selectedToOption[day] = value;
11813 scope.TotimeList[day].value = value;
11814 scope.TotimeListDay[day] = false;
11815 scope.isToDropDownOpen = false;
11818 scope.addSelectedValue = function (value, fromtime, totime) {
11820 if (scope.daysList[value] !== undefined && !scope.daysList[value]) {
11821 for (count = 0, len = scope.customTime.length; count < len; count++) {
11822 if (scope.customTime[count].day === value) {
11823 if (scope.uncheckedFromTime) {
11824 scope.selectedFromOption[scope.customTime[count].day] = scope.uncheckedFromTime;
11826 scope.selectedFromOption[scope.customTime[count].day] = scope.FrtimeList[scope.customTime[count].day].value;
11829 if (scope.uncheckedToTime) {
11830 scope.selectedToOption[scope.customTime[count].day] = scope.uncheckedToTime;
11832 scope.selectedToOption[scope.customTime[count].day] = scope.TotimeList[scope.customTime[count].day].value;
11835 scope.customTime.splice(count, 1);
11840 if (scope.selectedFromOption[value] === scope.uncheckedFromTime) {
11842 if (angular.isDefined(scope.validatedCustomPreselect[value])) {
11843 scope.selectedFromOption[value] = scope.validatedCustomPreselect[value].FromTime;
11844 fromtime = scope.validatedCustomPreselect[value].FromTime;
11845 scope.FrtimeList[value].value = scope.validatedCustomPreselect[value].FromTime;
11847 scope.selectedFromOption[value] = scope.fromtime[0].value;
11848 fromtime = scope.fromtime[0].value;
11849 scope.FrtimeList[value].value = scope.fromtime[0].value;
11854 if (scope.selectedToOption[value] === scope.uncheckedToTime) {
11856 if (angular.isDefined(scope.validatedCustomPreselect[value])) {
11857 scope.selectedToOption[value] = scope.validatedCustomPreselect[value].ToTime;
11858 totime = scope.validatedCustomPreselect[value].ToTime;
11859 scope.TotimeList[value].value = scope.validatedCustomPreselect[value].ToTime;
11861 scope.selectedToOption[value] = scope.totime[0].value;
11862 totime = scope.totime[0].value;
11863 scope.TotimeList[value].value = scope.totime[0].value;
11867 custTime["day"] = value;
11868 custTime["FromTime"] = scope.FrtimeList[value].value;
11869 custTime["ToTime"] = scope.TotimeList[value].value;
11871 for (count = 0, len = scope.customTime.length; count < len; count++) {
11872 if (scope.customTime[count].day === value) {
11873 scope.customTime[count].FromTime = custTime["FromTime"];
11874 scope.customTime[count].ToTime = custTime["ToTime"];
11878 if (count === len) {
11879 var x = angular.copy(custTime);
11880 scope.customTime.push(x);
11883 scope.selCategory = scope.customTime;
11887 var outsideClick = function () {
11888 if (scope.showlist) {
11889 scope.$apply(function () {
11890 scope.showlist = false;
11895 $documentBind.click('showlist', outsideClick, scope);
11897 var outsideClickFromDropdown = function () {
11898 scope.$apply(function () {
11899 if (scope.isFromDropDownOpen) {
11900 scope.FrtimeListDay[dropDownOpenValue] = false;
11901 scope.isFromDropDownOpen = false;
11906 $documentBind.click('isFromDropDownOpen', outsideClickFromDropdown, scope);
11908 var outsideClickToDropdown = function () {
11909 scope.$apply(function () {
11910 if (scope.isToDropDownOpen) {
11911 scope.TotimeListDay[dropDownOpenValue] = false;
11912 scope.isToDropDownOpen = false;
11917 $documentBind.click('isToDropDownOpen', outsideClickToDropdown, scope);
11919 scope.selectOption = function (sItem) {
11921 if (sItem === hourpickerConfig.customOption) {
11922 scope.showDaysSelector = true;
11923 scope.selCategory = scope.customTime;
11925 scope.showDaysSelector = false;
11926 var fromTime = /[0-9]\s?am/i.exec(sItem);
11927 var toTime = /[0-9]\s?pm/i.exec(sItem);
11928 scope.selCategory = {
11930 FromTime: fromTime === null ? 'NA' : fromTime[0],
11931 ToTime: toTime === null ? 'NA' : toTime[0]
11935 scope.showlist = false;
11937 scope.selectedOption = sItem;
11943 .directive('attHourpickerValidator', ['hourpickerConfig', function (hourpickerConfig) {
11946 require: ['attHourpicker', 'ngModel'],
11947 link: function (scope, element, attr, ctrl) {
11949 var attHourpickerCtrl = ctrl[0];
11950 var ngModelCtrl = ctrl[1];
11952 //required format [h:MM tt] like '1:10 PM'
11953 var convertTimeStrngToMilitaryFormat = function (time) {
11954 var hours = Number(time.match(/^(\d+)/)[1]);
11955 var minutes = Number(time.match(/:(\d+)/)[1]);
11956 var AMPM = (time.match(/\s(.*)$/)[1]).toUpperCase();
11957 if (AMPM === 'PM' && hours < 12) {
11958 hours = hours + 12;
11960 if (AMPM === 'AM' && hours === 12) {
11961 hours = hours - 12;
11963 var sHours = hours.toString();
11964 var sMinutes = minutes.toString();
11966 sHours = '0' + sHours;
11968 if (minutes < 10) {
11969 sMinutes = '0' + sMinutes;
11971 return parseInt(sHours + sMinutes, 10);
11974 var compareTimeStrings = function (fromTimeString, toTimeString) {
11975 var fromMilitaryTime = convertTimeStrngToMilitaryFormat(fromTimeString);
11976 var toMilitaryTime = convertTimeStrngToMilitaryFormat(toTimeString);
11977 return (toMilitaryTime - fromMilitaryTime);
11980 var validateCustomData = function (finalDataModal) {
11982 if (attHourpickerCtrl.getSelectedOption() === hourpickerConfig.customOption) {
11984 var errorDaysCount = 0;
11986 for (var item in finalDataModal) {
11987 if (finalDataModal.hasOwnProperty(item)) {
11988 if (compareTimeStrings(finalDataModal[item].FromTime, finalDataModal[item].ToTime) <= 0) {
11989 attHourpickerCtrl.setToTimeErrorDay(finalDataModal[item].day, true);
11992 attHourpickerCtrl.setToTimeErrorDay(finalDataModal[item].day, false);
11997 if (errorDaysCount > 0) {
11999 ngModelCtrl.$setValidity('validationStatus', false);
12002 //validation successful
12003 ngModelCtrl.$setValidity('validationStatus', true);
12004 return finalDataModal;
12007 //default case no validation
12008 ngModelCtrl.$setValidity('validationStatus', true);
12009 return finalDataModal;
12014 ngModelCtrl.$parsers.unshift(validateCustomData);
12018 angular.module('att.abs.iconButtons', [])
12019 .constant('buttonConfig', {
12020 activeClass: 'active--button',
12021 toggleEvent: 'click'
12023 .directive('attIconBtnRadio', ['buttonConfig', function(buttonConfig) {
12024 var activeClass = buttonConfig.activeClass || 'active--button';
12025 var toggleEvent = buttonConfig.toggleEvent || 'click';
12027 require: 'ngModel',
12028 link: function(scope, element, attrs, ngModelCtrl) {
12029 element.attr("tabindex","0");
12030 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnRadio+"</span>");
12032 ngModelCtrl.$render = function() {
12033 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, attrs.attIconBtnRadio));
12036 element.parent().bind(toggleEvent, function() {
12037 if (!element.parent().hasClass(activeClass)) {
12038 scope.$apply(function() {
12039 ngModelCtrl.$setViewValue(attrs.attIconBtnRadio);
12040 ngModelCtrl.$render();
12047 .directive('attIconBtnCheckbox', ['buttonConfig', function(buttonConfig) {
12048 var activeClass = buttonConfig.activeClass || 'active--button';
12049 var toggleEvent = buttonConfig.toggleEvent || 'click';
12051 require: 'ngModel',
12052 link: function(scope, element, attrs, ngModelCtrl) {
12053 element.attr("tabindex","0");
12054 element.append("<span class='hidden-spoken'>"+attrs.attIconBtnCheckbox+"</span>");
12055 function getTrueValue() {
12056 var trueValue = scope.$eval(attrs.btnCheckboxTrue);
12057 return angular.isDefined(trueValue) ? trueValue : true;
12059 function getFalseValue() {
12060 var falseValue = scope.$eval(attrs.btnCheckboxFalse);
12061 return angular.isDefined(falseValue) ? falseValue : false;
12064 ngModelCtrl.$render = function() {
12065 element.parent().toggleClass(activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
12068 element.parent().bind(toggleEvent, function() {
12069 scope.$apply(function() {
12070 ngModelCtrl.$setViewValue(element.parent().hasClass(activeClass) ? getFalseValue() : getTrueValue());
12071 ngModelCtrl.$render();
12078 angular.module('att.abs.links', ['ngSanitize'])
12079 .directive('attLink', [function() {
12082 link: function(scope, elem) {
12083 elem.addClass('link');
12084 if(!(elem.attr('href'))){
12085 elem.attr("tabindex", "0");
12090 .directive('attLinkVisited', [function() {
12093 link: function(scope, elem) {
12094 elem.addClass('link--visited');
12095 if(!(elem.attr('href'))){
12096 elem.attr("tabindex", "0");
12101 .directive('attReadmore', ['$timeout',function($timeout) {
12105 lines:"@noOfLines",
12107 //attribute to use readmore inside accordion
12110 templateUrl: 'app/scripts/ng_js_att_tpls/links/readMore.html',
12111 link: function(scope, elem) {
12113 scope.$watch('textModel', function(val){
12115 scope.textToDisplay = '';
12116 scope.readMoreLink = false;
12117 scope.readLessLink = false;
12118 scope.readFlag = false;
12121 if (typeof String.prototype.trim !== 'function') {
12122 String.prototype.trim = function() {
12123 return this.replace(/^\s+|\s+$/g, '');
12126 scope.textToDisplay = val.trim();
12127 scope.readFlag = true;
12128 $timeout(function() {
12129 var readElem = elem[0].children[0].children[0];
12131 if(window.getComputedStyle){
12132 height = parseInt(scope.lines) * parseFloat(window.getComputedStyle(readElem,null).getPropertyValue("height"));
12135 height = parseInt(scope.lines) * parseFloat(readElem.currentStyle.height);
12137 scope.elemHeight = height;
12138 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12141 scope.readMoreLink = true;
12142 scope.readLessLink = false;
12145 // Code to use readmore inside accordion
12146 var parentElem = elem.parent();
12147 if (parentElem.hasClass('att-accordion__body')) {
12148 scope.$watch('isOpen', function(val) {
12150 scope.readMoreLink = true;
12151 scope.readLessLink = false;
12152 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12153 scope.readFlag = true;
12157 scope.readMore = function() {
12158 scope.readMoreLink = false;
12159 scope.readLessLink = true;
12160 scope.readLinkStyle = {'height': 'auto'};
12161 scope.readFlag = false;
12162 var moreLink = angular.element(elem).children().eq(1).find('a')[0];
12163 $timeout(function()
12168 scope.readLess = function() {
12169 scope.readMoreLink = true;
12170 scope.readLessLink = false;
12171 scope.readLinkStyle = {'height': scope.elemHeight + 'px'};
12172 scope.readFlag = true;
12173 var readLessLink = angular.element(elem).children().eq(0).find('a')[0];
12174 $timeout(function()
12176 readLessLink.focus();
12182 .directive('attLinksList', [function() {
12185 controller: function() {
12187 link: function(scope, elem) {
12188 elem.addClass('links-list');
12192 .directive('attLinksListItem', [function() {
12195 require: '^attLinksList',
12196 link: function(scope, elem) {
12197 elem.addClass('links-list__item');
12198 if(!(elem.attr('href'))){
12199 elem.attr("tabindex", "0");
12204 angular.module('att.abs.loading', [])
12205 .directive('attLoading', ['$window',function($window) {
12210 icon: '@attLoading',
12211 progressStatus: '=?',
12214 templateUrl: 'app/scripts/ng_js_att_tpls/loading/loading.html',
12215 link: function(scope, element) {
12216 var progressvalue = scope.progressStatus;
12217 scope.progressStatus = Math.min(100, Math.max(0, progressvalue));
12218 if($window.navigator.userAgent.indexOf("MSIE 8.")!==-1){
12219 var shiftX = 0, shiftY = scope.progressStatus * 36;
12221 'background-position-x' : shiftX,
12222 'background-position-y' : -shiftY
12228 angular.module('att.abs.modal', ['att.abs.utilities'])
12230 * A helper, internal data structure that acts as a map but also allows getting / removing
12231 * elements in the LIFO order
12233 .factory('$$stackedMap', function () {
12235 createNew: function () {
12239 add: function (key, value) {
12245 get: function (key) {
12246 for (var i = 0; i < stack.length; i++) {
12247 if (key === stack[i].key) {
12254 for (var i = 0; i < stack.length; i++) {
12255 keys.push(stack[i].key);
12260 return stack[stack.length - 1];
12262 remove: function (key) {
12264 for (var i = 0; i < stack.length; i++) {
12265 if (key === stack[i].key) {
12270 return stack.splice(idx, 1)[0];
12272 removeTop: function () {
12273 return stack.splice(stack.length - 1, 1)[0];
12275 length: function () {
12276 return stack.length;
12284 * A helper directive for the $modal service. It creates a backdrop element.
12286 .directive('modalBackdrop', ['$timeout', function ($timeout) {
12290 templateUrl: 'app/scripts/ng_js_att_tpls/modal/backdrop.html',
12291 link: function (scope) {
12292 scope.animate = false;
12293 //trigger CSS transitions
12294 $timeout(function () {
12295 scope.animate = true;
12301 .directive('modalWindow', ['$modalStack','$timeout','$document', function ($modalStack,$timeout,$document) {
12310 templateUrl: 'app/scripts/ng_js_att_tpls/modal/window.html',
12311 link: function (scope, element, attrs) {
12312 scope.windowClass = attrs.windowClass || '';
12313 if (attrs['modalTitle'] && attrs['modalTitle']!=="") {
12314 element[0].setAttribute('aria-label', attrs['modalTitle']);
12315 element[0].removeAttribute('modal-title');
12317 $timeout(function () {
12318 // trigger CSS transitions
12319 scope.focusModalFlag = true;
12320 scope.animate = true;
12322 $document.on('focus keydown', function(e){
12323 if (e.which ===9) {
12324 String.prototype.contains = function(it) {
12325 return this.indexOf(it) !== -1;
12327 if (element[0] !== e.target && !element[0].contains( e.target )) {
12328 element[0].focus();
12332 scope.close = function (evt) {
12333 var modal = $modalStack.getTop();
12334 if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
12335 // Check if preventDefault exists due to lack of support for IE8
12336 if (evt.preventDefault) {
12337 evt.preventDefault();
12338 evt.stopPropagation();
12340 evt.returnValue = false;
12342 $modalStack.dismiss(modal.key, 'backdrop click');
12349 .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', 'events', 'keymap',
12350 function ($document, $compile, $rootScope, $$stackedMap, events, keymap) {
12351 var OPENED_MODAL_CLASS = 'modal-open';
12352 var backdropjqLiteEl, backdropDomEl;
12353 var backdropScope = $rootScope.$new(true);
12354 var openedWindows = $$stackedMap.createNew();
12355 var $modalStack = {};
12356 var modalLaunchingElement = undefined;
12357 function backdropIndex() {
12358 var topBackdropIndex = -1;
12359 var opened = openedWindows.keys();
12360 for (var i = 0; i < opened.length; i++) {
12361 if (openedWindows.get(opened[i]).value.backdrop) {
12362 topBackdropIndex = i;
12365 return topBackdropIndex;
12368 $rootScope.$watch(backdropIndex, function(newBackdropIndex){
12369 backdropScope.index = newBackdropIndex;
12372 function removeModalWindow(modalInstance) {
12374 var body = $document.find('body').eq(0);
12375 var html = $document.find('html').eq(0);
12376 var modalWindow = openedWindows.get(modalInstance).value;
12377 //clean up the stack
12378 openedWindows.remove(modalInstance);
12379 ////remove window DOM element
12380 modalWindow.modalDomEl.remove();
12381 body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
12382 html.css({overflow: 'scroll'});
12384 //remove backdrop if no longer needed
12385 if (backdropDomEl && backdropIndex() == -1) {
12386 backdropDomEl.remove();
12387 backdropDomEl = undefined;
12390 modalWindow.modalScope.$destroy();
12393 if (angular.isDefined(modalLaunchingElement) && modalLaunchingElement != null) {
12394 modalLaunchingElement.focus();
12397 $document.bind('keydown', function (evt) {
12399 if (evt.which === 27) {
12400 modal = openedWindows.top();
12401 if (modal && modal.value.keyboard) {
12402 $rootScope.$apply(function () {
12403 $modalStack.dismiss(modal.key);
12406 } else if (evt.keyCode === keymap.KEY.BACKSPACE) {
12407 var doPrevent = false;
12408 var d = evt.srcElement || evt.target;
12410 if (d.type === undefined) {
12412 } else if (d.tagName.toUpperCase() === 'INPUT' &&
12413 ( (type = d.type.toUpperCase()) === 'TEXT' ||
12414 type === 'PASSWORD' ||
12416 type === 'SEARCH' ||
12417 type === 'EMAIL' ||
12418 type === 'NUMBER' ||
12423 || d.tagName.toUpperCase() === 'TEXTAREA') {
12424 doPrevent = d.readOnly || d.disabled;
12429 events.preventDefault(evt);
12434 $modalStack.open = function (modalInstance, modal) {
12435 openedWindows.add(modalInstance, {
12436 deferred: modal.deferred,
12437 modalScope: modal.scope,
12438 backdrop: modal.backdrop,
12439 keyboard: modal.keyboard
12442 //Before opening modal, find the focused element
12443 modalLaunchingElement = document.activeElement;
12445 var body = $document.find('body').eq(0);
12446 var html = $document.find('html').eq(0);
12448 if (backdropIndex() >= 0 && !backdropDomEl) {
12449 backdropjqLiteEl = angular.element('<div modal-backdrop></div>');
12450 backdropDomEl = $compile(backdropjqLiteEl)(backdropScope);
12451 body.append(backdropDomEl);
12453 var angularDomEl = angular.element('<div modal-window></div>');
12454 angularDomEl.attr('window-class', modal.windowClass);
12455 angularDomEl.attr('index', openedWindows.length() - 1);
12456 angularDomEl.attr('modal-title', modal.modalTitle);
12457 angularDomEl.html(modal.content);
12459 var modalDomEl = $compile(angularDomEl)(modal.scope);
12460 openedWindows.top().value.modalDomEl = modalDomEl;
12461 body.append(modalDomEl);
12462 body.addClass(OPENED_MODAL_CLASS);
12463 html.css({overflow: 'hidden'});
12466 $modalStack.close = function (modalInstance, result) {
12467 var modal = openedWindows.get(modalInstance);
12469 modal.value.deferred.resolve(result);
12470 removeModalWindow(modalInstance);
12474 $modalStack.dismiss = function (modalInstance, reason) {
12475 var modalWindow = openedWindows.get(modalInstance).value;
12477 modalWindow.deferred.reject(reason);
12478 removeModalWindow(modalInstance);
12482 $modalStack.getTop = function () {
12483 return openedWindows.top();
12486 return $modalStack;
12489 .provider('$modal', function () {
12491 var $modalProvider = {
12493 //can be also false or 'static'
12497 $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
12498 function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
12500 function getTemplatePromise(options) {
12501 return options.template ? $q.when(options.template) :
12502 $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
12503 return result.data;
12507 function getResolvePromises(resolves) {
12508 var promisesArr = [];
12509 angular.forEach(resolves, function (value) {
12510 if (angular.isFunction(value) || angular.isArray(value)) {
12511 promisesArr.push($q.when($injector.invoke(value)));
12514 return promisesArr;
12516 $modal.open = function (modalOptions) {
12517 var modalResultDeferred = $q.defer();
12518 var modalOpenedDeferred = $q.defer();
12520 //prepare an instance of a modal to be injected into controllers and returned to a caller
12521 var modalInstance = {
12522 result: modalResultDeferred.promise,
12523 opened: modalOpenedDeferred.promise,
12524 close: function (result) {
12525 $modalStack.close(modalInstance, result);
12527 dismiss: function (reason) {
12528 $modalStack.dismiss(modalInstance, reason);
12531 //merge and clean up options
12532 modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
12533 modalOptions.resolve = modalOptions.resolve || {};
12536 if (!modalOptions.template && !modalOptions.templateUrl) {
12537 throw new Error('One of template or templateUrl options is required.');
12540 var templateAndResolvePromise =
12541 $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
12542 templateAndResolvePromise.then(function(tplAndVars) {
12543 var modalScope = (modalOptions.scope || $rootScope).$new();
12544 modalScope.$close = modalInstance.close;
12545 modalScope.$dismiss = modalInstance.dismiss;
12547 var ctrlInstance, ctrlLocals = {};
12548 var resolveIter = 1;
12551 if (modalOptions.controller) {
12552 ctrlLocals.$scope = modalScope;
12553 ctrlLocals.$modalInstance = modalInstance;
12554 angular.forEach(modalOptions.resolve, function (value, key) {
12555 ctrlLocals[key] = tplAndVars[resolveIter++];
12558 ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
12561 $modalStack.open(modalInstance, {
12563 deferred: modalResultDeferred,
12564 content: tplAndVars[0],
12565 backdrop: modalOptions.backdrop,
12566 keyboard: modalOptions.keyboard,
12567 windowClass: modalOptions.windowClass,
12568 modalTitle: modalOptions.modalTitle
12571 }, function(reason) {
12572 modalResultDeferred.reject(reason);
12575 templateAndResolvePromise.then(function () {
12576 modalOpenedDeferred.resolve(true);
12578 modalOpenedDeferred.reject(false);
12581 return modalInstance;
12588 return $modalProvider;
12591 .directive("simpleModal", ["$modal", function($modal) {
12604 link: function(scope, elm) {
12605 elm.bind('click', function(ev) {
12606 ev.preventDefault();
12607 if (angular.isDefined(elm.attr("href")) && elm.attr("href") !== "") {
12608 scope.simpleModal = elm.attr("href");
12611 scope.backdrop === "false" ? scope.backdropclick = 'static' : scope.backdropclick = true;
12612 scope.keyboard === "false" ? scope.keyboardev = false : scope.keyboardev = true;
12615 templateUrl: scope.simpleModal,
12616 backdrop:scope.backdropclick,
12617 keyboard:scope.keyboardev,
12618 windowClass:scope.windowClass,
12619 controller: scope.controller,
12620 modalTitle: scope.modalTitle
12621 }).result.then(scope.modalOk, scope.modalCancel);
12627 .directive('tabbedItem', ['$modal', '$log',function ($modal, $log){
12637 templateUrl: 'app/scripts/ng_js_att_tpls/modal/tabbedItem.html',
12638 controller: ['$scope', '$rootScope', '$attrs', function ($scope) {
12639 $scope.clickTab = function (index) {
12640 for (var i = 0; i < $scope.items.length; i++) {
12642 $scope.items[i].isTabOpen = true;
12643 $scope.items[i].showData = true;
12646 $scope.items[i].isTabOpen = false;
12647 $scope.items[i].showData = false;
12650 var modalInstance = $modal.open({
12651 templateUrl: $scope.templateId,
12652 controller: $scope.controller,
12653 windowClass: 'tabbedOverlay_modal',
12654 modalTitle: $scope.modalTitle,
12656 items: function () {
12657 return $scope.items;
12661 modalInstance.result.then(function (selectedItem) {
12662 $scope.selected = selectedItem;
12664 $log.info('Modal dismissed at: ' + new Date());
12667 $scope.isActiveTab = function (index) {
12668 return $scope.items && $scope.items[index] && $scope.items[index].isTabOpen;
12674 .directive('tabbedOverlay', [function () {
12682 templateUrl: 'app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html',
12683 controller: ['$scope', function ($scope) {
12684 $scope.clickTab = function (index) {
12685 for (var i = 0; i < $scope.items.length; i++) {
12687 $scope.items[i].isTabOpen = true;
12688 $scope.items[i].showData = true;
12691 $scope.items[i].isTabOpen = false;
12692 $scope.items[i].showData = false;
12696 $scope.isActiveTab = function (index) {
12697 return $scope.items && $scope.items[index] && $scope.items[index].isTabOpen;
12702 angular.module('att.abs.pagination', ['att.abs.utilities'])
12703 .directive('attPagination', [ function() {
12713 templateUrl: 'app/scripts/ng_js_att_tpls/pagination/pagination.html',
12714 link: function(scope) {
12716 scope.$watch('totalPages', function(value) {
12717 if(angular.isDefined(value) && value !== null){
12720 scope.totalPages = 1;
12724 for (var i = 1; i <= value; i++) {
12725 scope.pages.push(i);
12727 } else if (value > 7) {
12728 var midVal = Math.ceil(value / 2);
12729 scope.pages = [midVal - 1, midVal, midVal + 1];
12731 currentPageChanged(1);
12734 scope.$watch('currentPage', function(value) {
12735 currentPageChanged(value);
12737 var callbackHandler = function(num) {
12738 if (angular.isFunction(scope.clickHandler)){
12739 scope.clickHandler(num);
12742 function currentPageChanged(value) {
12743 if (angular.isDefined(value) && value !== null) {
12744 if (!value || value < 1) {
12747 if (value > scope.totalPages) {
12748 value = scope.totalPages;
12750 if(scope.currentPage !== value) {
12751 scope.currentPage = value;
12752 callbackHandler(scope.currentPage);
12754 if (scope.totalPages > 7) {
12755 if (value < scope.pages[0] && value > 3) {
12756 scope.pages = [value, value + 1, value + 2];
12757 } else if (value > scope.pages[2] && value < scope.totalPages - 2) {
12758 scope.pages = [value - 2, value - 1, value];
12759 } else if (value <= 3) {
12760 scope.pages = [1, 2, 3];
12761 } else if (value >= scope.totalPages - 2) {
12762 scope.pages = [scope.totalPages - 2, scope.totalPages - 1, scope.totalPages];
12767 scope.next = function(event) {
12768 event.preventDefault();
12769 if (scope.currentPage < scope.totalPages) {
12770 scope.currentPage += 1;
12771 callbackHandler(scope.currentPage);
12774 scope.prev = function(event) {
12775 event.preventDefault();
12776 if (scope.currentPage > 1) {
12777 scope.currentPage -= 1;
12778 callbackHandler(scope.currentPage);
12781 scope.selectPage = function(value, event) {
12782 event.preventDefault();
12783 scope.currentPage = value;
12784 scope.focusedPage = value;
12785 callbackHandler(scope.currentPage);
12787 scope.checkSelectedPage = function(value) {
12788 if(scope.currentPage === value) {
12793 scope.isFocused = function(page) {
12794 return scope.focusedPage === page;
12800 angular.module('att.abs.paneSelector',['att.abs.utilities'])
12801 .constant('paneGroupConstants',{
12802 SIDE_WIDTH_DEFAULT: '33%',
12803 INNER_PANE_DEFAULT: '67%',
12804 SIDE_PANE_ID: 'sidePane',
12805 NO_DRILL_DOWN: 'none'
12807 .factory('animation', function(){
12809 }).directive('attPaneAccessibility',['keymap','$window',function(keymap,$window) {
12812 require: ['^?sidePane','^?innerPane'],
12813 link: function (scope, elem,attr,ctrl) {
12814 var sidepaneCtrl = ctrl[0],innerPaneCtrl = ctrl[1],ieFlag=false;
12815 scope.ie = (function () {
12816 var undef,v = 3,div = document.createElement('div'),
12817 all = div.getElementsByTagName('i');
12819 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i>< ![endif]-->',
12822 return v > 4 ? v : undef;
12824 if(scope.ie === 8){
12830 elem.bind('keydown',function(ev){
12831 if (keymap.isAllowedKey(ev.keyCode) || keymap.isControl(ev) || keymap.isFunctionKey(ev)) {
12832 ev.preventDefault();
12833 ev.stopPropagation();
12835 switch (ev.keyCode) {
12836 case keymap.KEY.DOWN:
12837 el = angular.element(elem[0])[0];
12838 if(el && el.nextElementSibling){
12839 el.nextElementSibling.focus();
12844 if (el && el.nextSibling){
12845 el = el.nextSibling;
12850 } while (el && el.tagName !== 'DIV');
12854 case keymap.KEY.UP:
12855 el = angular.element(elem[0])[0];
12856 if(el && el.previousElementSibling){
12857 el.previousElementSibling.focus();
12862 if (el && el.previousSibling){
12863 el = el.previousSibling;
12868 } while (el && el.tagName !== 'DIV');
12872 case keymap.KEY.RIGHT:
12873 if(angular.isDefined(sidepaneCtrl)){
12874 el = sidepaneCtrl.getElement()[0];
12876 if(angular.isDefined(innerPaneCtrl)){
12877 el = innerPaneCtrl.getElement()[0];
12880 if (el && el.nextElementSibling){
12881 el = el.nextElementSibling;
12886 }while(window.getComputedStyle(el, null).getPropertyValue("display") === 'none');
12890 if (el && el.nextSibling){
12891 el = el.nextSibling;
12896 }while ((el && el.tagName == 'DIV') && el.currentStyle['display'] == 'none');
12899 el.querySelector("[att-pane-accessibility]").focus();
12902 case keymap.KEY.LEFT:
12903 if(angular.isDefined(sidepaneCtrl)){
12904 el = sidepaneCtrl.getElement()[0];
12906 if(angular.isDefined(innerPaneCtrl)){
12907 el = innerPaneCtrl.getElement()[0];
12910 if (el && el.previousElementSibling){
12911 el = el.previousElementSibling;
12916 }while (window.getComputedStyle(el, null).getPropertyValue("display") == 'none');
12921 if (el && el.previousSibling){
12922 el = el.previousSibling;
12927 }while((el && el.tagName == 'DIV') && el.currentStyle['display'] == 'none');
12930 el.querySelector("[att-pane-accessibility]").focus();
12941 .directive('sideRow', [function(){
12945 require: ['^sidePane','^paneGroup'],
12946 link: function(scope,element,attr,ctrls){
12947 var sidePaneCtrl = ctrls[0];
12948 var paneGroupCtrl = ctrls[1];
12951 Reset the sidePaneId array if a new
12952 set of ngRepeat data appeared
12954 sidePaneCtrl.sidePaneIds = [];
12956 var paneId =attr['paneId'];
12957 var drillDownTo = attr['drillDownTo'];
12958 sidePaneCtrl.sidePaneRows.push({'paneId':paneId, 'drillDownTo':drillDownTo});
12959 element.on('click', function(){
12960 sidePaneCtrl.currentSelectedRowPaneId = paneId;
12961 paneGroupCtrl.slideOutPane(paneId,true);
12966 .controller('SidePaneCtrl',['$scope', '$element','animation', 'paneGroupConstants',
12967 function($scope,$element,animation, paneGroupConstants){
12968 this.getElement = function(){
12971 this.sidePaneTracker = {};
12972 this.currentWidth = paneGroupConstants.SIDE_WIDTH_DEFAULT;
12973 this.paneId = paneGroupConstants.SIDE_PANE_ID;
12974 this.currentSelectedRowPaneId;
12975 this.drillDownToMapper = {};
12976 this.sidePaneRows = [];
12977 this.init = function(){
12978 var sidePaneRows = this.sidePaneRows;
12980 for(var index in sidePaneRows){
12981 if (sidePaneRows.hasOwnProperty(index)) {
12982 var paneId = sidePaneRows[index].paneId;
12983 var drillDownTo = sidePaneRows[index].drillDownTo;
12984 this.drillDownToMapper[paneId] = drillDownTo;
12986 this.currentSelectedRowPaneId = paneId;
12987 this.sidePaneTracker[paneId] = [];
12993 this.getSidePanesList = function(){
12994 return this.sidePaneTracker[this.currentSelectedRowPaneId];
12996 this.addToSidePanesList = function(newPaneId){
12997 if(this.sidePaneTracker[this.currentSelectedRowPaneId] === undefined){
12998 this.sidePaneTracker[this.currentSelectedRowPaneId] = [];
13000 else if(newPaneId){
13001 this.sidePaneTracker[this.currentSelectedRowPaneId].push(newPaneId);
13004 this.setWidth = function(val){
13006 this.currentWidth = val;
13008 animation.set($element,{width:this.currentWidth});
13010 this.resizeWidth = function(val){
13012 this.currentWidth = val;
13014 animation.to($element,.5,{width:val});
13018 .directive('sidePane', ['paneGroupConstants', function(paneGroupConstants){
13023 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/sidePane.html',
13024 require: ['^paneGroup', 'sidePane'],
13025 controller: 'SidePaneCtrl',
13027 link: function(scope,element,attr, ctrls){
13028 var paneGroupCtrl = ctrls[0];
13029 var sidePaneCtrl = ctrls[1];
13030 paneGroupCtrl.addPaneCtrl(paneGroupConstants.SIDE_PANE_ID, sidePaneCtrl);
13034 .directive('drillDownRow', ['$parse', 'paneGroupConstants',function($parse,paneGroupConstants){
13038 require: ['^innerPane','^paneGroup'],
13039 link: function(scope,element,attr,ctrls){
13040 var innerPaneCtrl = ctrls[0];
13041 var paneGroupCtrl = ctrls[1];
13042 element.on('click', function(){
13043 var drillDownTo = innerPaneCtrl.drillDownTo;
13044 if(innerPaneCtrl.drillDownTo !== paneGroupConstants.NO_DRILL_DOWN){
13045 paneGroupCtrl.slideOutPane(drillDownTo);
13047 element[0].focus();
13052 .controller('InnerPaneCtrl', ['$scope', '$element','animation', 'paneGroupConstants',
13053 function($scope,$element,animation,paneGroupConstants){
13054 this.getElement = function(){
13057 this.paneId = $scope.paneId;
13059 this.currentWidth = paneGroupConstants.INNER_PANE_DEFAULT;
13060 this.setWidth = function(val){
13062 this.currentWidth = val;
13064 animation.set($element,{width:this.currentWidth});
13066 this.resizeWidth = function(val,callback){
13067 animation.to($element,.25,{width:val,onComplete: callback});
13069 this.displayNone = function(){
13070 animation.set($element, {display:'none'});
13072 this.displayBlock = function(){
13073 animation.set($element,{display:'block'});
13075 this.hideRightBorder();
13078 this.floatLeft = function(){
13079 animation.set($element,{float:'left'});
13081 this.hideLeftBorder = function(){
13082 animation.set($element, {borderLeftWidth: '0px'});
13084 this.showLeftBorder = function(){
13085 animation.set($element,{borderLeftWidth: '1px'});
13087 this.hideRightBorder = function(){
13088 animation.set($element,{borderRightWidth: '0px'});
13090 this.showRightBorder = function(){
13091 animation.set($element, {borderRightWidth: '1px'});
13093 this.slideFromRight = function(){
13094 animation.set($element, {float:'right'});
13095 animation.set($element, {width: this.currentWidth});
13097 this.startOpen = function(){
13098 return $scope.startOpen;
13101 .directive('innerPane', function(){
13106 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/innerPane.html',
13107 require: ['^paneGroup', 'innerPane'],
13108 controller: 'InnerPaneCtrl',
13112 link: function(scope,element,attr,ctrls){
13113 if(attr.startOpen === ""){
13114 scope.startOpen = true;
13116 var paneGroupCtrl = ctrls[0];
13117 var innerPaneCtrl = ctrls[1];
13118 paneGroupCtrl.addPaneCtrl(scope.paneId,innerPaneCtrl);
13122 .controller('PaneGroupCtrl', ['$scope', '$element', 'paneGroupConstants',function($scope,$element,paneGroupConstants){
13124 this.accountLevelPaneModel = [];
13125 this.title = $scope.title;
13126 this.init = function(){
13127 var sidePane = this.panes[paneGroupConstants.SIDE_PANE_ID];
13131 //Show the other panes that may be set to startOpen
13132 //numOpen starts at 1 because of the side pane
13135 for(key in this.panes){
13136 if(this.panes[key].startOpen && this.panes[key].startOpen()){
13142 width = ((100/numOpen)) + '%';
13144 if(this.panes[sidePane.currentSelectedRowPaneId])
13147 sidePane.setWidth(width);
13148 this.panes[sidePane.currentSelectedRowPaneId].setWidth(width);
13151 sidePane.setWidth();
13152 this.panes[sidePane.currentSelectedRowPaneId].setWidth();
13154 this.panes[sidePane.currentSelectedRowPaneId].displayBlock();
13155 for(key in this.panes){
13156 if(key !== paneGroupConstants.SIDE_PANE_ID && key !== sidePane.currentSelectedRowPaneId){
13157 this.panes[key].displayNone();
13159 this.panes[key].drillDownTo = sidePane.drillDownToMapper[key];
13162 openOtherPanesOnStart(sidePane, this.panes);
13165 function openOtherPanesOnStart(sidePane, panes){
13166 //Build an array of the panes that need to be out
13167 var otherPanesStartOpened = [];
13169 for(index in sidePane.sidePaneRows){
13170 if (sidePane.sidePaneRows.hasOwnProperty(index)) {
13171 var pane = sidePane.sidePaneRows[index];
13173 //Skip the first pane row since we handled it in the begining
13174 if(index > 0 && panes[pane.paneId].startOpen && panes[pane.paneId].startOpen()){
13175 otherPanesStartOpened.push(pane);
13176 //Remember the panes that are opened for the first pane row Index
13177 sidePane.addToSidePanesList(pane.paneId);
13183 for(index in otherPanesStartOpened){
13184 if (otherPanesStartOpened.hasOwnProperty(index)) {
13185 var paneId = otherPanesStartOpened[index].paneId;
13186 var paneCtrl = panes[paneId];
13187 if(paneCtrl && paneCtrl.setWidth && paneCtrl.displayBlock){
13188 paneCtrl.setWidth(width);
13189 paneCtrl.displayBlock();
13199 Resets all the panels to their original positions at the end of a sidebar click
13200 By setting the sideBar to its default width
13201 Setting all panes to float left and displaynone
13202 Setting the pane that was clicked to default width and slide right
13205 this.resetPanes = function(){
13206 for(var key in this.panes){
13207 if(this.panes.hasOwnProperty(key)){
13208 var pane = this.panes[key];
13209 if(pane && (pane.paneId !== paneGroupConstants.SIDE_PANE_ID)){
13211 pane.displayNone();
13216 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13217 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
13221 this.addPaneCtrl = function(paneId,paneCtrl){
13222 this.panes[paneId] = paneCtrl;
13225 this._slideOutPane = function(paneId,isFromSidePane){
13227 //Check current side pane stack to see how many panes are already open for that side pane choice
13228 //then add the new pane that needs to be there
13230 if(isFromSidePane){
13232 //Check if the side pane id has already been clicked
13233 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13234 panesList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13237 if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID] && this.panes[paneId]){
13238 this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId = paneId;
13239 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList();
13241 this.panes[paneId].slideFromRight();
13242 this.panes[paneId].displayBlock();
13244 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
13247 else if(this.panes && this.panes[paneGroupConstants.SIDE_PANE_ID]){
13248 //Restore the panes based on the panelist
13249 if(panesList.length === 0 && this.panes[paneId]){
13250 //Only one pane is out
13251 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(paneGroupConstants.SIDE_WIDTH_DEFAULT);
13252 this.panes[paneId].displayBlock();
13253 this.panes[paneId].setWidth(paneGroupConstants.INNER_PANE_DEFAULT);
13256 //Multiple panes out
13257 var numPanes = panesList.length + 2;
13258 var width = ((100/numPanes)) + '%';
13259 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(width);
13261 //Set the sidePanes pane
13262 //set the panes children list
13263 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13264 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
13265 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].setWidth(width);
13267 for(var i in panesList){
13268 if(this.panes[panesList[i]]){
13269 this.panes[panesList[i]].displayBlock();
13270 this.panes[panesList[i]].setWidth(width);
13278 //Have to check the paneId that was given and where it is drilling down to
13279 var isPaneInStack = false;
13281 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13282 stackPaneList = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13284 for(var j in stackPaneList){
13285 if(stackPaneList.hasOwnProperty(j)){
13286 var pId = stackPaneList[j];
13287 if(pId === paneId){
13288 isPaneInStack = true;
13293 if(!isPaneInStack && this.panes[paneGroupConstants.SIDE_PANE_ID]){
13294 this.panes[paneGroupConstants.SIDE_PANE_ID].addToSidePanesList(paneId);
13296 var sidePanesListLength;
13297 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13298 sidePanesListLength = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList().length;
13300 var numberPanes = sidePanesListLength + 2;
13301 var widthToSet = ((100/numberPanes)) + '%';
13302 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13303 this.panes[paneGroupConstants.SIDE_PANE_ID].setWidth(widthToSet);
13307 if(this.panes[paneGroupConstants.SIDE_PANE_ID]){
13308 slideInPaneId = this.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList()[sidePanesListLength - 1];
13313 if(that.panes[paneGroupConstants.SIDE_PANE_ID]){
13314 panesList = that.panes[paneGroupConstants.SIDE_PANE_ID].getSidePanesList();
13317 for(var p in panesList){
13318 if(panesList.hasOwnProperty(p)){
13319 var paneListPaneId = panesList[p];
13320 var pane = this.panes[paneListPaneId];
13321 if(paneListPaneId !== slideInPaneId && pane){
13322 pane.setWidth(widthToSet);
13323 pane.displayBlock();
13329 if(this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13330 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].displayBlock();
13331 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].showRightBorder();
13333 this.panes[this.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].resizeWidth(widthToSet,function(){
13335 if(that.panes[slideInPaneId] && that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId]){
13336 that.panes[that.panes[paneGroupConstants.SIDE_PANE_ID].currentSelectedRowPaneId].hideRightBorder();
13337 that.panes[slideInPaneId].setWidth(widthToSet);
13338 that.panes[slideInPaneId].slideFromRight();
13339 that.panes[slideInPaneId].displayBlock();
13340 that.panes[slideInPaneId].floatLeft();
13348 this.slideOutPane = function(paneId,isFromSidePane){
13349 this._slideOutPane(paneId,isFromSidePane);
13352 .directive('paneGroup', ['$timeout',function($timeout){
13357 templateUrl: 'app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html',
13360 controller: 'PaneGroupCtrl',
13361 link: function(scope,element,attr,ctrl){
13362 $timeout(initialize,100);
13363 function initialize(){
13369 angular.module('att.abs.tooltip', ['att.abs.position', 'att.abs.utilities', 'ngSanitize'])
13370 // The default options tooltip and popover.
13371 .constant('tooltipDefaultOptions', {
13372 placement: 'above',
13380 * The $tooltip service creates tooltip- and popover-like directives as well as
13381 * houses global options for them.
13383 .provider('$tooltip', ['tooltipDefaultOptions', function(tooltipDefaultOptions) {
13385 // Default hide triggers for each show trigger
13387 'mouseenter': 'mouseleave',
13390 'mouseover':'mouseout'
13393 // The options specified to the provider globally.
13394 var globalOptions = {};
13396 this.options = function(value) {
13397 angular.extend(globalOptions, value);
13401 * This allows you to extend the set of trigger mappings available. E.g.:
13403 * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
13405 this.setTriggers = function(triggers) {
13406 angular.extend(triggerMap, triggers);
13410 * This is a helper function for translating camel-case to snake-case.
13412 function snakeCase(name) {
13413 var regexp = /[A-Z]/g;
13414 var separator = '-';
13415 return name.replace(regexp, function(letter, pos) {
13416 return (pos ? separator : '') + letter.toLowerCase();
13421 * Returns the actual instance of the $tooltip service.
13423 this.$get = ['$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', '$attElementDetach', function($window, $compile, $timeout, $parse, $document, $position, $interpolate, $attElementDetach) {
13424 return function (type, prefix, defaultTriggerShow) {
13425 var options = angular.extend({}, tooltipDefaultOptions, globalOptions);
13427 * Returns an object of show and hide triggers.
13429 * If a trigger is supplied,
13430 * it is used to show the tooltip; otherwise, it will use the `trigger`
13431 * option passed to the `$tooltipProvider.options` method; else it will
13432 * default to the trigger supplied to this directive factory.
13434 * The hide trigger is based on the show trigger. If the `trigger` option
13435 * was passed to the `$tooltipProvider.options` method, it will use the
13436 * mapped trigger from `triggerMap` or the passed trigger if the map is
13437 * undefined; otherwise, it uses the `triggerMap` value of the show
13438 * trigger; else it will just use the show trigger.
13440 function getTriggers(trigger) {
13441 var show = trigger || options.trigger || defaultTriggerShow;
13442 var hide = triggerMap[show] || show;
13449 var directiveName = snakeCase(type);
13451 var startSym = $interpolate.startSymbol();
13452 var endSym = $interpolate.endSymbol();
13457 link: function (scope, element, attrs) {
13458 /* Allows a developer to force element to be non-tabable */
13459 if (!element.attr('tabindex')) {
13460 element.attr('tabindex', '0');
13463 var isElementHovered = false;
13464 element.bind('mouseenter', function(){
13465 isElementHovered = true;
13466 element.removeAttr('title');
13468 element.bind('mouseleave', function(){
13469 isElementHovered = false;
13470 setTooltipAriaLabel();
13473 /* We store our attributes on our scope so any user of $tooltip service can access attributes */
13474 scope.parentAttrs = attrs;
13476 '<div ' + directiveName + '-popup ' +
13477 'title="' + startSym + 'tt_title' + endSym + '" ' +
13478 'content="' + startSym + 'tt_content' + endSym + '" ' +
13479 'placement="' + startSym + 'tt_placement' + endSym + '" ' +
13480 'animation="tt_animation()" ' +
13481 'is-open="tt_isOpen" ' +
13482 'stylett="' + startSym + 'tt_style' + endSym + '" ' +
13486 var tooltip = $compile(template)(scope);
13487 var transitionTimeout;
13490 var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
13491 var triggers = getTriggers(undefined);
13492 var hasRegisteredTriggers = false;
13493 var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
13494 var tooltipOffset = 0;
13495 var tooltipAriaLabelDefined = false;
13497 // By default, the tooltip is not open.
13498 // add ability to start tooltip opened
13499 scope.tt_isOpen = false;
13501 //Adding a scope watch, to remove the created popup from DOM, incase it is updated outside the provider code.
13502 scope.$watch('tt_isOpen', function(newVal, oldVal){
13503 if(newVal !== oldVal && !newVal){
13504 $attElementDetach(tooltip[0]);
13508 function toggleTooltipBind() {
13509 if (!scope.tt_isOpen) {
13516 // Show the tooltip with delay if specified, otherwise show it immediately
13517 function showTooltipBind() {
13518 if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
13521 if (scope.tt_popupDelay) {
13522 popupTimeout = $timeout(show, scope.tt_popupDelay);
13524 scope.$apply(show);
13528 function hideTooltipBind() {
13529 scope.$apply(function() {
13534 // Show the tooltip popup element.
13541 // Don't show empty tooltips.
13542 if (!scope.tt_content) {
13546 // If there is a pending remove transition, we must cancel it, lest the
13547 // tooltip be mysteriously removed.
13548 if (transitionTimeout) {
13549 $timeout.cancel(transitionTimeout);
13552 // Set the initial positioning.
13553 tooltip.css({top: 0, left: 0, display: 'block', 'z-index': 9999});
13555 // Now we add it to the DOM because need some info about it. But it's not
13556 // visible yet anyway.
13557 if (appendToBody) {
13558 $body = $body || $document.find('body');
13559 $body.append(tooltip);
13561 element.after(tooltip);
13564 // Get the position of the directive element.
13565 position = appendToBody ? $position.offset(element) : $position.position(element);
13567 // Get the height and width of the tooltip so we can center it.
13568 ttWidth = tooltip.prop('offsetWidth');
13569 ttHeight = tooltip.prop('offsetHeight');
13571 // Calculate the tooltip's top and left coordinates to center it with
13573 var ttArrowOffset = 10;
13574 switch (scope.tt_placement) {
13578 top: position.top + position.height / 2 - ttHeight / 2,
13579 left: (position.left + position.width) + tooltipOffset
13583 top: position.top + position.height / 2 - ttHeight / 2,
13584 left: (position.left + position.width + ttArrowOffset) + tooltipOffset
13591 top: (position.top + position.height) + tooltipOffset,
13592 left: position.left + position.width / 2 - ttWidth / 2
13596 top: (position.top + position.height + ttArrowOffset) + tooltipOffset,
13597 left: position.left + position.width / 2 - ttWidth / 2
13604 top: position.top + position.height / 2 - ttHeight / 2,
13605 left: (position.left - ttWidth) - tooltipOffset
13609 top: position.top + position.height / 2 - ttHeight / 2,
13610 left: (position.left - ttWidth - ttArrowOffset) - tooltipOffset
13617 top: (position.top - ttHeight) - tooltipOffset,
13618 left: position.left + position.width / 2 - ttWidth / 2
13622 top: (position.top - ttHeight - ttArrowOffset) - tooltipOffset,
13623 left: position.left + position.width / 2 - ttWidth / 2
13629 ttPosition.top += 'px';
13630 ttPosition.left += 'px';
13632 // Now set the calculated positioning.
13633 tooltip.css(ttPosition);
13635 // And show the tooltip.
13636 scope.tt_isOpen = true;
13639 // Hide the tooltip popup element.
13641 // First things first: we don't show it anymore.
13642 scope.tt_isOpen = false;
13644 //if tooltip is going to be shown after delay, we must cancel this
13645 $timeout.cancel(popupTimeout);
13647 // And now we remove it from the DOM. However, if we have animation, we
13648 // need to wait for it to expire beforehand.
13649 // This is a placeholder for a port of the transitions library.
13650 if (angular.isDefined(scope.tt_animation) && scope.tt_animation()) {
13651 transitionTimeout = $timeout(function() {
13652 $attElementDetach(tooltip[0]);
13655 $attElementDetach(tooltip[0]);
13659 function setTooltipAriaLabel() {
13660 element.removeAttr('title');
13661 if(!isElementHovered){
13662 if (tooltipAriaLabelDefined) {
13663 element.attr('title', scope.tooltipAriaLabel);
13665 element.attr('title', scope.tt_content);
13671 * Observe the relevant attributes.
13673 attrs.$observe(type, function(val) {
13675 scope.tt_content = val;
13676 setTooltipAriaLabel();
13678 if (scope.tt_isOpen) {
13684 attrs.$observe(prefix + 'Title', function(val) {
13685 scope.tt_title = val;
13688 attrs.$observe(prefix + 'Placement', function(val) {
13689 scope.tt_placement = angular.isDefined(val) ? val : options.placement;
13692 attrs.$observe(prefix + 'Style', function(val) {
13693 scope.tt_style = angular.isDefined(val) ? val : options.stylett;
13696 attrs.$observe(prefix + 'Animation', function(val) {
13697 scope.tt_animation = angular.isDefined(val) ? $parse(val) : function() {
13698 return options.animation;
13702 attrs.$observe(prefix + 'PopupDelay', function(val) {
13703 var delay = parseInt(val, 10);
13704 scope.tt_popupDelay = !isNaN(delay) ? delay : options.popupDelay;
13707 attrs.$observe(prefix + 'Trigger', function(val) {
13709 if (hasRegisteredTriggers) {
13710 element.unbind(triggers.show, showTooltipBind);
13711 element.unbind(triggers.hide, hideTooltipBind);
13714 triggers = getTriggers(val);
13716 /* This fixes issue in which a click on input field with trigger as focus
13717 causes focus to fire following click thus making tooltip flash. */
13718 if (triggers.show === 'focus') {
13719 element.bind('focus', showTooltipBind);
13720 element.bind('blur', hideTooltipBind);
13721 element.bind('click', function(e) {
13722 e.stopPropagation();
13724 } else if (triggers.show === triggers.hide) {
13725 element.bind(triggers.show, toggleTooltipBind);
13727 element.bind(triggers.show, showTooltipBind);
13728 element.bind(triggers.hide, hideTooltipBind);
13731 hasRegisteredTriggers = true;
13734 attrs.$observe(prefix + 'AppendToBody', function (val) {
13735 appendToBody = angular.isDefined(val) ? $parse(val)(scope) : appendToBody;
13738 attrs.$observe(prefix + 'Offset', function (val) {
13739 tooltipOffset = angular.isDefined(val) ? parseInt(val, 10) : 0;
13742 attrs.$observe(prefix + 'AriaLabel', function (val) {
13743 if (angular.isDefined(val)) {
13744 scope.tooltipAriaLabel = val;
13745 tooltipAriaLabelDefined = true;
13747 tooltipAriaLabelDefined = false;
13749 setTooltipAriaLabel();
13752 // if a tooltip is attached to <body> we need to remove it on
13753 // location change as its parent scope will probably not be destroyed
13755 if (appendToBody) {
13756 scope.$on('$locationChangeSuccess', function() {
13757 if (scope.tt_isOpen) {
13763 // Make sure tooltip is destroyed and removed.
13764 scope.$on('$destroy', function() {
13765 if (scope.tt_isOpen) {
13777 .directive('tooltipPopup', ['$document', '$documentBind', function($document, $documentBind) {
13782 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
13783 templateUrl: 'app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html',
13784 link: function(scope, elem) {
13785 scope.$watch("isOpen", function() {
13788 elem.bind('click', function (e) {
13789 e.stopPropagation();
13791 var outsideClick = function() {
13792 scope.$apply(function() {
13793 scope.isOpen = false;
13797 $documentBind.event('click', 'isOpen', outsideClick, scope, true, 10);
13802 .directive('tooltip', ['$tooltip', function($tooltip) {
13803 return $tooltip('tooltip', 'tooltip', 'mouseenter');
13806 .directive('tooltipCondition', [ '$timeout',function($timeout) {
13811 tooltipCondition:"@?"
13813 template:'<p><span tooltip=\"{{tooltipCondition}}\" ng-if=\"showpop\">{{tooltipCondition}}</span><span id=\"innerElement\" ng-hide=\"showpop\">{{tooltipCondition}}</span></p>',
13814 link: function(scope, elem, attr){
13815 scope.showpop=false;
13816 if(attr.height==='true'){
13817 $timeout(function () {
13818 var maxHeight=(elem[0].offsetHeight);
13819 var elemHeight=elem.children(0)[0].offsetHeight;
13820 if(elemHeight > maxHeight){
13821 scope.showpop=true;
13825 else if(scope.tooltipCondition.length>=25){
13826 scope.showpop=true;
13831 angular.module('att.abs.popOvers', ['att.abs.tooltip', 'att.abs.utilities', 'ngSanitize'])
13832 .directive('popover', ['$tooltip', function($tooltip) {
13833 return $tooltip('popover', 'popover', 'click');
13835 .directive('popoverPopup', ['$document', '$documentBind', '$timeout', 'events', 'DOMHelper', function($document, $documentBind, $timeout, events, DOMHelper) {
13840 templateUrl: 'app/scripts/ng_js_att_tpls/popOvers/popOvers.html',
13841 scope: {content: '@', placement: '@', animation: '&', isOpen: '=', stylett: '@'},
13842 link: function(scope, elem, attr, ctrl) {
13844 scope.closeable = false;
13846 scope.closeable = scope.$parent.parentAttrs['closeable'] === '' ? true : false;
13849 /* Before opening modal, find the focused element */
13850 var launchingElement = undefined,
13851 firstTabableElement = undefined;
13853 var outsideClick = function(evt) {
13854 scope.$apply(function() {
13855 scope.isOpen = false;
13858 var escKeydown = function(evt) {
13859 if (evt.which === 27 || evt.keyCode === 27) {
13860 console.log('ESC was pressed!');
13861 scope.$apply(function() {
13862 scope.isOpen = false;
13867 $timeout(function() {
13868 firstTabableElement = DOMHelper.firstTabableElement(elem);
13871 scope.$watch('isOpen', function(value) {
13872 if (scope.isOpen) {
13873 launchingElement = document.activeElement;
13874 /* Focus on first tabbable element */
13875 if (angular.isDefined(firstTabableElement)) {
13877 firstTabableElement.focus();
13881 if (angular.isDefined(launchingElement)) {
13883 launchingElement.focus();
13884 } catch (e) {} /* IE8 will throw exception */
13889 scope.$watch("stylett", function(value) {
13890 scope.popOverStyle = value;
13893 scope.$watch("placement", function(value) {
13894 scope.popOverPlacement = value;
13897 scope.closeMe = function(){
13898 scope.isOpen = false;
13901 elem.bind('click', function (e) {
13902 events.stopPropagation(e);
13905 $documentBind.event('click', 'isOpen', outsideClick, scope, true, 10);
13906 $documentBind.event('keydown', 'isOpen', escKeydown, scope, true, 10);
13911 angular.module('att.abs.profileCard', [])
13912 .constant('profileStatus',{
13914 ACTIVE:{status:"Active",color:"green"},
13915 DEACTIVATED:{status:"Deactivated",color:"red"},
13916 LOCKED:{status:"Locked",color:"red"},
13917 IDLE:{status:"Idle",color:"yellow"},
13918 PENDING:{status:"Pending",color:"blue"}
13920 role:"COMPANY ADMINISTRATOR"
13922 .directive('profileCard',['$http','$q','profileStatus', function($http,$q,profileStatus) {
13926 templateUrl:function(element, attrs){
13927 if(!attrs.addUser){
13928 return 'app/scripts/ng_js_att_tpls/profileCard/profileCard.html';
13931 return 'app/scripts/ng_js_att_tpls/profileCard/addUser.html';
13937 link: function(scope, elem, attr){
13939 function isImage(src) {
13940 var deferred = $q.defer();
13941 var image = new Image();
13942 image.onerror = function() {
13943 deferred.reject(false);
13945 image.onload = function() {
13946 deferred.resolve(true);
13948 if(src!==undefined && src.length>0 ){
13951 deferred.reject(false);
13953 return deferred.promise;
13957 isImage(scope.profile.img).then(function(img) {
13960 var splitName=(scope.profile.name).split(' ');
13962 for(var i=0;i<splitName.length;i++){
13963 scope.initials += splitName[i][0];
13965 if(scope.profile.role.toUpperCase()===profileStatus.role){
13968 var profileState=profileStatus.status[scope.profile.state.toUpperCase()];
13970 scope.profile.state=profileStatus.status[scope.profile.state.toUpperCase()].status;
13971 scope.colorIcon=profileStatus.status[scope.profile.state.toUpperCase()].color;
13972 if(scope.profile.state.toUpperCase()===profileStatus.status.PENDING.status.toUpperCase()||scope.profile.state.toUpperCase()===profileStatus.status.LOCKED.status.toUpperCase()){
13973 scope.profile.lastLogin=scope.profile.state;
13976 var today=new Date().getTime();
13977 var lastlogin=new Date(scope.profile.lastLogin).getTime();
13978 var diff=(today-lastlogin)/(1000*60*60*24);
13980 scope.profile.lastLogin="Today";
13983 scope.profile.lastLogin="Yesterday";
13989 angular.module('att.abs.progressBars', [])
13991 .directive('attProgressBar', [function(){
13995 templateUrl : 'app/scripts/ng_js_att_tpls/progressBars/progressBars.html'
13998 angular.module('att.abs.radio', [])
13999 .constant('attRadioConfig', {
14000 activeClass : "att-radio--on",
14001 disabledClass : "att-radio--disabled"
14003 .directive('attRadio', ['$compile','attRadioConfig', function ($compile, attRadioConfig) {
14007 require: 'ngModel',
14008 link: function (scope, element, attr, ctrl) {
14011 var parentDiv = angular.element('<div att-accessibility-click="13,32" ng-click="updateModel($event)" class="att-radio"></div>');
14012 element.attr("value",attr.attRadio);
14013 element.removeAttr("att-radio");
14014 element.removeAttr("title");
14015 element.attr("ng-model","radioVal");
14016 parentDiv.append(element.prop('outerHTML'));
14017 parentDiv.append('<div class="att-radio__indicator"></div>');
14018 parentDiv.attr("title", attr.title);
14020 var elm = parentDiv.prop('outerHTML');
14021 elm = $compile(elm)(scope);
14022 element = element.replaceWith(elm);
14023 var radioElm = elm.find("input");
14025 radioElm.on('focus', function() {
14026 elm.css("outline","thin dotted #333");
14027 elm.css("outline","-webkit-focus-ring-color auto 5px");
14029 radioElm.on('blur', function() {
14030 elm.css("outline","none");
14033 ngCtrl.$render = function () {
14034 scope.radioVal = ngCtrl.$modelValue;
14035 var selected = angular.equals(ngCtrl.$modelValue, attr.attRadio);
14036 elm.toggleClass(attRadioConfig.activeClass, selected);
14039 scope.updateModel = function () {
14040 radioElm[0].focus();
14041 var isActive = elm.hasClass(attRadioConfig.activeClass);
14043 if (!isActive && !scope.disabled) {
14044 ngCtrl.$setViewValue(isActive ? null : attr.attRadio);
14049 attr.$observe('disabled', function (val) {
14050 scope.disabled = (val || val === "disabled" || val === "true");
14051 if (scope.disabled){
14052 elm.addClass(attRadioConfig.disabledClass);
14053 elm.attr("tabindex", "-1");
14059 angular.module('att.abs.scrollbar', ['att.abs.position'])
14061 .constant('attScrollbarConstant', {
14063 // Vertical or horizontal scrollbar? ( x || y ).
14065 // Whether navigation pane is required of not.
14067 // Enable or disable the mousewheel.
14069 // How many pixels must the mouswheel scroll at a time.
14071 // Lock default scrolling window when there is no more content.
14073 //// Enable invert style scrolling
14074 scrollInvert: false,
14075 // Set the size of the scrollbar to auto or a fixed number.
14077 // Set the size of the thumb to auto or a fixed number.
14079 // Set to false to hide the scrollbar if not being used
14080 alwaysVisible: true
14084 .directive('attScrollbar', ['$window', '$timeout', '$parse', '$animate', 'attScrollbarConstant', '$position', function ($window, $timeout, $parse, $animate, attScrollbarConstant, $position) {
14089 templateUrl: 'app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html',
14090 controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
14092 axis: $attrs.attScrollbar || attScrollbarConstant.defaults.axis,
14093 navigation: $attrs.navigation || attScrollbarConstant.defaults.navigation,
14094 wheel: attScrollbarConstant.defaults.wheel,
14095 wheelSpeed: attScrollbarConstant.defaults.wheelSpeed,
14096 wheelLock: attScrollbarConstant.defaults.wheelLock,
14097 scrollInvert: attScrollbarConstant.defaults.scrollInvert,
14098 trackSize: attScrollbarConstant.defaults.trackSize,
14099 thumbSize: attScrollbarConstant.defaults.thumbSize,
14100 alwaysVisible: attScrollbarConstant.defaults.alwaysVisible
14102 var options = $attrs.scrollbar;
14104 options = $parse(options)($scope);
14108 this.options = angular.extend({}, defaults, options);
14109 this._defaults = defaults;
14112 $body = angular.element(document.querySelectorAll('body')[0]),
14113 $document = angular.element(document),
14114 $viewport = angular.element($element[0].querySelectorAll('.scroll-viewport')[0]),
14115 $overview = angular.element($element[0].querySelectorAll('.scroll-overview')[0]),
14116 $scrollbar = angular.element($element[0].querySelectorAll('.scroll-bar')[0]),
14117 $thumb = angular.element($element[0].querySelectorAll('.scroll-thumb')[0]),
14119 isHorizontal = this.options.axis === 'x',
14120 hasTouchEvents = false,
14121 // Modern browsers support "wheel"
14122 wheelEvent = ("onwheel" in document ? "wheel" :
14123 // Webkit and IE support at least "mousewheel"
14124 document.onmousewheel !== undefined ? "mousewheel" :
14125 // let's assume that remaining browsers are older Firefox
14127 sizeLabel = isHorizontal ? 'width' : 'height',
14128 sizeLabelCap = sizeLabel.charAt(0).toUpperCase() + sizeLabel.slice(1).toLowerCase(),
14129 posiLabel = isHorizontal ? 'left' : 'top',
14130 // moveEvent = document.createEvent('HTMLEvents'),
14131 restoreVisibilityAfterWheel,
14132 thumbscrolltouch = false,
14133 documnetscrolltouch = false;
14134 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
14135 hasTouchEvents = true;
14138 //moveEvent.initEvent('move', true, true);
14139 this.contentPosition = 0;
14140 this.viewportSize = 0;
14141 this.contentSize = 0;
14142 this.contentRatio = 0;
14143 this.trackSize = 0;
14144 this.trackRatio = 0;
14145 this.thumbSize = 0;
14146 this.thumbPosition = 0;
14148 this.initialize = function () {
14149 if (!this.options.alwaysVisible) {
14150 $scrollbar.css('opacity', 0);
14157 this.setSizeData = function () {
14158 this.viewportSize = $viewport.prop('offset' + sizeLabelCap) || 1;
14159 this.contentSize = $overview.prop('scroll' + sizeLabelCap) || 1;
14160 this.contentRatio = this.viewportSize / this.contentSize;
14161 this.trackSize = this.options.trackSize || this.viewportSize;
14162 this.thumbSize = Math.min(this.trackSize, Math.max(0, (this.options.thumbSize || (this.trackSize * this.contentRatio))));
14163 this.trackRatio = this.options.thumbSize ? (this.contentSize - this.viewportSize) / (this.trackSize - this.thumbSize) : (this.contentSize / this.trackSize);
14166 this.update = function (scrollTo) {
14167 self.setSizeData();
14168 mousePosition = $scrollbar.prop('offsetTop');
14170 $scrollbar.toggleClass('disable', this.contentRatio >= 1 || isNaN(this.contentRatio));
14172 if (!this.options.alwaysVisible && this.contentRatio < 1 && this.viewportSize > 0) {
14173 //flash the scrollbar when update happens
14174 $animate.addClass($scrollbar, 'visible').then(function () {
14175 $animate.removeClass($scrollbar, 'visible');
14180 if (scrollTo !== null) {
14181 if (scrollTo === 'bottom') {
14182 this.contentPosition = this.contentSize - this.viewportSize;
14184 this.contentPosition = parseInt(scrollTo, 10) || 0;
14188 ensureContentPosition();
14189 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14190 $scrollbar.css(sizeLabel, self.trackSize + 'px');
14191 $thumb.css(sizeLabel, self.thumbSize + 'px');
14192 $overview.css(posiLabel, -self.contentPosition + 'px');
14197 fireEvent = function (obj, evt) {
14198 var fireOnThis = obj;
14200 if (document.createEvent) {
14202 evtObj = document.createEvent('HTMLEvents');
14203 evtObj.initEvent(evt, true, false);
14204 fireOnThis.dispatchEvent(evtObj);
14205 } else if (document.createEventObject) {
14207 evtObj = document.createEventObject();
14208 fireOnThis.fireEvent('on' + evt, evtObj);
14212 function ensureContentPosition() {
14213 // if scrollbar is on, ensure the bottom of the content does not go above the bottom of the viewport
14214 if (self.contentRatio <= 1 && self.contentPosition > self.contentSize - self.viewportSize) {
14215 self.contentPosition = self.contentSize - self.viewportSize;
14217 // if scrollbar is off, ensure the top of the content does not go below the top of the viewport
14218 else if (self.contentRatio > 1 && self.contentPosition > 0) {
14219 self.contentPosition = 0;
14222 if (self.contentPosition <= 0) {
14223 $scope.prevAvailable = false;
14225 $scope.prevAvailable = true;
14228 if (self.contentPosition >= (self.contentSize - self.viewportSize)) {
14229 $scope.nextAvailable = false;
14231 $scope.nextAvailable = true;
14235 function setEvents() {
14236 if (hasTouchEvents) {
14237 $viewport.on('touchstart', touchstart);
14238 $thumb.on('touchstart', touchstart);
14240 $thumb.on('mousedown', start);
14241 $scrollbar.on('mousedown', drag);
14244 angular.element($window).on('resize', resize);
14246 if (self.options.wheel) {
14247 $element.on(wheelEvent, wheel);
14251 function resize() {
14255 function touchstart(event) {
14256 if (1 === event.touches.length) {
14257 event.stopPropagation();
14258 start(event.touches[0]);
14262 function start(event) {
14263 $body.addClass('scroll-no-select');
14264 $element.addClass('scroll-no-select');
14266 if (!self.options.alwaysVisible) {
14267 $scrollbar.addClass('visible');
14269 mousePosition = isHorizontal ? event.clientX : event.clientY;
14270 self.thumbPosition = parseInt($thumb.css(posiLabel), 10) || 0;
14272 if (hasTouchEvents) {
14273 documnetscrolltouch = false;
14274 thumbscrolltouch = false;
14275 $viewport.on('touchmove', touchdrag);
14276 $viewport.on('touchend', end);
14277 $thumb.on('touchmove', touchdragthumb);
14278 $thumb.on('touchend', end);
14280 $document.on('mousemove', drag);
14281 $document.on('mouseup', end);
14282 $thumb.on('mouseup', end);
14286 function wheel(event) {
14287 if (self.contentRatio >= 1) {
14291 if (!self.options.alwaysVisible) {
14292 //cancel removing visibility if wheel event is triggered before the timeout
14293 if (restoreVisibilityAfterWheel) {
14294 $timeout.cancel(restoreVisibilityAfterWheel);
14296 $scrollbar.addClass('visible');
14298 restoreVisibilityAfterWheel = $timeout(function () {
14299 $scrollbar.removeClass('visible');
14303 var evntObj = (event && event.originalEvent) || event || $window.event,
14304 deltaDir = self.options.axis.toUpperCase(),
14306 X: evntObj.deltaX || 0,
14307 Y: evntObj.deltaY || 0
14309 wheelSpeed = evntObj.deltaMode === 0 ? self.options.wheelSpeed : 1;
14311 if (self.options.scrollInvert) {
14315 if (wheelEvent === 'mousewheel') {
14316 delta.Y = -1 * evntObj.wheelDelta / 40;
14317 if (evntObj.wheelDeltaX) {
14318 delta.X = -1 * evntObj.wheelDeltaX / 40;
14321 delta.X *= -1 / wheelSpeed;
14322 delta.Y *= -1 / wheelSpeed;
14324 var wheelSpeedDelta = delta[deltaDir];
14326 self.contentPosition -= wheelSpeedDelta * self.options.wheelSpeed;
14327 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
14329 fireEvent($element[0], 'move');
14331 ensureContentPosition();
14332 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14333 $overview.css(posiLabel, -self.contentPosition + 'px');
14335 if (self.options.wheelLock || (self.contentPosition !== (self.contentSize - self.viewportSize) && self.contentPosition !== 0)) {
14336 evntObj.preventDefault();
14342 function touchdrag(event) {
14343 event.preventDefault();
14344 documnetscrolltouch = true;
14345 drag(event.touches[0]);
14348 function touchdragthumb(event) {
14349 event.preventDefault();
14350 thumbscrolltouch = true;
14351 drag(event.touches[0]);
14354 function drag(event) {
14355 if (self.contentRatio >= 1) {
14359 var mousePositionNew = isHorizontal ? event.clientX : event.clientY,
14360 thumbPositionDelta = mousePositionNew - mousePosition;
14362 if ((self.options.scrollInvert && !hasTouchEvents) ||
14363 (hasTouchEvents && !self.options.scrollInvert)) {
14364 thumbPositionDelta = mousePosition - mousePositionNew;
14366 if (documnetscrolltouch && hasTouchEvents) {
14367 thumbPositionDelta = mousePosition - mousePositionNew;
14369 if (thumbscrolltouch && hasTouchEvents) {
14370 thumbPositionDelta = mousePositionNew - mousePosition;
14372 var thumbPositionNew = Math.min((self.trackSize - self.thumbSize), Math.max(0, self.thumbPosition + thumbPositionDelta));
14373 self.contentPosition = thumbPositionNew * self.trackRatio;
14375 fireEvent($element[0], 'move');
14377 ensureContentPosition();
14378 $thumb.css(posiLabel, thumbPositionNew + 'px');
14379 $overview.css(posiLabel, -self.contentPosition + 'px');
14384 $scope.customScroll = function (direction) {
14385 if (self.contentRatio >= 1) {
14389 var customScrollDelta;
14390 var viewportDimension = $position.position($viewport);
14392 if (isHorizontal) {
14393 customScrollDelta = viewportDimension.width;
14395 customScrollDelta = viewportDimension.height;
14399 self.contentPosition += customScrollDelta;
14401 self.contentPosition -= customScrollDelta;
14403 self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
14405 fireEvent($element[0], 'move');
14407 ensureContentPosition();
14408 $thumb.css(posiLabel, self.contentPosition / self.trackRatio + 'px');
14409 $overview.css(posiLabel, -self.contentPosition + 'px');
14413 $body.removeClass('scroll-no-select');
14414 $element.removeClass('scroll-no-select');
14415 if (!self.options.alwaysVisible) {
14416 $scrollbar.removeClass('visible');
14418 $document.off('mousemove', drag);
14419 $document.off('mouseup', end);
14420 $thumb.off('mouseup', end);
14421 $document.off('touchmove', touchdrag);
14422 $document.off('ontouchend', end);
14423 $thumb.off('touchmove', touchdragthumb);
14424 $thumb.off('touchend', end);
14427 this.cleanup = function () {
14428 $viewport.off('touchstart', touchstart);
14429 $thumb.off('mousedown', start);
14430 $scrollbar.off('mousedown', drag);
14431 $thumb.off('touchmove', touchdragthumb);
14432 $thumb.off('touchend', end);
14433 angular.element($window).off('resize', resize);
14434 $element.off(wheelEvent, wheel);
14435 //ensure scrollbar isn't activated
14436 self.options.alwaysVisible = true;
14440 link: function (scope, iElement, iAttrs, controller) {
14441 scope.navigation = controller.options.navigation;
14442 scope.viewportHeight = iAttrs.viewportHeight;
14443 scope.viewportWidth = iAttrs.viewportWidth;
14444 scope.scrollbarAxis = controller.options.axis;
14445 if (scope.scrollbarAxis === 'x') {
14446 iElement.addClass('horizontal');
14447 } else if (scope.scrollbarAxis === 'y') {
14448 iElement.addClass('vertical');
14451 var position = iElement.css('position');
14452 if (position !== 'relative' && position !== 'absolute') {
14453 iElement.css('position', 'relative');
14456 scope.$watch(function () {
14457 $timeout(refreshScrollbar, 100, false);
14460 var refreshScrollbar = function () {
14461 var $overview = angular.element(iElement[0].querySelectorAll('.scroll-overview')[0]);
14462 var newValue = $overview.prop('scrollHeight');
14463 var oldValue = scope.oldValue;
14464 if (newValue !== oldValue) {
14465 scope.oldValue = newValue;
14466 controller.update();
14470 controller.initialize();
14471 iElement.on('$destroy', function () {
14472 controller.cleanup();
14478 angular.module('att.abs.search', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
14479 .directive('attSearch', ['$document', '$filter', '$isElement', '$documentBind', '$timeout', '$log', 'keymap', function($document, $filter, $isElement, $documentBind, $timeout, $log, keymap){
14482 scope:{cName: '=attSearch'},
14486 templateUrl: 'app/scripts/ng_js_att_tpls/search/search.html',
14487 link: function(scope, element, attr, ctrl) {
14488 scope.selectedIndex = -1;
14489 scope.selectedOption = attr.placeholder;
14490 scope.isDisabled = false;
14491 scope.className = "select2-match";
14492 scope.showSearch = false;
14493 scope.showlist = false;
14495 // This is used to jump to elements in list
14497 // This is used to ensure searches only persist so many ms.
14498 var prevSearchDate = new Date();
14499 // This is used to shift focus back after closing dropdown
14500 var dropdownElement = undefined;
14501 // Used to ensure focus on dropdown elements
14503 $timeout(function() {
14504 list = element.find('li');
14507 $log.warn('attSearch is deprecated, please use attSelect instead. This component will be removed by version 2.7.')
14509 if (attr.noFilter || attr.noFilter === 'true') {
14510 scope.noFilter = true;
14512 scope.noFilter = false;
14514 if (attr.placeholderAsOption === 'false') {
14515 //scope.selectMsg = '';
14516 scope.selectedOption = attr.placeholder;
14518 scope.selectMsg = attr.placeholder;
14520 if (attr.startsWithFilter || attr.startsWithFilter === 'true') {
14521 scope.startsWithFilter = true;
14523 if (attr.showInputFilter === 'true') {
14524 scope.showSearch = false;
14525 $log.warn('showInputFilter functionality has been removed from the library.');
14526 // This is deprecated
14528 if (attr.disabled) {
14529 scope.isDisabled = true;
14531 dropdownElement = angular.element(element).children().eq(0).find('a')[0];
14533 var selectOptionFromSearch = function() {
14534 if (!scope.noFilter) {
14538 // Find next element that matches search criteria.
14539 // If no element is found, loop to beginning and search.
14540 var criteria = search;
14542 for (i = prevIndex; i < scope.cName.length; i++) {
14543 // Need to ensure we keep searching until all startsWith have passed before looping
14544 if (scope.cName[i].title.startsWith(criteria) && i !== scope.selectedIndex) {
14545 scope.selectOption(scope.cName[i], i, scope.showlist);
14551 if ((i >= scope.cName.length || !scope.cName[i+1].title.startsWith(criteria)) && prevIndex > 0) {
14555 scope.showDropdown = function() {
14556 if (!(attr.disabled)) {
14557 scope.showlist = !scope.showlist;
14558 scope.setSelectTop();
14561 element.bind('keydown', function(e) {
14562 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
14563 e.preventDefault();
14564 e.stopPropagation();
14566 switch (e.keyCode) {
14567 case keymap.KEY.DOWN:
14568 scope.selectNext();
14570 case keymap.KEY.UP:
14571 scope.selectPrev();
14574 case keymap.KEY.ENTER:
14575 scope.selectCurrent();
14578 case keymap.KEY.BACKSPACE:
14583 case keymap.KEY.SPACE:
14584 if (!scope.noFilter) {
14585 scope.title += ' ';
14589 case keymap.KEY.ESC:
14590 if (scope.title === '' || scope.title === undefined) {
14591 scope.showlist = false;
14592 dropdownElement.focus();
14598 if (scope.noFilter) {
14600 dropdownElement.focus();
14601 scope.showlist = false;
14608 if (e.keyCode !== 9)
14610 if (!scope.noFilter) {
14611 scope.showlist = true;
14612 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14614 var date = new Date();
14615 var delta = Math.abs(prevSearchDate.getMilliseconds() - date.getMilliseconds());
14616 prevSearchDate = date;
14620 search = search ? search + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14621 if (search.length > 2) {
14622 search = search.substring(0, 2);
14624 selectOptionFromSearch();
14627 } else if (e.keyCode === 9) {
14628 scope.showlist = false;
14634 scope.selectOption = function(sTitle, sIndex, keepOpen) {
14635 if (sIndex === -1 || sIndex === '-1') {
14636 scope.selCategory = '';
14637 scope.selectedIndex = -1;
14638 ctrl.$setViewValue('');
14639 if(attr.placeholderAsOption !== 'false')
14641 scope.selectedOption = scope.selectMsg;
14644 scope.selCategory = scope.cName[sIndex];
14645 scope.selectedIndex = sIndex;
14646 ctrl.$setViewValue(scope.selCategory);
14647 scope.selectedOption = scope.selCategory.title;
14648 if (angular.isDefined(list[sIndex])) {
14649 list[sIndex].focus();
14654 scope.showlist = false;
14655 dropdownElement.focus();
14659 scope.selectCurrent = function() {
14660 if (scope.showlist) {
14661 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14664 scope.showlist = true;
14665 scope.setSelectTop();
14669 scope.hoverIn = function(cItem) {
14670 scope.selectedIndex = cItem;
14673 scope.setSelectTop = function() {
14674 $timeout(function() {
14675 if (scope.showlist && !scope.noFilter)
14677 var containerUL = angular.element(element)[0].querySelector(".select2-results");
14678 if(angular.element(containerUL.querySelector('.select2-result-current'))[0])
14680 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
14682 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
14686 scope.setCurrentTop = function() {
14687 $timeout(function() {
14688 if (scope.showlist) {
14689 var containerUL = angular.element(element)[0].querySelector(".select2-results");
14690 if(angular.element(containerUL.querySelector('.hovstyle'))[0])
14692 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
14694 if (selectedElemTopPos < (angular.element(containerUL)[0].scrollTop)) {
14695 angular.element(containerUL)[0].scrollTop -= 30;
14696 } else if ((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight)) {
14697 angular.element(containerUL)[0].scrollTop += 30;
14703 scope.selectNext = function() {
14704 if ((scope.selectedIndex + 1) <= (scope.cName.length - 1)) {
14705 scope.selectedIndex += 1;
14706 if (!scope.showlist) {
14707 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14712 scope.setCurrentTop();
14714 scope.selectPrev = function() {
14715 if ((scope.selectedIndex - 1) >= 0) {
14716 scope.selectedIndex -= 1;
14717 if (!scope.showlist) {
14718 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14722 } else if (scope.selectedIndex - 1 < 0) {
14723 // If placeholderAsOption is true or undefined (default), ensure we can select it on up key.
14724 if (attr.placeholderAsOption === undefined || attr.placeholderAsOption === 'true') {
14725 scope.selectedIndex = -1;
14727 scope.selectedIndex = 0;
14729 if (!scope.showlist) {
14730 scope.selectOption(scope.selectMsg, scope.selectedIndex, false);
14735 scope.setCurrentTop();
14737 scope.updateSelection = function(sItem) {
14738 scope.selectedOption = sItem.title;
14741 scope.focusme = function() {
14742 $timeout(function() {
14743 var list = angular.element(element).find('ul').find('li');
14744 var index = scope.selectedIndex + 2;
14745 if (scope.noFilter) {
14746 index = scope.selectedIndex;
14748 if (angular.isDefined(list[index])) {
14749 list[index].focus();
14753 scope.$watch('selCategory', function(value) {
14755 scope.updateSelection(value);
14758 ctrl.$viewChangeListeners.push(function() {
14759 scope.$eval(attr.ngChange);
14761 ctrl.$render = function() {
14762 scope.selCategory = ctrl.$viewValue;
14764 var outsideClick = function(e) {
14765 var isElement = $isElement(angular.element(e.target), element, $document);
14767 scope.showlist = false;
14768 dropdownElement.focus();
14772 $documentBind.click('showlist', outsideClick, scope);
14776 angular.module('att.abs.select', ['att.abs.utilities', 'att.abs.position', 'att.abs.utilities'])
14777 .directive('attSelect', ["$document", "$filter", "$isElement", '$documentBind', '$timeout', 'keymap', '$log', function($document, $filter, $isElement, $documentBind, $timeout, keymap, $log) {
14781 cName: '=attSelect'
14785 require: 'ngModel',
14786 templateUrl: 'app/scripts/ng_js_att_tpls/select/select.html',
14787 link: function(scope, element, attr, ctrl) {
14788 scope.selectedIndex = -1;
14789 scope.selectedOption = attr.placeholder;
14790 scope.isDisabled = false;
14791 scope.className = "select2-match";
14792 scope.showSearch = false;
14793 scope.showlist = false;
14795 // This is used to jump to elements in list
14797 // This is used to ensure searches only persist so many ms.
14798 var prevSearchDate = new Date();
14799 // This is used to shift focus back after closing dropdown
14800 var dropdownElement = undefined;
14801 // Used to ensure focus on dropdown elements
14803 $timeout(function() {
14804 list = element.find('li');
14807 if (attr.noFilter || attr.noFilter === 'true') {
14808 scope.noFilter = true;
14810 scope.noFilter = false;
14812 if (attr.placeholderAsOption === 'false') {
14813 scope.selectedOption = attr.placeholder;
14815 scope.selectMsg = attr.placeholder;
14817 if (attr.startsWithFilter || attr.startsWithFilter === 'true') {
14818 scope.startsWithFilter = true;
14820 if (attr.showInputFilter === 'true') {
14821 scope.showSearch = false;
14822 /* This is deprecated */
14823 $log.warn('showInputFilter functionality has been removed from the library.');
14825 if (attr.disabled) {
14826 scope.isDisabled = true;
14828 var getFilterType = function() {
14829 if (scope.startsWithFilter) {
14830 return 'startsWith';
14835 dropdownElement = angular.element(element).children().eq(0).find('span')[0];
14837 var selectOptionFromSearch = function() {
14838 if (!scope.noFilter) {
14842 // Find next element that matches search criteria.
14843 // If no element is found, loop to beginning and search.
14844 var criteria = search;
14846 for (i = prevIndex; i < scope.cName.length; i++) {
14847 // Need to ensure we keep searching until all startsWith have passed before looping
14848 if (scope.cName[i].title.startsWith(criteria) && i !== scope.selectedIndex) {
14849 scope.selectOption(scope.cName[i], i, scope.showlist);
14855 if ((i >= scope.cName.length || !scope.cName[i+1].title.startsWith(criteria)) && prevIndex > 0) {
14859 scope.showDropdown = function() {
14860 if (!(attr.disabled)) {
14861 scope.showlist = !scope.showlist;
14862 scope.setSelectTop();
14863 /* Ensure selected element is focused upon opening dropdown */
14867 element.bind('keydown', function(e) {
14868 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
14869 e.preventDefault();
14870 e.stopPropagation();
14872 switch (e.keyCode) {
14873 case keymap.KEY.DOWN:
14874 scope.selectNext();
14876 case keymap.KEY.UP:
14877 scope.selectPrev();
14880 case keymap.KEY.ENTER:
14881 scope.selectCurrent();
14884 case keymap.KEY.BACKSPACE:
14889 case keymap.KEY.SPACE:
14890 if (!scope.noFilter) {
14891 scope.title += ' ';
14895 case keymap.KEY.ESC:
14896 if (scope.title === '' || scope.title === undefined) {
14897 scope.showlist = false;
14898 dropdownElement.focus();
14904 if (scope.noFilter) {
14906 dropdownElement.focus();
14907 scope.showlist = false;
14914 if (e.keyCode !== keymap.KEY.TAB)
14916 if (!scope.noFilter) {
14917 scope.showlist = true;
14918 scope.title = scope.title ? scope.title + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14920 /* Perform index correction */
14921 if (scope.title != '') {
14922 var filteredArray = $filter(getFilterType())(scope.cName, scope.title);
14924 for (var i = 0; i < filteredArray.length; i++) {
14925 for (var j = 0; j < scope.cName.length; j++) {
14926 if (!angular.isDefined(scope.cName[scope.selectedIndex])) {
14929 if (filteredArray[i]['title'] === scope.cName[scope.selectedIndex]['title']) {
14930 scope.selectedIndex = i;
14938 var date = new Date();
14939 var delta = Math.abs(prevSearchDate.getMilliseconds() - date.getMilliseconds());
14940 prevSearchDate = date;
14944 search = search ? search + String.fromCharCode(e.keyCode) : String.fromCharCode(e.keyCode);
14945 if (search.length > 2) {
14946 search = search.substring(0, 2);
14948 selectOptionFromSearch();
14951 } else if (e.keyCode === keymap.KEY.TAB) {
14952 scope.showlist = false;
14958 scope.selectOption = function(sTitle, sIndex, keepOpen) {
14960 if (sIndex === -1 || sIndex === '-1') {
14961 scope.selCategory = '';
14962 scope.selectedIndex = -1;
14963 ctrl.$setViewValue('');
14964 if(attr.placeholderAsOption !== 'false')
14966 scope.selectedOption = scope.selectMsg;
14970 /* Apply filter here to remap the selected index and shift focus*/
14971 if (scope.title != '') {
14972 var filteredArray = $filter(getFilterType())(scope.cName, scope.title);
14974 if (angular.isDefined(filteredArray) && angular.isDefined(filteredArray[sIndex]))
14976 for (var i = 0; i < scope.cName.length; i++) {
14977 if (filteredArray[sIndex]['title'] === scope.cName[i]['title']) {
14984 scope.selCategory = scope.cName[sIndex];
14985 scope.selectedIndex = sIndex;
14986 ctrl.$setViewValue(scope.selCategory);
14987 scope.selectedOption = scope.selCategory.title;
14989 $timeout(function(){
14990 if (angular.isDefined(list[sIndex])) {
14992 list[index].focus();
14993 } catch (e) {} /* IE8 will throw exception if display:none or not in DOM */
14999 scope.showlist = false;
15000 dropdownElement.focus();
15003 scope.selectCurrent = function() {
15004 if (scope.showlist) {
15005 scope.selectOption(scope.selectMsg,scope.selectedIndex,false);
15007 scope.showlist = true;
15008 scope.setSelectTop();
15012 scope.hoverIn = function(cItem) {
15013 scope.selectedIndex = cItem;
15016 scope.setSelectTop = function() {
15017 $timeout(function() {
15018 if (scope.showlist && !scope.noFilter)
15020 var containerUL = angular.element(element)[0].querySelector(".select2-results");
15021 if(angular.element(containerUL.querySelector('.select2-result-current'))[0])
15023 var selectedElemTopPos = angular.element(containerUL.querySelector('.select2-result-current'))[0].offsetTop;
15025 angular.element(containerUL)[0].scrollTop = selectedElemTopPos;
15029 scope.setCurrentTop = function() {
15030 $timeout(function() {
15031 if (scope.showlist) {
15032 var containerUL = angular.element(element)[0].querySelector(".select2-results");
15033 if(angular.element(containerUL.querySelector('.hovstyle'))[0])
15035 var selectedElemTopPos = angular.element(containerUL.querySelector('.hovstyle'))[0].offsetTop;
15037 if (selectedElemTopPos < (angular.element(containerUL)[0].scrollTop)) {
15038 angular.element(containerUL)[0].scrollTop -= 30;
15039 } else if ((selectedElemTopPos + 30) > (angular.element(containerUL)[0].clientHeight)) {
15040 angular.element(containerUL)[0].scrollTop += 30;
15046 scope.selectNext = function() {
15047 var length = scope.cName.length;
15049 if ((scope.selectedIndex + 1) <= (scope.cName.length - 1)) {
15050 scope.selectedIndex += 1;
15051 var nextDisabled = scope.cName[scope.selectedIndex].disabled;
15052 if (nextDisabled) {
15053 scope.selectedIndex += 1;
15055 if (!scope.showlist) {
15056 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15061 scope.setCurrentTop();
15063 scope.selectPrev = function() {
15064 if ((scope.selectedIndex - 1) >= 0) {
15065 scope.selectedIndex -= 1;
15066 var prevDisabled = scope.cName[scope.selectedIndex].disabled;
15067 if (prevDisabled) {
15068 scope.selectedIndex -= 1;
15070 if (!scope.showlist) {
15071 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15075 } else if (scope.selectedIndex - 1 < 0) {
15076 // If placeholderAsOption is true or undefined (default), ensure we can select it on up key.
15077 if (attr.placeholderAsOption === undefined || attr.placeholderAsOption === 'true') {
15078 if(attr.placeholder === undefined ){
15079 scope.selectedIndex = 0;
15082 scope.selectedIndex = -1;
15085 scope.selectedIndex = 0;
15087 if (!scope.showlist) {
15088 scope.selectOption(scope.selectMsg, scope.selectedIndex,false);
15093 scope.setCurrentTop();
15095 scope.updateSelection = function(sItem) {
15096 scope.selectedOption = sItem.title;
15099 if (sItem.index < 0) {
15100 scope.selectOption(scope.selectMsg, sItem.index, scope.showlist);
15103 scope.focusme = function() {
15104 $timeout(function() {
15105 var list = angular.element(element).find('ul').find('li');
15106 var index = scope.selectedIndex + 2;
15107 if (scope.noFilter) {
15108 index = scope.selectedIndex;
15110 if (angular.isDefined(list[index])) {
15112 list[index].focus();
15113 } catch (e) {} /* IE8 will throw exception if display:none or not in DOM */
15117 scope.$watch('selCategory', function(value) {
15119 scope.updateSelection(value);
15122 ctrl.$viewChangeListeners.push(function() {
15123 scope.$eval(attr.ngChange);
15125 ctrl.$render = function() {
15126 scope.selCategory = ctrl.$viewValue;
15128 var outsideClick = function(e) {
15129 var isElement = $isElement(angular.element(e.target), element, $document);
15131 scope.showlist = false;
15132 dropdownElement.focus();
15136 $documentBind.click('showlist', outsideClick, scope);
15140 .directive('textDropdown', ['$document', '$isElement', '$documentBind', "keymap", function($document, $isElement, $documentBind, keymap) {
15145 actions: '=actions',
15146 defaultAction: '=defaultAction',
15147 onActionClicked: '=?'
15149 templateUrl: 'app/scripts/ng_js_att_tpls/select/textDropdown.html',
15150 link: function(scope, element, attr) {
15151 scope.selectedIndex = 0;
15152 scope.selectedOption = attr.placeholder;
15153 scope.isDisabled = false;
15154 scope.isActionsShown = false;
15155 var dropdownElement = undefined;
15156 if (attr.disabled) {
15157 scope.isDisabled = true;
15160 dropdownElement = element.find('div')[0];
15162 // Set default Action
15163 if (!angular.isDefined(scope.defaultAction)) {
15164 scope.currentAction = scope.actions[0];
15165 scope.selectedIndex = 0;
15166 } else if (angular.isDefined(scope.defaultAction) || scope.defaultAction !== '') {
15167 for (var act in scope.actions) {
15168 if (scope.actions[act] === scope.defaultAction) {
15169 scope.currentAction = scope.actions[act];
15170 scope.selectedIndex = scope.actions.indexOf(act);
15171 scope.isActionsShown = false;
15176 scope.currentAction = scope.actions[0];
15178 scope.toggle = function() {
15179 scope.isActionsShown = !scope.isActionsShown;
15181 scope.chooseAction = function($event, action, $index) {
15182 if ($event != null) {
15183 scope.currentAction = action;
15184 scope.selectedIndex = $index;
15186 scope.currentAction = scope.actions[scope.selectedIndex];
15188 if (angular.isFunction(scope.onActionClicked)) {
15189 scope.onActionClicked(scope.currentAction);
15193 scope.isCurrentAction = function(action) {
15194 return (action === scope.currentAction);
15196 element.bind("keydown", function(e) {
15197 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
15198 e.preventDefault();
15199 e.stopPropagation();
15200 switch (e.keyCode) {
15201 case keymap.KEY.DOWN:
15202 scope.selectNext();
15204 case keymap.KEY.UP:
15205 scope.selectPrev();
15207 case keymap.KEY.ENTER:
15208 scope.selectCurrent();
15210 case keymap.KEY.ESC:
15211 scope.isActionsShown = false;
15212 dropdownElement.focus();
15220 } else if (e.keyCode === keymap.KEY.TAB) {
15221 scope.isActionsShown = false;
15225 scope.selectCurrent = function() {
15226 if (scope.selectedIndex < 0) {
15227 scope.selectedIndex = 0;
15229 if (!scope.isActionsShown) {
15232 scope.chooseAction(null, scope.currentAction);
15235 scope.selectNext = function() {
15236 if (scope.isActionsShown) {
15237 if ((scope.selectedIndex + 1) < scope.actions.length) {
15238 scope.selectedIndex += 1;
15240 scope.selectedIndex = (scope.actions.length - 1);
15245 scope.selectPrev = function() {
15246 if (scope.isActionsShown) {
15247 if ((scope.selectedIndex - 1) >= 0) {
15248 scope.selectedIndex -= 1;
15249 } else if (scope.selectedIndex - 1 < 0) {
15250 scope.selectedIndex = 0;
15255 scope.hoverIn = function(cItem) {
15256 scope.selectedIndex = cItem;
15259 var outsideClick = function(e) {
15260 var isElement = $isElement(angular.element(e.target), element, $document);
15266 $documentBind.click('isActionsShown', outsideClick, scope);
15270 angular.module('att.abs.slider', ['att.abs.position'])
15271 .constant('sliderDefaultOptions', {
15277 .directive('attSlider', ['sliderDefaultOptions','$position','$document', function(sliderDefaultOptions,$position,$document)
15291 ngModelSingle: '=?',
15294 ngModelDisabled: '=?'
15296 templateUrl: 'app/scripts/ng_js_att_tpls/slider/slider.html',
15297 link: function(scope, elem, attr)
15299 var minOffset, maxOffset, newOffset, newOffset1, newOffset2, offsetRange, valueRange, start_x = 0, disabledRange, disabled, evFlag = false, minValue, maxValue, range, refLow, refHigh, maxPtr, minPtr, singlePtr, getHandles;
15300 scope.minPtrOffset = 0;
15301 scope.maxPtrOffset = 0;
15302 var disableWidth = sliderDefaultOptions.disabledWidth;
15304 var obj = elem.children();
15305 disabledRange = obj[0].children;
15306 disabledRange = angular.element(disabledRange[0]);
15307 getHandles = obj[1].children;
15308 singlePtr = angular.element(getHandles[0]);
15309 minPtr = angular.element(getHandles[1]);
15310 maxPtr = angular.element(getHandles[2]);
15311 disabled = ((attr.ngModelSingle == null) && (attr.ngModelLow == null) && (attr.ngModelHigh == null)) && (attr.ngModelDisabled != null);
15312 range = (attr.ngModelSingle == null) && ((attr.ngModelLow != null) && (attr.ngModelHigh != null));
15313 refLow = 'ngModelLow';
15314 refHigh = 'ngModelHigh';
15320 singlePtr.remove();
15323 disabledRange.remove();
15326 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
15327 scope.handleStyle = {left: disableWidth + 'px'};
15329 minValue = parseFloat(scope.floor);
15330 maxValue = parseFloat(scope.ceiling);
15331 valueRange = maxValue - minValue;
15333 if (attr.width !== undefined) {
15334 maxOffset = attr.width;
15337 if (elem[0].clientWidth !== 0) {
15338 maxOffset = elem[0].clientWidth;
15341 maxOffset = sliderDefaultOptions.width;
15344 offsetRange = maxOffset - minOffset;
15346 scope.keyDown = function(ev){
15347 if(ev.keyCode === 39){
15348 var elemLeft = $position.position(elem).left;
15350 if(scope.ref === "ngModelLow"){
15351 newOffset1 = sliderDefaultOptions.step + newOffset1;
15352 newOffset = newOffset1;
15354 else if(scope.ref === "ngModelHigh"){
15355 newOffset2 = sliderDefaultOptions.step + newOffset2;
15356 newOffset = newOffset2;
15358 else{newOffset = sliderDefaultOptions.step + newOffset;}
15361 if(range &&scope.ref === "ngModelLow"){
15365 newOffset = sliderDefaultOptions.step + elemLeft;
15366 newOffset1 = newOffset2 = newOffset;
15370 else if(ev.keyCode === 37){
15371 var ptrLeft = $position.position(singlePtr).left;
15373 if (!(newOffset<=0)){
15374 if(scope.ref === "ngModelLow"){
15375 newOffset1 = newOffset1 - sliderDefaultOptions.step;
15376 newOffset = newOffset1;
15378 else if(scope.ref === "ngModelHigh"){
15379 newOffset2 = newOffset2 - sliderDefaultOptions.step;
15380 newOffset = newOffset2;
15383 newOffset = newOffset - sliderDefaultOptions.step;
15384 newOffset1 = newOffset2 = newOffset;
15389 newOffset = ptrLeft - sliderDefaultOptions.step;
15393 scope.ptrOffset(newOffset);
15397 scope.mouseDown = function(e, ref) {
15403 start_x = e.clientX - newOffset;
15406 start_x = e.clientX;
15409 if (scope.ref === refLow) {
15410 start_x = e.clientX - scope.minPtrOffset;
15413 start_x = e.clientX - scope.maxPtrOffset;
15417 scope.ref= 'ngModelDisabled';
15418 scope.disabledStyle = {width: disableWidth + 'px', zIndex: 1};
15421 // Mouse Move Event
15422 scope.moveElem = function(ev) {
15425 eventX = ev.clientX;
15426 newOffset = eventX - start_x;
15427 scope.ptrOffset(newOffset);
15430 scope.focus=function(ev,ref){
15435 scope.mouseUp = function(ev) {
15437 minPtr.removeClass('dragging');
15438 maxPtr.removeClass('dragging');
15439 singlePtr.removeClass('dragging');
15440 $document.off('mousemove');
15443 scope.keyUp = function(ev) {
15445 minPtr.removeClass('dragging');
15446 maxPtr.removeClass('dragging');
15447 singlePtr.removeClass('dragging');
15448 $document.off('mousemove');
15450 //Function to calculate the current PositionValue
15451 scope.calStep = function(value, precision, step, floor) {
15452 var decimals, remainder, roundedValue, steppedValue;
15453 if (floor === null) {
15456 if (step === null) {
15457 step = 1 / Math.pow(10, precision);
15459 remainder = (value - floor) % step;
15460 steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
15461 decimals = Math.pow(10, precision);
15462 roundedValue = steppedValue * decimals / decimals;
15463 return roundedValue.toFixed(precision);
15465 //Function to calculate Offset Percent
15466 scope.percentOffset = function(offset) {
15467 return ((offset - minOffset) / offsetRange) * 100;
15469 //Function to calculate Offset position
15470 scope.ptrOffset = function(newOffset){
15471 var newPercent, newValue;
15472 newOffset = Math.max(Math.min(newOffset, maxOffset), minOffset);
15473 newPercent = scope.percentOffset(newOffset);
15474 newValue = minValue + (valueRange * newPercent / 100.0);
15476 var rangeSliderWidth;
15477 if (scope.ref === refLow) {
15478 scope.minHandleStyle = {left: newOffset + "px"};
15479 scope.minNewVal = newValue;
15480 scope.minPtrOffset = newOffset;
15481 minPtr.addClass('dragging');
15482 if (newValue > scope.maxNewVal) {
15483 scope.ref = refHigh;
15485 scope.maxNewVal = newValue;
15486 scope.maxPtrOffset = newOffset;
15487 maxPtr.addClass('dragging');
15488 minPtr.removeClass('dragging');
15489 scope.maxHandleStyle = {left: newOffset + "px"};
15493 scope.maxHandleStyle = {left: newOffset + "px"};
15494 scope.maxNewVal = newValue;
15495 scope.maxPtrOffset = newOffset;
15496 maxPtr.addClass('dragging');
15497 if (newValue < scope.minNewVal) {
15498 scope.ref = refLow;
15500 scope.minVal = newValue;
15501 scope.minPtrOffset = newOffset;
15502 minPtr.addClass('dragging');
15503 maxPtr.removeClass('dragging');
15504 scope.minHandleStyle = {left: newOffset + "px"};
15507 rangeSliderWidth = parseInt(scope.maxPtrOffset) - parseInt(scope.minPtrOffset);
15508 scope.rangeStyle = {width: rangeSliderWidth + "px", left: scope.minPtrOffset + "px"};
15511 if (disabled && newOffset > disableWidth) {
15512 scope.rangeStyle = {width: newOffset + "px", zIndex: 0};
15515 singlePtr.addClass('dragging');
15516 scope.rangeStyle = {width: newOffset + "px"};
15518 scope.handleStyle = {left: newOffset + "px"};
15520 if ((scope.precision === undefined) || (scope.step === undefined)) {
15521 scope.precision = sliderDefaultOptions.precision;
15522 scope.step = sliderDefaultOptions.step;
15524 newValue = scope.calStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
15525 scope[scope.ref] = newValue;
15530 ]).directive('attSliderMin',[function()
15533 require: '^attSlider',
15537 templateUrl: 'app/scripts/ng_js_att_tpls/slider/minContent.html'
15540 ]).directive('attSliderMax',[function()
15543 require: '^attSlider',
15547 templateUrl: 'app/scripts/ng_js_att_tpls/slider/maxContent.html'
15551 angular.module('att.abs.splitButtonDropdown', ['att.abs.utilities','att.abs.position'])
15552 .directive('attButtonDropdown', ['$document', '$parse', '$documentBind', '$timeout','$isElement', function ($document, $parse, $documentBind, $timeout,$isElement) {
15557 templateUrl: 'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html',
15565 controller: ['$scope', '$element', function ($scope, $element) {
15567 this.cSelected = 0;
15568 this.closeAndFocusDropdown = function () {
15569 if ($scope.isDropDownOpen) {
15570 $scope.$apply(function () {
15571 $scope.isDropDownOpen = false;
15572 angular.element($element[0].querySelector('a.dropdown-toggle'))[0].focus();
15577 this.focusNext = function () {
15578 this.cSelected = this.cSelected + 1 >= this.childScopes.length ?($scope.cycleSelection === true ? 0 : this.childScopes.length-1): this.cSelected +1;
15579 this.childScopes[this.cSelected].sFlag = true;
15580 this.resetFlag(this.cSelected);
15583 this.focusPrev = function () {
15584 this.cSelected = this.cSelected -1 < 0 ? ($scope.cycleSelection === true ? this.childScopes.length-1 : 0) : this.cSelected - 1 ;
15585 this.childScopes[this.cSelected].sFlag = true;
15586 this.resetFlag(this.cSelected);
15589 this.childScopes = [];
15590 this.registerScope = function(childScope)
15592 this.childScopes.push(childScope);
15595 this.resetFlag = function(index){
15596 for(var i=0; i < this.childScopes.length; i++)
15600 this.childScopes[i].sFlag = false;
15606 link: function (scope, element, attr) {
15607 scope.isSmall = attr.small === "" ? true : false;
15608 scope.multiselect = attr.multiselect === ""? true : false;
15609 scope.cycleSelection = attr.cycleSelection === "" ? true : false;
15610 scope.isDropDownOpen = false;
15611 scope.isActionDropdown = false;
15613 if (!(scope.btnText)) {
15614 scope.isActionDropdown = true;
15617 scope.clickFxn = function () {
15618 if (typeof scope.btnClick === "function" && !scope.btnLink) {
15619 scope.btnClick = $parse(scope.btnClick);
15622 if(scope.multiselect === true)
15624 scope.isDropDownOpen = false;
15628 scope.toggleDropdown = function () {
15629 if (!(scope.btnType === 'disabled')) {
15630 scope.isDropDownOpen = !scope.isDropDownOpen;
15631 if (scope.isDropDownOpen) {
15632 $timeout(function () {
15633 angular.element(element[0].querySelector('li'))[0].focus();
15639 scope.btnTypeSelector = function (directiveValue, attrValue) {
15640 if (directiveValue !== "") {
15641 scope.btnTypeFinal = directiveValue;
15643 scope.btnTypeFinal = attrValue;
15647 var outsideClick = function(e) {
15648 var isElement = $isElement(angular.element(e.target), element.find('ul').eq(0), $document);
15650 scope.isDropDownOpen = false;
15655 $documentBind.click('isDropDownOpen', outsideClick, scope);
15657 attr.$observe('btnType', function (val) {
15658 scope.btnType = val;
15660 attr.$observe('attButtonDropdown', function (val) {
15661 attr.attButtonDropdown = val;
15662 scope.btnTypeSelector(attr.attButtonDropdown, scope.btnType);
15669 .directive('attButtonDropdownItem', ['$location','keymap', function ($location,keymap) {
15672 require: ['^attButtonDropdown','?ngModel'],
15675 templateUrl:'app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html', scope: {
15678 link: function (scope, element, attr, ctrl) {
15679 var rootLink = angular.element(element[0].querySelector('a'));
15680 scope.sFlag = false;
15681 ctrl[0].registerScope(scope);
15682 var clickOnLink = function () {
15683 if (scope.itemLinkFinal) {
15684 $location.url(scope.itemLinkFinal);
15689 scope.isSelected = ctrl[1].$viewValue;
15691 scope.isSelected = false;
15694 element.bind('keydown', function(e) {
15695 if (keymap.isAllowedKey(e.keyCode) || keymap.isControl(e) || keymap.isFunctionKey(e)) {
15696 e.preventDefault();
15697 e.stopPropagation();
15698 switch (e.keyCode) {
15699 case keymap.KEY.DOWN:
15700 ctrl[0].focusNext();
15702 case keymap.KEY.UP:
15703 ctrl[0].focusPrev();
15705 case keymap.KEY.ENTER:
15706 scope.selectItem();
15708 case keymap.KEY.ESC:
15709 ctrl[0].closeAndFocusDropdown();
15719 scope.selectItem = function()
15722 scope.$evalAsync(function(){ctrl[1].$setViewValue(!ctrl[1].$viewValue)});
15730 angular.module('att.abs.splitIconButton', ['att.abs.utilities'])
15731 .constant('iconStateConstants', {
15735 NEXT_TO_DROPDOWN:'next-to-dropdown',
15736 LEFT_NEXT_TO_DROPDOWN:'left-next-to-dropdown',
15742 SPLIT_ICON_BTN_EVENT_EMITTER_KEY: 'splitIconButtonTap'
15744 .directive('expandableLine', [function(){
15749 require: ['^attSplitIconButton', 'expandableLine'],
15750 controller: ['$scope', function($scope){
15751 $scope.isActive = false;
15752 this.setActiveState = function(isActive){
15753 $scope.isActive = isActive;
15755 this.isActive = $scope.isActive;
15756 this.dirType = $scope.dirType;
15758 template: '<div ng-class="{\'expand-line-container\': !isActive, \'expand-line-container-active\': isActive}"> <div ng-class="{\'hovered-line\':isActive, \'vertical-line\':!isActive}"> </div></div>',
15762 link: function(scope,element,attr,ctrls) {
15763 var attSplitIconButtonCtrl = ctrls[0];
15764 var expandableLineCtrl = ctrls[1];
15765 attSplitIconButtonCtrl.addSubCtrl(expandableLineCtrl);
15769 .controller('AttSplitIconCtrl', ['$scope', function($scope){
15770 this.setType = function(type){
15771 $scope.type = type;
15773 this.isDropdown = function(isDropdown){
15774 $scope.isDropdown = isDropdown;
15776 this.dropDownClicked = function(){
15777 if($scope.dropDownClicked) {
15778 $scope.dropDownClicked();
15781 this.dirType = $scope.dirType;
15783 .directive('attSplitIcon', ['$document', '$timeout','iconStateConstants','$documentBind','events', 'keymap',
15784 function($document,$timeout,iconStateConstants,$documentBind, events, keymap){
15790 require: ['^attSplitIconButton','attSplitIcon'],
15791 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html',
15794 iconTitle: '@title',
15796 dropDownWatch: '=',
15799 controller:'AttSplitIconCtrl',
15800 link: function(scope,element,attr,ctrls){
15801 var attSplitIconButtonCtrl = ctrls[0];
15802 var attSplitIconCtrl = ctrls[1];
15803 attSplitIconButtonCtrl.addSubCtrl(attSplitIconCtrl);
15804 scope.iconStateConstants = iconStateConstants;
15805 var currentIndex = 0;
15806 var isMyElement = false;
15808 scope.isDropdown = false;
15809 scope.isDropdownOpen = false;
15810 var outsideClick = function(e) {
15811 if(scope.isDropdown){
15813 isMyElement = false;
15814 scope.toggleDropdown();
15816 scope.toggleDropdown(false);
15821 if(attr.dropDownId && attr.dropDownId !== ''){
15822 scope.dropDownId = attr.dropDownId;
15823 scope.isDropdown = true;
15825 scope.$on(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, function(evnt, data){
15826 if(typeof data === 'boolean' && data) {
15827 scope.dropDownClicked();
15829 Check if the dropdown is open and if we are selecting one
15830 of the items, so that when pressing enter it will trigger it.
15832 if(scope.isDropDownOpen) {
15833 listElements[currentIndex].eq(0).find('a')[0].click();
15837 //Only trigger the keyboard event if the icon button is a dropdown type
15838 if(scope.isDropdown) {
15839 triggerKeyboardEvents(e);
15842 function triggerKeyboardEvents(e) {
15844 case (keymap.KEY.TAB):
15845 scope.toggleDropdown(false);
15848 case (keymap.KEY.ESC):
15851 case (keymap.KEY.ENTER):
15852 if (scope.isDropDownOpen) {
15853 listElementsInit();
15856 case (keymap.KEY.UP):
15857 e.preventDefault();
15858 events.stopPropagation(e);
15859 if(scope.isDropDownOpen) {
15860 scope.previousItemInDropdown();
15863 case (keymap.KEY.DOWN):
15864 e.preventDefault();
15865 events.stopPropagation(e);
15866 //Dropdown is open and the user taps down again
15867 if(scope.isDropDownOpen) {
15868 //Now we need to go through the rows in the dropdown
15869 scope.nextItemInDropdown();
15871 isMyElement = true;
15873 listElementsInit();
15880 function listElementsInit() {
15881 if(listElements === undefined) {
15883 var liTemps = element.find('li');
15884 for(var i = 0; i < liTemps.length; i++) {
15885 listElements.push(liTemps.eq(i));
15887 listElements[currentIndex].children().eq(0).addClass('selected-item');
15891 scope.nextItemInDropdown = function(){
15892 if(listElements && currentIndex < listElements.length - 1){
15894 listElements[currentIndex - 1].children().eq(0).removeClass('selected-item');
15895 listElements[currentIndex].children().eq(0).addClass('selected-item');
15898 scope.previousItemInDropdown = function(){
15899 if(currentIndex > 0) {
15901 listElements[currentIndex].children().eq(0).addClass('selected-item');
15903 if(currentIndex + 1 < listElements.length)
15904 listElements[currentIndex + 1].children().eq(0).removeClass('selected-item');
15907 scope.$watch('isIconHovered', function(val) {
15908 scope.hoverWatch = val;
15910 scope.$watch('type', function(val) {
15911 function toggleValues(isMiddle,isNextToDropDown,isRight,isLeft,isLeftNextDropdown){
15912 scope['isMiddle'] = isMiddle;
15913 scope['isNextToDropDown'] = isNextToDropDown;
15914 scope['isRight'] = isRight;
15915 scope['isLeft'] = isLeft;
15916 scope['isLeftNextDropdown'] = isLeftNextDropdown;
15919 case (scope.iconStateConstants.MIDDLE):
15920 toggleValues(true,false,false,true,false);
15922 case (scope.iconStateConstants.LEFT):
15923 toggleValues(false,false,false,true,false);
15925 case (scope.iconStateConstants.RIGHT):
15926 toggleValues(false,false,true,false,false);
15928 case (scope.iconStateConstants.NEXT_TO_DROPDOWN):
15929 toggleValues(false,true,true,true,false);
15931 case (scope.iconStateConstants.LEFT_NEXT_TO_DROPDOWN):
15932 toggleValues(false,false,false,true,true);
15938 scope.dropDownClicked = function() {
15939 isMyElement = true;
15941 scope.toggleDropdown = function(val) {
15942 if(val !== undefined) {
15943 scope.isDropDownOpen = val;
15945 scope.isDropDownOpen = !scope.isDropDownOpen;
15947 scope.dropDownWatch = scope.isDropDownOpen;
15949 $documentBind.click('isDropdown', outsideClick, scope);
15953 .controller('AttSplitIconButtonCtrl',['$scope', 'iconStateConstants',function($scope,iconStateConstants){
15954 this.subCtrls = [];
15955 $scope.isLeftLineShown=true;
15956 $scope.isRightLineShown=true;
15957 $scope.childrenScopes = [];
15960 function getDirIndex(dirType) {
15962 for(var c in that.subCtrls) {
15963 var ctrl = that.subCtrls[c];
15964 if(ctrl.dirType === dirType) {
15971 this.addSubCtrl = function(sub) {
15972 this.subCtrls.push(sub);
15974 this.isLeftLineShown = function(isShown) {
15975 if(isShown === undefined) {
15976 return $scope.isLeftLineShown;
15978 $scope.isLeftLineShown = isShown;
15981 this.isRightLineShown = function(isShown) {
15982 if(isShown === undefined) {
15983 return $scope.isRightLineShown;
15985 $scope.isRightLineShown = isShown;
15988 this.setLeftLineHover = function(isHovered) {
15989 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
15991 if($scope.isLeftLineShown && this.subCtrls[leftLineIndex] && this.subCtrls[leftLineIndex].setActiveState) {
15992 this.subCtrls[leftLineIndex].setActiveState(isHovered);
15995 this.setRightLineHover = function(isHovered) {
15996 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
15997 if($scope.isRightLineShown && this.subCtrls[rightLineIndex] && this.subCtrls[rightLineIndex].setActiveState){
15998 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16001 this.toggleLines = function(isHovered, buttonGroupCtrl, buttonCtrl, isDropDownOpen) {
16002 var subIconButtons = buttonGroupCtrl.subIconButtons;
16003 var subIconButtonsLength = subIconButtons.length;
16004 var leftLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.LEFT);
16005 var rightLineIndex = getDirIndex(iconStateConstants.DIR_TYPE.RIGHT);
16006 function noVerticalLineToggle() {
16007 for(var i =0; i < subIconButtonsLength; i++) {
16008 if(subIconButtons[i] === buttonCtrl) {
16009 if(i + 1 <= subIconButtonsLength - 1 && subIconButtons[i+1].isLeftLineShown()
16010 && subIconButtons[i+1].subCtrls[leftLineIndex]
16011 && subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState) {
16012 subIconButtons[i+1].subCtrls[leftLineIndex].setActiveState(isHovered);
16014 if(i - 1 >= 0 && subIconButtons[i-1].isRightLineShown()
16015 && subIconButtons[i-1].subCtrls[rightLineIndex]
16016 && subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState) {
16017 subIconButtons[i-1].subCtrls[rightLineIndex].setActiveState(isHovered);
16023 if(isDropDownOpen) {
16025 If the button is next to the dropdown button then just keep the
16026 buttons left line or its left neighbors right line toggled on
16027 If the button is the dropdown button don't do anything
16028 else do things normally witht the button
16030 /*if(subIconButtons[subIconButtonsLength-1] === buttonCtrl) {
16034 if(subIconButtons[subIconButtonsLength-2]==buttonCtrl) {
16035 if(subIconButtons[subIconButtonsLength-2].isLeftLineShown()) {
16036 subIconButtons[subIconButtonsLength-2].subCtrls[leftLineIndex].setActiveState(isHovered);
16037 } else if(subIconButtonsLength - 3 >= 0) {
16038 if(subIconButtons[subIconButtonsLength-3].isRightLineShown()) {
16039 subIconButtons[subIconButtonsLength-3].subCtrls[rightLineIndex].setActiveState(isHovered);
16043 noVerticalLineToggle();
16045 if($scope.isLeftLineShown) {
16046 this.subCtrls[leftLineIndex].setActiveState(isHovered);
16048 if($scope.isRightLineShown) {
16049 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16052 } else { // End of if(isDropDownOpen)
16053 //Handle Special cases where they aren't showing any vertical lines
16054 //and the dropdown isn't down
16055 if(!$scope.isLeftLineShown && !$scope.isRightLineShown) {
16056 noVerticalLineToggle();
16058 if($scope.isLeftLineShown && this.subCtrls[leftLineIndex].setActiveState) {
16059 this.subCtrls[leftLineIndex].setActiveState(isHovered);
16061 if($scope.isRightLineShown && this.subCtrls[rightLineIndex].setActiveState){
16062 this.subCtrls[rightLineIndex].setActiveState(isHovered);
16066 this.setButtonType = function(type){
16067 var buttonIndex = getDirIndex(iconStateConstants.DIR_TYPE.BUTTON);
16068 if(this.subCtrls[buttonIndex] && this.subCtrls[buttonIndex].setType) {
16069 this.subCtrls[buttonIndex].setType(type);
16073 .directive('attSplitIconButton', ['$document', 'iconStateConstants', 'keymap',
16074 function($document, iconStateConstants, keymap){
16080 require: ['^attSplitIconButtonGroup', 'attSplitIconButton'],
16081 controller: 'AttSplitIconButtonCtrl',
16082 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html',
16088 link: function(scope,element,attr,ctrls) {
16090 scope.title = scope.icon;
16092 var attSplitButtonGroupCtrl = ctrls[0];
16093 var attSplitIconButtonCtrl = ctrls[1];
16094 attSplitButtonGroupCtrl.addIconButton(attSplitIconButtonCtrl);
16095 element.bind('keydown', function(e){
16096 //Check if the key is the up or down key
16097 if(e.which === keymap.KEY.ESC ||
16098 e.which === keymap.KEY.DOWN ||
16099 e.which === keymap.KEY.ENTER ||
16100 e.which === keymap.KEY.UP ||
16101 e.which === keymap.KEY.TAB ) {
16102 scope.clickHandler();
16103 scope.$broadcast(iconStateConstants.SPLIT_ICON_BTN_EVENT_EMITTER_KEY, e);
16106 scope.dropDownWatch = false;
16107 scope.iconStateConstants = iconStateConstants;
16108 scope.clickHandler = function() {
16109 attSplitButtonGroupCtrl.hideLeftLineRightButton(attSplitIconButtonCtrl);
16111 scope.$watch('isHovered', function(val){
16113 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
16115 attSplitIconButtonCtrl.toggleLines(val,attSplitButtonGroupCtrl,attSplitIconButtonCtrl,attSplitButtonGroupCtrl.isDropDownOpen);
16118 scope.$watch('dropDownWatch', function(val) {
16119 attSplitButtonGroupCtrl.isDropDownOpen = val;
16120 attSplitButtonGroupCtrl.toggleDropdownState(val);
16125 .controller('AttSplitIconButtonGroupCtrl', ['$scope','iconStateConstants',function($scope,iconStateConstants){
16126 this.subIconButtons = [];
16127 this.addIconButton = function(iconButton){
16128 this.subIconButtons.push(iconButton);
16130 this.isDropDownOpen = false;
16131 this.hideLeftLineRightButton = function(btn){
16132 var numButtons = this.subIconButtons.length;
16133 var buttonLeftOfRightMost = this.subIconButtons[numButtons - 2];
16134 var rightMostButton = this.subIconButtons[numButtons -1];
16136 if (btn != buttonLeftOfRightMost && btn != rightMostButton ){
16137 rightMostButton.setLeftLineHover(false);
16140 this.toggleDropdownState = function(isDropDownOpen){
16141 var numButtons = this.subIconButtons.length;
16142 if(numButtons > 2) {
16143 if(isDropDownOpen) {
16144 if(this.subIconButtons[numButtons - 2].isRightLineShown()) {
16145 this.subIconButtons[numButtons - 2].setRightLineHover(true);
16147 this.subIconButtons[numButtons - 1].setLeftLineHover(true);
16149 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.NEXT_TO_DROPDOWN);
16151 this.subIconButtons[numButtons - 1].setLeftLineHover(false);
16152 this.subIconButtons[numButtons - 2].setButtonType(iconStateConstants.MIDDLE);
16155 if(isDropDownOpen) {
16156 this.subIconButtons[0].setRightLineHover(true);
16157 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT_NEXT_TO_DROPDOWN);
16159 this.subIconButtons[0].setButtonType(iconStateConstants.LEFT);
16164 .directive('attSplitIconButtonGroup', ['$document', '$timeout', 'iconStateConstants' ,function($document,$timeout,iconStateConstants){
16170 require: 'attSplitIconButtonGroup',
16171 controller: 'AttSplitIconButtonGroupCtrl',
16172 templateUrl: 'app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html',
16174 link: function(scope,element,attr,ctrls){
16175 $timeout(initialize,100);
16176 function initialize(){
16177 var subIconButtonCtrls = ctrls.subIconButtons;
16178 var leftMostButtonIndex = 0;
16179 var rightMostButtonIndex =subIconButtonCtrls.length-1;
16180 //left most button config
16181 subIconButtonCtrls[leftMostButtonIndex].setButtonType(iconStateConstants.LEFT);
16182 subIconButtonCtrls[leftMostButtonIndex].isLeftLineShown(false);
16183 subIconButtonCtrls[leftMostButtonIndex].isRightLineShown(true);
16184 //right most button config
16185 subIconButtonCtrls[rightMostButtonIndex].setButtonType(iconStateConstants.RIGHT);
16186 subIconButtonCtrls[rightMostButtonIndex].isRightLineShown(false);
16187 subIconButtonCtrls[rightMostButtonIndex].isLeftLineShown(false);
16188 //middle buttons config
16189 if(rightMostButtonIndex >= 2) {
16191 while(index < rightMostButtonIndex) {
16192 subIconButtonCtrls[index].setButtonType(iconStateConstants.MIDDLE);
16193 subIconButtonCtrls[index].isRightLineShown(false);
16194 subIconButtonCtrls[index].isLeftLineShown(false);
16198 while(skipIndex <= rightMostButtonIndex){
16199 if(skipIndex == rightMostButtonIndex) {
16200 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
16202 subIconButtonCtrls[skipIndex].isRightLineShown(true);
16203 subIconButtonCtrls[skipIndex].isLeftLineShown(true);
16205 skipIndex = skipIndex + 2;
16208 //reposition the dropdown
16209 var ulElem = element.find('ul');
16210 if(ulElem.length > 0) {
16211 var numButtons = rightMostButtonIndex+1;
16212 if(numButtons > 2) {
16213 var offset = (numButtons)*34-70+(numButtons/1.5) + 0.5;
16214 var offSetStr = offset+'px';
16215 angular.element(ulElem).css('left',offSetStr);
16216 angular.element(ulElem).css('border-top-left-radius','0px');
16218 angular.element(ulElem).css('left','0px');
16226 angular.module('att.abs.stepSlider', ['att.abs.position'])
16227 .constant('sliderConstants', {
16229 The MIT License (MIT)
16230 Copyright (c) 2013 Julien Valéry
16243 className: "jslider",
16244 selector: ".jslider-"
16250 BLUE_HIGHLIGHT: 'blue',
16251 MAGENTA: 'magenta',
16254 DARK_BLUE: 'dark-blue',
16255 REGULAR: 'regular',
16259 .factory('utils', function () {
16261 The MIT License (MIT)
16262 Copyright (c) 2013 Julien Valéry
16265 offset: function (elm) {
16266 var rawDom = elm[0];
16269 var body = document.documentElement || document.body;
16270 var scrollX = window.pageXOffset || body.scrollLeft;
16271 var scrollY = window.pageYOffset || body.scrollTop;
16272 _x = rawDom.getBoundingClientRect().left + scrollX;
16273 _y = rawDom.getBoundingClientRect().top + scrollY;
16274 return {left: _x, top: _y};
16276 roundUpToScale: function (mousePrc, scale, cutOffWidth, cutOffIndex) {
16282 for (var index = 1; index < scale.length; index++) {
16283 lowerVal = scale[index - 1];
16284 higherVal = scale[index];
16285 middle = ((higherVal - lowerVal) * .5) + lowerVal;
16287 Handles a situation where the user clicks close to the start point of
16288 the slider but the pointer doesn't move
16290 if ((lowerVal === 0 && mousePrc <= middle) || checkEquality(lowerVal, mousePrc)) {
16291 newMousePrc = lowerVal;
16294 else if (lowerVal < mousePrc && (mousePrc < higherVal ||
16295 checkEquality(mousePrc, higherVal)))
16297 newMousePrc = higherVal;
16301 //Check if the newMousePrc is <= the cuttOffPoint
16302 if (cutOffWidth && newMousePrc < cutOffWidth) {
16303 return scale[cutOffIndex];
16306 return newMousePrc;
16309 Checks to see if 2 points are so close that they are
16312 function checkEquality(point1, point2) {
16313 var precision = 0.1;
16314 if (Math.abs(point2 - point1) <= precision) {
16320 valueForDifferentScale: function (from, to, prc, prcToValueMapper) {
16321 var decimalPrc = prc / 100;
16322 if (decimalPrc === 0) {
16325 return prcToValueMapper[prc];
16327 /* converts the default value Kbps to Mbps or Gbps */
16328 convertToMbpsGbps: function (unitValue, unitLabel, configDecimalPlaces) {
16329 var defaultDecimalPlaces = 3; /* this is the default decimal places as per business requirements */
16330 if (configDecimalPlaces) {
16331 defaultDecimalPlaces = configDecimalPlaces;
16334 if ((unitValue > 1024 && unitValue < 1000000) && angular.equals(unitLabel, 'Kbps')) {
16335 unitValue = truncator((unitValue/1000), defaultDecimalPlaces);
16336 unitLabel = 'Mbps';
16337 } else if ((unitValue > 1024 && unitValue < 1000000) && angular.equals(unitLabel, 'Mbps')){
16338 unitValue = truncator((unitValue/1000), defaultDecimalPlaces);
16339 unitLabel = 'Mbps';
16340 } else if (unitValue <= 1024 && angular.equals(unitLabel, 'Mbps')) {
16341 unitLabel = 'Kbps';
16343 unitLabel = 'Kbps';
16346 if (unitValue >= 1000000 && angular.equals(unitLabel, 'Kbps')) {
16347 unitValue = truncator((unitValue/1000000), defaultDecimalPlaces);
16348 unitLabel = 'Gbps';
16351 unitValue: unitValue,
16352 unitLabel: unitLabel
16355 function truncator(numToTruncate, intDecimalPlaces) {
16356 var cnvrtdNum = Math.pow(10, intDecimalPlaces);
16357 return ~~(numToTruncate * cnvrtdNum)/cnvrtdNum;
16360 getConversionFactorValue: function (value, conversion, firstDimension) {
16362 Loop through the conversion array and keep checking the
16365 if (value <= conversion[0].startVal) {
16368 scaledDimension: firstDimension
16372 for (var index in conversion) {
16373 var c = conversion[index];
16374 if (value > c.startVal) {
16378 var scaleFactor = conversion[endIndex].scaleFactor;
16379 var scaledVal = value / scaleFactor;
16380 var scaledDimension = conversion[endIndex].dimension;
16382 scaledVal: scaledVal,
16383 scaledDimension: scaledDimension
16388 .factory('sliderDraggable', ['utils', function (utils) {
16390 The MIT License (MIT)
16391 Copyright (c) 2013 Julien Valéry
16393 function Draggable() {
16394 this._init.apply(this, arguments);
16396 Draggable.prototype.oninit = function () {
16398 Draggable.prototype.events = function () {
16400 Draggable.prototype.onmousedown = function () {
16401 this.ptr.css({position: "absolute"});
16403 Draggable.prototype.onmousemove = function (evt, x, y) {
16404 this.ptr.css({left: x, top: y});
16406 Draggable.prototype.onmouseup = function () {
16408 Draggable.prototype.isDefault = {
16414 Draggable.prototype._init = function () {
16415 if (arguments.length > 0) {
16416 this.ptr = arguments[0];
16417 this.parent = arguments[2];
16422 angular.extend(this.is, this.isDefault);
16423 var offset = utils.offset(this.ptr);
16427 width: this.ptr[0].clientWidth,
16428 height: this.ptr[0].clientHeight
16430 this.oninit.apply(this, arguments);
16434 Draggable.prototype._getPageCoords = function (event) {
16436 if (event.targetTouches && event.targetTouches[0]) {
16437 value = {x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY};
16439 value = {x: event.pageX, y: event.pageY};
16443 Draggable.prototype._bindEvent = function (ptr, eventType, handler) {
16444 if (this.supportTouches_) {
16445 ptr[0].attachEvent(this.events_[ eventType ], handler);
16449 ptr.bind(this.events_[ eventType ], handler);
16453 Draggable.prototype._events = function () {
16455 this.supportTouches_ = 'ontouchend' in document;
16457 "click": this.supportTouches_ ? "touchstart" : "click",
16458 "down": this.supportTouches_ ? "touchstart" : "mousedown",
16459 "move": this.supportTouches_ ? "touchmove" : "mousemove",
16460 "up": this.supportTouches_ ? "touchend" : "mouseup",
16461 "mousedown": this.supportTouches_ ? "mousedown" : "mousedown"
16463 var documentElt = angular.element(window.document);
16464 this._bindEvent(documentElt, "move", function (event) {
16465 if (self.is.drag) {
16466 event.stopPropagation();
16467 event.preventDefault();
16468 if (!self.parent.disabled) {
16469 self._mousemove(event);
16473 this._bindEvent(documentElt, "down", function (event) {
16474 if (self.is.drag) {
16475 event.stopPropagation();
16476 event.preventDefault();
16479 this._bindEvent(documentElt, "up", function (event) {
16480 self._mouseup(event);
16482 this._bindEvent(this.ptr, "down", function (event) {
16483 self._mousedown(event);
16486 this._bindEvent(this.ptr, "up", function (event) {
16487 self._mouseup(event);
16491 Draggable.prototype._mousedown = function (evt) {
16492 this.is.drag = true;
16493 this.is.clicked = false;
16494 this.is.mouseup = false;
16495 var coords = this._getPageCoords(evt);
16496 this.cx = coords.x - this.ptr[0].offsetLeft;
16497 this.cy = coords.y - this.ptr[0].offsetTop;
16498 angular.extend(this.d, {
16499 left: this.ptr[0].offsetLeft,
16500 top: this.ptr[0].offsetTop,
16501 width: this.ptr[0].clientWidth,
16502 height: this.ptr[0].clientHeight
16504 if (this.outer && this.outer.get(0)) {
16505 this.outer.css({height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden"});
16507 this.onmousedown(evt);
16509 Draggable.prototype._mousemove = function (evt) {
16510 if (this.uid === 0) {
16513 this.is.toclick = false;
16514 var coords = this._getPageCoords(evt);
16515 this.onmousemove(evt, coords.x - this.cx, coords.y - this.cy);
16517 Draggable.prototype._mouseup = function (evt) {
16518 if (this.is.drag) {
16519 this.is.drag = false;
16520 if (this.outer && this.outer.get(0)) {
16521 if ($.browser.mozilla) {
16522 this.outer.css({overflow: "hidden"});
16524 this.outer.css({overflow: "visible"});
16526 if ($.browser.msie && $.browser.version === '6.0') {
16527 this.outer.css({height: "100%"});
16529 this.outer.css({height: "auto"});
16532 this.onmouseup(evt);
16537 .factory('sliderPointer', ['sliderDraggable', 'utils', function (Draggable, utils) {
16539 The MIT License (MIT)
16540 Copyright (c) 2013 Julien Valéry
16542 function SliderPointer() {
16543 Draggable.apply(this, arguments);
16545 SliderPointer.prototype = new Draggable();
16546 SliderPointer.prototype.oninit = function (ptr, id, _constructor) {
16548 this.parent = _constructor;
16550 this.settings = angular.copy(_constructor.settings);
16552 SliderPointer.prototype.onmousedown = function (evt) {
16553 var off = utils.offset(this.parent.domNode);
16557 width: this.parent.domNode[0].clientWidth,
16558 height: this.parent.domNode[0].clientHeight
16562 width: offset.width,
16563 height: offset.height
16565 this.ptr.addClass("jslider-pointer-hover");
16566 this.setIndexOver();
16568 SliderPointer.prototype.onmousemove = function (evt, x, y) {
16569 var coords = this._getPageCoords(evt);
16570 //val is the percent where the slider pointer is located
16571 var val = this.calc(coords.x);
16572 if (!this.parent.settings.smooth) {
16573 val = utils.roundUpToScale(val,
16574 this.parent.settings.scale,
16575 this.parent.settings.cutOffWidth,
16576 this.parent.settings.cutOffIndex);
16578 var cutOffWidth = this.parent.settings.cutOffWidth;
16579 if (cutOffWidth && val < cutOffWidth) {
16584 SliderPointer.prototype.onmouseup = function (evt) {
16585 if (this.settings.callback && angular.isFunction(this.settings.callback)) {
16586 var val = this.parent.getValue();
16587 this.settings.callback.call(this.parent, val);
16589 this.ptr.removeClass("jslider-pointer-hover");
16591 SliderPointer.prototype.setIndexOver = function () {
16592 this.parent.setPointersIndex(1);
16595 SliderPointer.prototype.index = function (i) {
16597 SliderPointer.prototype.limits = function (x) {
16598 return this.parent.limits(x, this);
16600 SliderPointer.prototype.calc = function (coords) {
16601 var diff = coords - this._parent.offset.left;
16602 var val = this.limits((diff * 100) / this._parent.width);
16605 SliderPointer.prototype.set = function (value, opt_origin) {
16606 this.value.origin = this.parent.round(value);
16607 this._set(this.parent.valueToPrc(value, this), opt_origin);
16609 SliderPointer.prototype._set = function (prc, opt_origin) {
16611 this.value.origin = this.parent.prcToValue(prc);
16613 this.value.prc = prc;
16614 //Sets the location of the SliderPointer
16615 this.ptr.css({left: prc + '%'});
16616 this.parent.redraw(this);
16618 return SliderPointer;
16620 .factory('slider', ['sliderPointer', 'sliderConstants', 'utils', function (SliderPointer, sliderConstants, utils) {
16622 The MIT License (MIT)
16623 Copyright (c) 2013 Julien Valéry
16626 function Slider() {
16627 return this.init.apply(this, arguments);
16629 function changeCutOffWidth(width) {
16630 cutOffDom.css('width', width);
16633 Slider.prototype.changeCutOffWidth = changeCutOffWidth;
16634 Slider.prototype.init = function (inputNode, templateNode, settings) {
16635 this.settings = sliderConstants.SLIDER.settings;
16636 angular.extend(this.settings, angular.copy(settings));
16637 this.inputNode = inputNode;
16638 this.inputNode.addClass("ng-hide");
16639 this.settings.interval = this.settings.to - this.settings.from;
16640 if (this.settings.calculate && $.isFunction(this.settings.calculate)) {
16641 this.nice = this.settings.calculate;
16643 if (this.settings.onstatechange && $.isFunction(this.settings.onstatechange)) {
16644 this.onstatechange = this.settings.onstatechange;
16646 this.is = {init: false};
16648 this.create(templateNode);
16650 Slider.prototype.create = function (templateNode) {
16652 this.domNode = templateNode;
16653 var off = utils.offset(this.domNode);
16657 width: this.domNode[0].clientWidth,
16658 height: this.domNode[0].clientHeight
16660 this.sizes = {domWidth: this.domNode[0].clientWidth, domOffset: offset};
16661 angular.extend(this.o, {
16665 o: angular.element(this.domNode.find('div')[5])
16668 o: angular.element(this.domNode.find('div')[6])
16672 0: angular.element(this.domNode.find('div')[3]),
16673 1: angular.element(this.domNode.find('div')[5])
16676 angular.extend(this.o.labels[0], {
16677 value: this.o.labels[0].o.find("span")
16679 angular.extend(this.o.labels[1], {
16680 value: this.o.labels[1].o.find("span")
16682 if (!$this.settings.value.split(";")[1]) {
16683 this.settings.single = true;
16685 var domNodeDivs = this.domNode.find('div');
16686 cutOffDom = angular.element(domNodeDivs[8]);
16687 if (cutOffDom && cutOffDom.css) {
16688 cutOffDom.css('width', '0%');
16690 var pointers = [angular.element(domNodeDivs[1]), angular.element(domNodeDivs[2])];
16691 angular.forEach(pointers, function (pointer, key) {
16692 $this.settings = angular.copy($this.settings);
16693 var value = $this.settings.value.split(';')[key];
16695 $this.o.pointers[key] = new SliderPointer(pointer, key, $this);
16696 var prev = $this.settings.value.split(';')[key - 1];
16697 if (prev && parseInt(value, 10) < parseInt(prev, 10)) {
16700 var value1 = value < $this.settings.from ? $this.settings.from : value;
16701 value1 = value > $this.settings.to ? $this.settings.to : value;
16702 $this.o.pointers[key].set(value1, true);
16704 $this.domNode.bind('mousedown', $this.clickHandler.apply($this));
16708 this.o.value = angular.element(this.domNode.find("i")[2]);
16709 this.is.init = true;
16710 angular.forEach(this.o.pointers, function (pointer) {
16711 $this.redraw(pointer);
16714 Slider.prototype.clickHandler = function () {
16716 return function (evt) {
16717 if (self.disabled) {
16720 var className = evt.target.className;
16722 if (className.indexOf('jslider-pointer-to') > 0) {
16725 var _off = utils.offset(self.domNode);
16729 width: self.domNode[0].clientWidth,
16730 height: self.domNode[0].clientHeight
16733 var targetPtr = self.o.pointers[targetIdx];
16734 targetPtr._parent = {offset: offset, width: offset.width, height: offset.height};
16735 targetPtr._mousemove(evt);
16736 targetPtr.onmouseup();
16740 Slider.prototype.disable = function (bool) {
16741 this.disabled = bool;
16743 Slider.prototype.nice = function (value) {
16746 Slider.prototype.onstatechange = function () {
16748 Slider.prototype.limits = function (x, pointer) {
16749 if (!this.settings.smooth) {
16750 var step = this.settings.step * 100 / (this.settings.interval);
16751 x = Math.round(x / step) * step;
16753 var another = this.o.pointers[1 - pointer.uid];
16754 if (another && pointer.uid && x < another.value.prc) {
16755 x = another.value.prc;
16757 if (another && !pointer.uid && x > another.value.prc) {
16758 x = another.value.prc;
16766 var val = Math.round(x * 10) / 10;
16769 Slider.prototype.setPointersIndex = function (i) {
16770 angular.forEach(this.getPointers(), function (pointer, i) {
16774 Slider.prototype.getPointers = function () {
16775 return this.o.pointers;
16777 Slider.prototype.onresize = function () {
16780 domWidth: this.domNode[0].clientWidth,
16781 domHeight: this.domNode[0].clientHeight,
16783 left: this.domNode[0].offsetLeft,
16784 top: this.domNode[0].offsetTop,
16785 width: this.domNode[0].clientWidth,
16786 height: this.domNode[0].clientHeight
16789 angular.forEach(this.o.pointers, function (ptr, key) {
16793 Slider.prototype.update = function () {
16797 Slider.prototype.drawScale = function () {
16799 Slider.prototype.redraw = function (pointer) {
16800 if (!this.settings.smooth) {
16801 var newMousePrc = utils.roundUpToScale(pointer.value.prc,
16802 this.settings.scale,
16803 this.settings.cutOffWidth,
16804 this.settings.cutOffIndex);
16805 pointer.value.origin = newMousePrc;
16806 pointer.value.prc = newMousePrc;
16809 if (!this.is.init) {
16813 var width = this.o.pointers[1].value.prc;
16814 var newPos = {left: '0%', width: width + '%'};
16815 this.o.value.css(newPos);
16816 var htmlValue = this.nice(pointer.value.origin);
16817 var scaledDimension = this.settings.firstDimension;
16818 if (this.settings.stepWithDifferentScale && !this.settings.smooth) {
16819 htmlValue = utils.valueForDifferentScale(this.settings.from,
16820 this.settings.to, htmlValue, this.settings.prcToValueMapper);
16822 //This is the base value before the conversion
16823 if (this.settings.realtimeCallback && angular.isFunction(this.settings.realtimeCallback)
16824 && this.settings.cutOffVal !== undefined && pointer.uid === 1) {
16825 this.settings.realtimeCallback(htmlValue);
16827 //Need to change this to the correct value for the scale
16828 if (this.settings.conversion) {
16829 var conversionObj = utils.getConversionFactorValue(parseInt(htmlValue),
16830 this.settings.conversion,
16831 this.settings.firstDimension);
16832 htmlValue = conversionObj.scaledVal;
16833 scaledDimension = conversionObj.scaledDimension;
16836 htmlValue = parseFloat(htmlValue);
16837 var tooltipLabel = utils.convertToMbpsGbps(htmlValue, scaledDimension, this.settings.decimalPlaces);
16839 this.o.labels[pointer.uid].value.html(tooltipLabel.unitValue + ' ' + tooltipLabel.unitLabel);
16840 //Top tooltip label
16841 this.redrawLabels(pointer);
16843 Slider.prototype.redrawLabels = function (pointer) {
16844 function setPosition(label, sizes, prc) {
16845 sizes.margin = -sizes.label / 2;
16846 var domSize = self.sizes.domWidth;
16847 var label_left = sizes.border + sizes.margin;
16848 if (label_left < 0) {
16849 sizes.margin -= label_left;
16851 if (sizes.border + sizes.label / 2 > domSize) {
16853 sizes.right = true;
16855 sizes.right = false;
16856 //Adjust the tooltip location
16857 sizes.margin = -((label.o[0].clientWidth / 2) - label.o[0].clientWidth / 20);
16858 label.o.css({left: prc + "%", marginLeft: sizes.margin, right: "auto"});
16860 label.o.css({left: "auto", right: 0});
16864 var label = this.o.labels[pointer.uid];
16865 var prc = pointer.value.prc;
16867 label: label.o[0].offsetWidth,
16869 border: (prc * domSize) / 100
16871 var another_label = null;
16872 var another = null;
16873 if (!this.settings.single) {
16874 another = this.o.pointers[1 - pointer.uid];
16875 another_label = this.o.labels[another.uid];
16876 switch (pointer.uid) {
16878 if (sizes.border + sizes.label / 2 > another_label.o[0].offsetLeft - this.sizes.domOffset.left) {
16879 another_label.o.css({visibility: "hidden"});
16880 another_label.value.html(this.nice(another.value.origin));
16881 label.o.css({visibility: "hidden"});
16882 prc = (another.value.prc - prc) / 2 + prc;
16883 if (another.value.prc !== pointer.value.prc) {
16884 label.value.html(this.nice(pointer.value.origin) + " – " + this.nice(another.value.origin));
16885 sizes.label = label.o[0].clientWidth;
16886 sizes.border = (prc * domSize) / 100;
16889 another_label.o.css({visibility: "visible"});
16893 if (sizes.border - sizes.label / 2 < another_label.o[0].offsetLeft - this.sizes.domOffset.left + another_label.o[0].clientWidth) {
16894 another_label.o.css({visibility: "hidden"});
16895 another_label.value.html(this.nice(another.value.origin));
16896 label.o.css({visibility: "visible"});
16897 prc = (prc - another.value.prc) / 2 + another.value.prc;
16898 if (another.value.prc !== pointer.value.prc) {
16899 label.value.html(this.nice(another.value.origin) + " – " + this.nice(pointer.value.origin));
16900 sizes.label = label.o[0].clientWidth;
16901 sizes.border = (prc * domSize) / 100;
16904 another_label.o.css({visibility: "visible"});
16909 sizes = setPosition(label, sizes, prc);
16910 var domSize = self.sizes.domWidth;
16911 //This is the 0th pointer
16912 if (another_label) {
16914 label: another_label.o[0].clientWidth,
16916 border: (another.value.prc * this.sizes.domWidth) / 100
16918 sizes = setPosition(another_label, sizes, another.value.prc);
16921 Slider.prototype.redrawLimits = function () {
16922 if (this.settings.limits) {
16923 var limits = [true, true];
16924 for (var key in this.o.pointers) {
16925 if (!this.settings.single || key === 0) {
16926 var pointer = this.o.pointers[key];
16927 var label = this.o.labels[pointer.uid];
16928 var label_left = label.o[0].offsetLeft - this.sizes.domOffset.left;
16929 var limit = this.o.limits[0];
16930 if (label_left < limit[0].clientWidth)
16932 limit = this.o.limits[1];
16933 if (label_left + label.o[0].clientWidth > this.sizes.domWidth - limit[0].clientWidth)
16937 for (var i = 0; i < limits.length; i++) {
16939 angular.element(this.o.limits[i]).addClass("animate-show");}
16941 angular.element(this.o.limits[i]).addClass("animate-hidde");}
16945 Slider.prototype.setValue = function () {
16946 var value = this.getValue();
16947 this.inputNode.attr("value", value);
16948 this.onstatechange.call(this, value, this.inputNode);
16950 Slider.prototype.getValue = function () {
16951 if (!this.is.init){
16955 angular.forEach(this.o.pointers, function (pointer, key) {
16956 if (pointer.value.prc !== undefined && !isNaN(pointer.value.prc)) {
16957 var pointerPrc = pointer.value.prc;
16958 var myValue = $this.prcToValue(pointerPrc);
16959 if (!$this.settings.smooth) {
16960 var myValue = utils.valueForDifferentScale($this.settings.from,
16963 $this.settings.prcToValueMapper);
16965 value += (key > 0 ? ";" : "") + myValue;
16970 Slider.prototype.getPrcValue = function () {
16974 $.each(this.o.pointers, function (i) {
16975 if (this.value.prc !== undefined && !isNaN(this.value.prc))
16976 value += (i > 0 ? ";" : "") + this.value.prc;
16980 Slider.prototype.prcToValue = function (prc) {
16982 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
16983 var h = this.settings.heterogeneity;
16985 var _from = this.settings.from;
16986 for (var i = 0; i <= h.length; i++) {
16989 v = h[i].split("/");}
16991 v = [100, this.settings.to];}
16992 if (prc >= _start && prc <= v[0]) {
16993 value = _from + ((prc - _start) * (v[1] - _from)) / (v[0] - _start);
17000 value = this.settings.from + (prc * this.settings.interval) / 100;
17002 var roundedValue = this.round(value);
17003 return roundedValue;
17005 Slider.prototype.valueToPrc = function (value, pointer) {
17007 if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
17008 var h = this.settings.heterogeneity;
17010 var _from = this.settings.from;
17011 for (var i = 0; i <= h.length; i++) {
17014 v = h[i].split("/");
17016 v = [100, this.settings.to];
17017 if (value >= _from && value <= v[1]) {
17018 prc = pointer.limits(_start + (value - _from) * (v[0] - _start) / (v[1] - _from));
17024 prc = pointer.limits((value - this.settings.from) * 100 / this.settings.interval);
17028 Slider.prototype.round = function (value) {
17029 value = Math.round(value / this.settings.step) * this.settings.step;
17030 if (this.settings.round){
17031 value = Math.round(value * Math.pow(10, this.settings.round)) / Math.pow(10, this.settings.round);}
17033 value = Math.round(value);}
17038 .directive('attStepSlider', [
17039 '$compile', '$templateCache', '$timeout', '$window', 'slider', 'sliderConstants', 'utils',
17040 function (compile, templateCache, timeout, win, Slider, sliderConstants, utils) {
17042 The MIT License (MIT)
17043 Copyright (c) 2013 Julien Valéry
17045 var templateUrl = 'app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html';
17048 require: '?ngModel',
17054 templateUrl: templateUrl,
17055 link: function (scope, element, attrs, ngModel) {
17058 scope.mainSliderClass = 'step-slider';
17059 element.after(compile(templateCache.get(templateUrl))(scope, function (clonedElement, scope) {
17060 scope.tmplElt = clonedElement;
17062 ngModel.$render = function () {
17063 if (ngModel.$viewValue.split && ngModel.$viewValue.split(";").length === 1) {
17064 ngModel.$viewValue = '0;' + ngModel.$viewValue;
17065 } else if (typeof (ngModel.$viewValue) === 'number') {
17066 ngModel.$viewValue = '0;' + ngModel.$viewValue;
17068 if (!ngModel.$viewValue && ngModel.$viewValue !== 0) {
17071 if (typeof (ngModel.$viewValue) === 'number') {
17072 ngModel.$viewValue = '' + ngModel.$viewValue;
17074 if (scope.slider) {
17075 var firstPointer = '0';
17076 scope.slider.getPointers()[0].set(firstPointer, true);
17077 if (ngModel.$viewValue.split(";")[1]) {
17078 var value = ngModel.$viewValue.split(";")[1];
17079 if (value.length >= 4) {
17080 value = value.substring(0, 2);
17082 if (!scope.options.realtime)
17083 scope.options.callback(parseFloat(ngModel.$viewValue.split(";")[1]));
17084 scope.slider.getPointers()[1].set(ngModel.$viewValue.split(";")[1], true);
17088 var init = function () {
17089 scope.from = '' + scope.options.from;
17090 scope.to = '' + scope.options.to;
17091 if (scope.options.calculate && typeof scope.options.calculate === 'function') {
17092 scope.from = scope.options.calculate(scope.from);
17093 scope.to = scope.options.calculate(scope.to);
17095 scope.showDividers = scope.options.showDividers;
17096 scope.COLORS = sliderConstants.COLORS;
17097 scope.sliderColor = scope.options.sliderColor;
17098 if (!scope.sliderColor)
17099 scope.sliderColor = sliderConstants.COLORS.REGULAR;
17100 var scaleArray = scope.options.scale;
17101 /* Make a copy of the scaleArray before converting it to percentage for the bars */
17102 var nonPercentScaleArray = [];
17103 /* Define variable for displaying lower range values */
17104 var scaledUpValueArray=[];
17105 /* Create Mapper for the percentage to value */
17106 var prcToValueMapper = {};
17107 for (var i in scaleArray) {
17108 var s = scaleArray[i];
17109 nonPercentScaleArray.push(s);
17111 function addScaleArrayStartAndEnd() {
17112 if (scaleArray[0] !== 0) {
17113 scaleArray.splice(0, 0, 0);
17115 if (scaleArray[scaleArray.length - 1] !== 100) {
17116 scaleArray.splice(scaleArray.length, 0, 100);
17119 function convertScaleArrayToPercentage() {
17120 if (scaleArray[scaleArray.length - 1] !== scope.options.to) {
17121 scaleArray.splice(scaleArray.length, 0, scope.options.to);
17124 if(scope.options.displayScaledvalues){
17125 for(var i in scaleArray){
17126 scaledUpValueArray.push(Math.log2(scaleArray[i]));
17128 var maxScaledUpValue=scaledUpValueArray[scaledUpValueArray.length-1];
17131 for (var i in scaleArray) {
17133 var fromValueCheck = (scaleArray[i] / scope.options.from);
17134 var toValueCheck = (scaleArray[i] / scope.options.to);
17136 if (scope.options.displayScaledvalues){
17137 prcValue = (scaledUpValueArray[i] /maxScaledUpValue)*100;
17139 prcValue = ((scaleArray[i] - scope.options.from) / (scope.options.to - scope.options.from)) * 100;
17142 var realValue = scaleArray[i];
17144 if (toValueCheck === 1) {
17147 else if (fromValueCheck === 1) {
17150 scaleArray[i] = prcValue;
17151 prcToValueMapper['' + prcValue] = realValue;
17154 if ((scope.options.from !== 0 || scope.options.to !== 100)
17155 && scope.options.smooth) {
17157 scale array is in real values.
17159 addScaleArrayStartAndEnd();
17160 scope.options.stepWithDifferentScale = true;
17162 else if ((scope.options.from !== 0 || scope.options.to !== 100)
17163 && !scope.options.smooth) {
17165 Case for different from and to values other than 0 and 100
17166 so we have to do some different calculations
17168 scope.options.stepWithDifferentScale = true;
17169 convertScaleArrayToPercentage();
17170 addScaleArrayStartAndEnd();
17174 This is the normal case where the from and to values are 0 and
17177 //Check that the scale starts at 0 and 100
17178 convertScaleArrayToPercentage();
17179 addScaleArrayStartAndEnd();
17181 var decimalPlaces = 0;
17182 if (scope.options.decimalPlaces) {
17183 decimalPlaces = scope.options.decimalPlaces;
17185 //Modify the endDimension based on whether converison was passed in
17186 //Also change the toStr value to scale to the last factor
17187 scope.endDimension = scope.options.dimension;
17188 if (scope.options.conversion) {
17189 //Get the dimension of the last conversion
17190 var lastIndex = scope.options.conversion.length - 1;
17191 var lastDimension = scope.options.conversion[lastIndex].dimension;
17192 var lastScaleFactor = scope.options.conversion[lastIndex].scaleFactor;
17193 scope.endDimension = ' ' + lastDimension;
17195 var toVal = (scope.to / lastScaleFactor).toFixed(decimalPlaces);
17196 scope.toStr = toVal;
17198 scope.toStr = scope.options.to;
17201 var tooltipLabel = utils.convertToMbpsGbps(scope.toStr, scope.endDimension, scope.options.decimalPlaces);
17202 scope.toStr = tooltipLabel.unitValue;
17203 scope.endDimension = ' ' + tooltipLabel.unitLabel;
17206 from: scope.options.from,
17207 to: scope.options.to,
17208 step: scope.options.step,
17209 smooth: scope.options.smooth,
17211 stepWithDifferentScale: scope.options.stepWithDifferentScale,
17212 round: scope.options.round || false,
17213 value: ngModel.$viewValue,
17214 scale: scope.options.scale,
17215 nonPercentScaleArray: nonPercentScaleArray,
17216 prcToValueMapper: prcToValueMapper,
17217 firstDimension: scope.options.dimension,
17218 decimalPlaces: decimalPlaces,
17219 conversion: scope.options.conversion,
17220 realtimeCallback: scope.options.callback
17222 if (angular.isFunction(scope.options.realtime)) {
17223 OPTIONS.realtimeCallback = function (value) {
17224 ngModel.$setViewValue(value);
17225 scope.options.callback(value);
17229 OPTIONS.callback = forceApply;
17231 OPTIONS.calculate = scope.options.calculate || undefined;
17232 OPTIONS.onstatechange = scope.options.onstatechange || undefined;
17233 timeout(function () {
17234 var scaleDiv = scope.tmplElt.find('div')[7];
17235 if (!OPTIONS.conversion) {
17236 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-left', '10px');
17237 scope.tmplElt.find('div').eq(6).find('span').eq(0).css('padding-right', '15px');
17239 scope.slider = angular.element.slider(element, scope.tmplElt, OPTIONS);
17240 angular.element(scaleDiv).html(scope.generateScale());
17241 scope.drawScale(scaleDiv);
17243 scope.$watch('options.disable', function (val) {
17244 if (scope.slider) {
17245 scope.tmplElt.toggleClass('disabled', val);
17246 scope.slider.disable(val);
17249 scope.$watch('cutOff', function (cutOffVal) {
17250 if (cutOffVal && cutOffVal > 0) {
17251 var cutOffPrc = (cutOffVal - scope.slider.settings.from) / (scope.slider.settings.to -
17252 scope.slider.settings.from);
17253 cutOffPrc = cutOffPrc * 100;
17254 scope.isCutOffSlider = true;
17255 scope.slider.settings.cutOffWidth = cutOffPrc;
17256 //cutOffVal is the actual value of the cutoff point
17257 scope.cutOffVal = cutOffVal;
17258 if (scope.options.conversion) {
17259 var convertedVal = utils.getConversionFactorValue(cutOffVal, scope.options.conversion, scope.options.dimension);
17260 convertedVal.scaledVal = parseFloat(convertedVal.scaledVal).toFixed(scope.options.decimalPlaces);
17261 scope.cutOffVal = convertedVal.scaledVal + ' ' + convertedVal.scaledDimension;
17263 scope.slider.settings.cutOffVal = cutOffVal;
17264 //Calculate the cutOff percentage
17265 scope.slider.changeCutOffWidth(cutOffPrc + '%');
17266 var scale = scope.slider.settings.nonPercentScaleArray;
17267 //Calculate where the cutOff point in relation to the scale array
17268 for (var i in scale) {
17270 var lowerVal = scale[i - 1];
17271 var higherVal = scale[i];
17272 if (cutOffVal > lowerVal && cutOffVal <= higherVal) {
17273 scope.slider.settings.cutOffIndex = i;
17278 scope.slider.settings.cutOffVal = 0;
17283 function initListener() {
17284 angular.element(win).bind('resize', function (event) {
17285 scope.slider.onresize();
17288 scope.generateScale = function () {
17289 if (scope.options.scale && scope.options.scale.length > 0) {
17291 var s = scope.options.scale;
17292 var position = 'left';
17293 for (var i = 0; i < s.length; i++) {
17294 if (i !== 0 && i !== s.length - 1) {
17295 var scaledPosition = ((s[i] - scope.from) / (scope.to - scope.from)) * 100;
17296 if (scope.options.stepWithDifferentScale && !scope.options.smooth) {
17297 scaledPosition = s[i];
17299 str += '<span style="' + position + ': ' + scaledPosition + '%"></span>';
17307 scope.drawScale = function (scaleDiv) {
17308 angular.forEach(angular.element(scaleDiv).find('ins'), function (scaleLabel, key) {
17309 scaleLabel.style.marginLeft = -scaleLabel.clientWidth / 2;
17312 var forceApply = function (value) {
17313 var val = value.split(";")[1];
17314 scope.$apply(function () {
17315 ngModel.$setViewValue(parseInt(val));
17317 if (scope.options.callback) {
17318 scope.options.callback(parseInt(val));
17321 scope.$watch('options', function (value) {
17324 angular.element.slider = function (inputElement, element, settings) {
17325 if (!element.data('jslider'))
17326 element.data('jslider', new Slider(inputElement, element, settings));
17327 var sliderObj = element.data('jslider');
17333 angular.module('att.abs.steptracker', ['att.abs.transition'])
17334 .directive('steptracker', ['$timeout', function ($timeout) {
17336 // This allows dev's clickHandler to cancel an operation
17340 cstep: "=currentStep",
17341 clickHandler: '=?',
17346 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/step-tracker.html',
17347 link: function (scope, elem) {
17348 if (scope.disableClick === undefined) {
17349 scope.disableClick = false;
17351 $timeout(function () {
17352 if (scope.cstep < 1) {
17355 else if (scope.cstep > scope.sdata.length) {
17356 scope.cstep = scope.sdata.length;
17358 var divs = elem.find('div');
17359 var slidertracks = [];
17360 for (var i in divs) {
17361 if (divs.eq(i)[0]) {
17362 var el = divs.eq(i)[0].className;
17363 if (el.indexOf('track ng-scope') > -1) {
17364 slidertracks.push(divs.eq(i));
17368 var currentPage,totalPage,currentTrack = updateCurrentTrack(scope.cstep);
17369 function updateCurrentTrack(step) {
17370 // Always return the step-1 because array starts at 0
17371 return angular.element(slidertracks[step - 1]);
17373 function updateTrackWidth() {
17374 if (scope.cstep > 0 && scope.cstep <= scope.sdata.length - 1 && currentPage > 0) {
17375 var newWidth = ((currentPage / totalPage) * 100) + "%";
17376 currentTrack = updateCurrentTrack(scope.cstep);
17377 currentTrack.css('width', newWidth);
17380 function updatePages() {
17381 if (scope.cstep <= scope.sdata.length) {
17382 currentPage = scope.sdata[scope.cstep - 1]['currentPage'];
17383 totalPage = scope.sdata[scope.cstep - 1]['totalPages'];
17386 // dynamically add width for steps, depending on the number of steps.
17387 scope.set_width = function (indexval) {
17388 var setwidth = (100 / (scope.sdata.length - 1)) + "%";
17389 // skip last element and add width for all other element
17390 if ((scope.sdata.length - 1) > indexval) {
17391 return {'width': setwidth};
17394 scope.$watch('sdata', function () {
17396 var prevStep = scope.cstep;
17397 // Before anything, ensure currentPage is never below 1
17398 if (currentPage < 1) {
17400 if (scope.cstep !== 1) {
17401 // Decrease step, current track width is 0%, new step width updates
17406 // Move to next step, reset currentPage, totalPage, and ensure previous steps are completed
17407 if (currentPage > totalPage) {
17408 if (scope.cstep > scope.sdata.length - 1) {
17412 currentPage = totalPage;
17413 updateTrackWidth();
17416 updateTrackWidth();
17419 if (currentPage < 1 && prevStep === scope.cstep) {
17421 if (scope.cstep > 1) {
17423 scope.sdata[scope.cstep - 1]['currentPage'] = scope.sdata[scope.cstep - 1]['totalPages'];
17424 scope.sdata[scope.cstep]['currentPage'] = 1;
17427 updateTrackWidth();
17429 //add the active class for current step
17430 scope.activestep = function (index) {
17431 return (index === scope.cstep - 1);
17433 //add the done class for finished step
17434 scope.donesteps = function (index) {
17435 return (index < scope.cstep - 1);
17437 //add the last class for final step
17438 scope.laststep = function (index) {
17439 return (index === scope.sdata.length - 1);
17441 scope.isIncomplete = function (index) {
17442 if (index === scope.cstep - 1) {
17445 if (index >= 0 && index < scope.sdata.length - 1) {
17446 var step = scope.sdata[index];
17447 return (step['currentPage'] <= step['totalPages']);
17451 scope.stepclick = function ($event, steps) {
17452 // If we are decreasing steps, reset all currentPage counts to 1
17453 if (steps < scope.cstep) {
17454 for (var i = scope.cstep - 1; i > steps; i--) {
17455 scope.sdata[i]['currentPage'] = 1;
17457 scope.sdata[steps]['currentPage']--;
17459 if (angular.isFunction(scope.clickHandler)) {
17460 scope.clickHandler($event, steps);
17462 scope.cstep = steps + 1;
17463 // In the case we decremented previously from this step, we need to reset currentpage to default
17464 if (scope.cstep <= scope.sdata.length && scope.sdata[scope.cstep]['currentPage'] < 1) {
17465 scope.sdata[scope.cstep]['currentPage'] = 1;
17468 updateTrackWidth();
17475 .constant('timelineConstants', {
17478 COMPLETED: 'completed',
17479 CANCELLED: 'cancelled'
17482 .controller('AttTimelineCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
17483 var timelineBarCtrls = [];
17484 var timelineDotCtrls = [];
17486 this.isAlternate = function () {
17487 return $scope.alternate;
17489 this.addTimelineBarCtrls = function (t) {
17490 timelineBarCtrls.push(t);
17492 this.addTimelineDotCtrls = function (b) {
17493 timelineDotCtrls.push(b);
17495 $timeout(init, 200);
17497 function compare(a, b) {
17498 if (a.order < b.order) {
17501 if (a.order > b.order) {
17506 timelineDotCtrls.sort(compare);
17507 timelineBarCtrls.sort(compare);
17508 if ($scope.$parent.animate) {
17511 $scope.$watch('trigger', function (val) {
17513 $scope.resetTimeline();
17515 $scope.$parent.animate = false;
17519 function animateSequence() {
17520 var dotsDuration = .25;
17521 var timelineBarProgressDuration = .25;
17522 if (typeof $scope.barAnimateDuration === 'number') {
17523 timelineBarProgressDuration = $scope.barAnimateDuration;
17525 var start = createAnimation(0, timelineBarProgressDuration);
17526 function setToInactiveStates() {
17527 for (var i in timelineDotCtrls) {
17528 var dotCtrl = timelineDotCtrls[i];
17530 dotCtrl.unhoveredStateForBelow(.25);
17532 dotCtrl.unhoveredStateForAbove(.25);
17534 if (dotCtrl.isStop()) {
17539 function createAnimation(i, duration) {
17541 return function () {
17542 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
17543 timelineBarCtrls[i].isCancelled(true);
17545 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17547 } else if (i === timelineBarCtrls.length - 1) {
17548 return function () {
17549 //Removes the bolded text from the start
17550 if (timelineDotCtrls[0].isCurrentStep()) {
17551 timelineDotCtrls[0].isCurrentStep(false);
17553 if (timelineDotCtrls[i].isStop()) {
17554 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17555 timelineDotCtrls[i].isCurrentStep(true);
17557 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17558 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17560 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17561 $timeout(function () {
17562 setToInactiveStates();
17567 else if (i === timelineBarCtrls.length) {
17568 return function () {
17569 //Removes the bolded text from the start
17570 if (timelineDotCtrls[0].isCurrentStep()) {
17571 timelineDotCtrls[0].isCurrentStep(false);
17573 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17574 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17575 timelineDotCtrls[i].isCurrentStep(true);
17576 $timeout(function () {
17577 setToInactiveStates();
17582 return function () {
17583 //Removes the bolded text from the start
17584 if (timelineDotCtrls[0].isCurrentStep()) {
17585 timelineDotCtrls[0].isCurrentStep(false);
17587 if (timelineDotCtrls[i].isStop()) {
17588 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17589 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17590 timelineDotCtrls[i].isCurrentStep(true);
17591 $timeout(function () {
17592 setToInactiveStates();
17595 if (timelineDotCtrls[i + 1].isStop() && timelineDotCtrls[i + 1].isCancelled()) {
17596 timelineBarCtrls[i].isCancelled(true);
17598 timelineDotCtrls[i - 1].shrinkAnimate(dotsDuration);
17599 timelineBarCtrls[i].animate(createAnimation(i + 1, duration), duration);
17600 timelineDotCtrls[i].expandedAnimate(dotsDuration);
17608 .directive('attTimeline', ['$timeout', '$compile', function ($timeout, $compile) {
17616 barAnimateDuration: '='
17618 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timeline.html',
17619 controller: 'AttTimelineCtrl',
17620 link: function (scope, element, attrs, ctrl) {
17621 var init = function () {
17622 var steps = scope.steps;
17623 var middleSteps = [];
17624 for (var i = 1; i < steps.length; i++) {
17625 var aStep = steps[i];
17626 middleSteps.push(aStep);
17628 scope.middleSteps = middleSteps;
17629 //Used in calculating the width of the loading bars
17630 ctrl.numSteps = steps.length - 1;
17633 //Recompile in case of scope changes
17634 scope.resetTimeline = function () {
17635 scope.animate = true;
17636 $compile(element)(scope);
17641 .controller('TimelineBarCtrl', ['$scope', function ($scope) {
17642 this.type = 'timelinebar';
17643 this.order = parseInt($scope.order);
17644 this.animate = function (callback, duration) {
17645 $scope.loadingAnimation(callback, duration);
17647 this.isCancelled = function (isCancelled) {
17648 $scope.isCancelled = isCancelled;
17651 .directive('timelineBar', ['animation', '$progressBar', function (animation, $progressBar) {
17655 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineBar.html',
17659 require: ['^attTimeline', 'timelineBar'],
17660 controller: 'TimelineBarCtrl',
17661 link: function (scope, element, attrs, ctrls) {
17662 var attTimelineCtrl = ctrls[0];
17663 var timelineBarCtrl = ctrls[1];
17664 attTimelineCtrl.addTimelineBarCtrls(timelineBarCtrl);
17665 scope.isCompleted = true;
17666 var widthPerc = (100 / attTimelineCtrl.numSteps) - 3;
17667 element.css('width', widthPerc + '%');
17668 var elem = element.find('div').eq(0);
17669 animation.set(elem, {opacity: 0.0});
17670 var updateCallback = function (selfElement) {
17671 animation.set(elem, {opacity: 1.0});
17672 animation.set(elem, {
17673 scaleX: selfElement.progress(),
17674 transformOrigin: "left"
17677 scope.loadingAnimation = $progressBar(updateCallback);
17681 .controller('TimelineDotCtrl', ['$scope', '$timeout', 'timelineConstants', function ($scope, $timeout, timelineConstants) {
17683 this.order = parseInt($scope.order);
17685 $timeout(function () {
17686 if (self.order !== 0) {
17687 if (self.order % 2 !== 0) {
17688 $scope.initializeAboveForAnimation();
17691 $scope.initializeBelowForAnimation();
17695 this.expandedAnimate = function (duration) {
17697 $scope.expandedAnimate(duration);
17698 if (self.order !== 0 && !$scope.isStepsLessThanFive()) {
17699 if (self.order % 2 !== 0) {
17700 $scope.expandContentForAbove(duration);
17702 $scope.expandContentForBelow(duration);
17706 this.unhoveredStateForAbove = function (duration) {
17707 $scope.unhoveredStateForAbove(duration);
17709 this.unhoveredStateForBelow = function (duration) {
17710 $scope.unhoveredStateForBelow(duration);
17712 this.shrinkAnimate = function (duration) {
17713 $scope.shrinkAnimate(duration);
17715 this.setExpanded = function () {
17718 this.isStop = function () {
17719 return $scope.isStop;
17721 this.isCancelled = function () {
17722 return ($scope.type === timelineConstants.STEP_TYPE.CANCELLED);
17724 this.isAlert = function () {
17725 return ($scope.type === timelineConstants.STEP_TYPE.ALERT);
17727 //Sets the bolded text
17728 this.isCurrentStep = function (isCurrentStep) {
17729 if (isCurrentStep !== undefined) {
17730 $scope.isCurrentStep = isCurrentStep;
17732 return $scope.isCurrentStep;
17735 .directive('timelineDot', ['animation', 'timelineConstants',
17736 function (animation, timelineConstants) {
17748 templateUrl: 'app/scripts/ng_js_att_tpls/steptracker/timelineDot.html',
17749 require: ['^attTimeline', 'timelineDot'],
17750 controller: 'TimelineDotCtrl',
17751 link: function (scope, element, attrs, ctrls) {
17752 var attTimelineCtrl = ctrls[0];
17753 var timelineDotCtrl = ctrls[1];
17754 attTimelineCtrl.addTimelineDotCtrls(timelineDotCtrl);
17755 scope.numSteps = attTimelineCtrl.numSteps + 1;
17756 scope.isCurrentStep = false;
17757 scope.isCompleted = false;
17758 scope.isStop = false;
17759 if (scope.type === timelineConstants.STEP_TYPE.ALERT || scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
17760 scope.isStop = true;
17762 scope.isInactive = true;
17763 var divs = element.find('div');
17764 var biggerCircleElem = divs.eq(0);
17765 var expandableCircleElem = divs.eq(2);
17766 var infoboxElem = divs.eq(3);
17767 var titleElem = divs.eq(5);
17768 var contentElem = divs.eq(6);
17769 var dateElem = divs.eq(9);
17770 function isEmptyStep() {
17771 if (!scope.description && !scope.by && !scope.date) {
17776 scope.isStepsLessThanFive = function () {
17777 if (scope.numSteps < 5) {
17782 scope.titleMouseover = function (num) {
17783 if (!scope.isStepsLessThanFive() && !isEmptyStep()) {
17784 if (num === 1 && scope.order % 2 === 0) {
17785 scope.expandContentForBelow(.25);
17787 if (num === 2 && scope.order % 2 !== 0) {
17788 scope.expandContentForAbove(.25);
17792 scope.titleMouseleave = function () {
17793 if (scope.order % 2 === 0) {
17794 scope.unhoveredStateForBelow(.25);
17797 scope.unhoveredStateForAbove(.25);
17800 scope.initializeAboveForAnimation = function () {
17801 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17802 animation.set(contentElem, {opacity: 0});
17803 animation.set(dateElem, {opacity: 0});
17804 if (!isEmptyStep()) {
17805 var yOffset = contentElem[0].offsetHeight + dateElem[0].offsetHeight;
17806 animation.set(titleElem, {'top': yOffset});
17810 scope.expandContentForAbove = function (duration) {
17811 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17812 animation.to(titleElem, duration, {'top': 0});
17813 animation.to(contentElem, duration, {opacity: 1});
17814 animation.to(dateElem, duration, {opacity: 1});
17817 scope.unhoveredStateForAbove = function (duration) {
17818 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17819 animation.set(contentElem, {opacity: 0});
17820 animation.set(dateElem, {opacity: 1});
17821 var yOffset = contentElem[0].offsetHeight;
17822 animation.to(titleElem, duration, {'top': yOffset});
17825 scope.initializeBelowForAnimation = function () {
17826 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17827 animation.set(contentElem, {height: '0%', opacity: 0, top: '-20px'});
17828 animation.set(dateElem, {opacity: 0});
17831 scope.expandContentForBelow = function (duration) {
17832 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17833 animation.set(dateElem, {opacity: 1});
17834 animation.to(contentElem, duration, {height: 'auto', opacity: 1, top: '0px'});
17837 scope.unhoveredStateForBelow = function (duration) {
17838 if (!scope.isStepsLessThanFive() && attTimelineCtrl.isAlternate()) {
17839 animation.to(contentElem, duration, {height: '0%', opacity: 0, top: '-20px', position: 'relative'});
17840 animation.set(dateElem, {opacity: 1});
17843 /*Default Initializaztion*/
17844 //If the info box is above and the description and date and by are empty then we have do reset its position
17845 if (isEmptyStep() && (scope.order % 2 !== 0 && attTimelineCtrl.isAlternate())) {
17846 infoboxElem.css('top', '-47px');
17848 //Check if the order is odd and set the appropiate above or below and other effects
17849 if (scope.order % 2 === 0 || !attTimelineCtrl.isAlternate()) {
17850 scope.isBelowInfoBoxShown = true;
17853 scope.isBelowInfoBoxShown = false;
17855 //modify some css for steps less than 5 and not alternating
17856 if (scope.isStepsLessThanFive() && !attTimelineCtrl.isAlternate()) {
17857 animation.set(dateElem, {marginTop: 10});
17860 animation.set(biggerCircleElem, {opacity: '.5'});
17861 //shrink the expandableCircle to we can expand it later
17862 animation.set(expandableCircleElem, {opacity: '0.0'});
17863 animation.set(expandableCircleElem, {scale: .10});
17864 if (scope.order === 0) {
17865 animation.set(expandableCircleElem, {opacity: '1.0'});
17866 animation.set(expandableCircleElem, {scale: 1});
17867 animation.set(biggerCircleElem, {scale: 3});
17868 scope.isCurrentStep = true;
17869 scope.isInactive = false;
17870 scope.isCompleted = true;
17872 scope.setColor = function () {
17873 scope.isInactive = false;
17874 if (scope.type === timelineConstants.STEP_TYPE.CANCELLED) {
17875 scope.isCancelled = true;
17877 else if (scope.type === timelineConstants.STEP_TYPE.ALERT) {
17878 scope.isAlert = true;
17881 scope.isCompleted = true;
17883 if (!scope.$phase) {
17887 scope.setSize = function (size) {
17888 animation.set(biggerCircle, {scale: size});
17890 scope.setExpandedCircle = function () {
17891 animation.set(expandableCircleElem, {opacity: '1.0'});
17892 animation.set(expandableCircleElem, {scale: 1});
17894 scope.expandedAnimate = function (duration) {
17895 animation.to(biggerCircleElem, duration, {scale: 3});
17896 animation.set(expandableCircleElem, {opacity: '1.0'});
17897 animation.to(expandableCircleElem, duration, {scale: 1});
17899 scope.shrinkAnimate = function (duration) {
17900 animation.to(biggerCircleElem, duration, {scale: 1});
17905 angular.module('att.abs.table', ['att.abs.utilities'])
17906 .constant('tableConfig', {
17907 //true for descending & false for ascending
17908 defaultSortPattern: false,
17909 highlightSearchStringClass: 'tablesorter-search-highlight'
17912 .directive('attTable', ['$filter', function($filter) {
17922 searchCategory: "=",
17925 require: 'attTable',
17926 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTable.html',
17927 controller: ['$scope', function($scope) {
17929 this.currentSortIndex = null;
17930 this.setIndex = function(headerScope) {
17931 this.headers.push(headerScope);
17933 this.getIndex = function(headerName) {
17934 for (var i = 0; i < this.headers.length; i++) {
17935 if (this.headers[i].headerName === headerName) {
17936 return this.headers[i].index;
17941 this.sortData = function(columnIndex, reverse) {
17942 $scope.$parent.columnIndex = columnIndex;
17943 $scope.$parent.reverse = reverse;
17944 this.currentSortIndex = columnIndex;
17945 $scope.currentPage = 1;
17946 this.resetSortPattern();
17948 this.getSearchString = function() {
17949 return $scope.searchString;
17951 this.resetSortPattern = function() {
17952 for(var i = 0; i < this.headers.length; i++) {
17953 var currentScope = this.headers[i];
17954 if(currentScope.index !== this.currentSortIndex) {
17955 currentScope.resetSortPattern();
17960 link: function(scope, elem, attr, ctrl) {
17961 scope.searchCriteria = {};
17962 scope.$watchCollection('tableData', function(value) {
17963 if(value && !isNaN(value.length)) {
17964 scope.totalRows = value.length;
17967 scope.$watch('currentPage', function(val) {
17968 scope.$parent.currentPage = val;
17970 scope.$watch('viewPerPage', function(val) {
17971 scope.$parent.viewPerPage = val;
17973 scope.$watch(function() {
17974 return scope.totalRows / scope.viewPerPage;
17975 }, function(value) {
17976 if(!isNaN(value)) {
17977 scope.totalPage = Math.ceil(value);
17978 scope.currentPage = 1;
17981 var searchValCheck = function(val){
17982 if(angular.isDefined(val) && val !== null && val !== ""){
17986 var setSearchCriteria = function(v1,v2){
17987 if(searchValCheck(v1) && searchValCheck(v2)){
17988 var index = ctrl.getIndex(v2);
17989 scope.searchCriteria = {};
17990 if (index !== null) {
17991 scope.searchCriteria[index] = v1;
17993 }else if(searchValCheck(v1) && (!angular.isDefined(v2) || v2 === null || v2 === "")){
17994 scope.searchCriteria = {
17998 scope.searchCriteria = {};
18001 scope.$watch('searchCategory', function(newVal,oldVal) {
18002 if(newVal !== oldVal){
18003 setSearchCriteria(scope.searchString,newVal);
18006 scope.$watch('searchString', function (newVal,oldVal) {
18007 if(newVal !== oldVal){
18008 setSearchCriteria(newVal,scope.searchCategory);
18011 scope.$watchCollection('searchCriteria', function(val) {
18012 scope.$parent.searchCriteria = val;
18013 scope.totalRows = scope.tableData && ($filter('filter')(scope.tableData, val, false)).length || 0;
18014 scope.currentPage = 1;
18020 .directive('attTableRow', [function() {
18023 compile: function (elem, attr) {
18024 if (attr.type === 'header') {
18025 elem.find('tr').eq(0).addClass('tablesorter-headerRow');
18026 } else if (attr.type === 'body') {
18027 var html = elem.children();
18028 if(attr.rowRepeat){
18029 if (attr.trackBy) {
18030 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1) track by " + attr.trackBy));
18032 html.attr('ng-repeat', attr.rowRepeat.concat(" | orderBy : columnIndex : reverse | filter : searchCriteria : false | attLimitTo : viewPerPage : viewPerPage*(currentPage-1) track by $index"));
18035 html.attr('ng-class', "{'alt-row': $even,'normal-row': $odd}");
18042 .directive('attTableHeader', ['tableConfig', function(tableConfig) {
18052 require: '^attTable',
18053 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableHeader.html',
18054 link: function(scope, elem, attr, ctrl) {
18055 var reverse = tableConfig.defaultSortPattern;
18056 scope.headerName = elem.text();
18057 scope.sortPattern = null;
18058 ctrl.setIndex(scope);
18060 scope.$watch(function() {
18061 return elem.text();
18062 }, function(value) {
18063 scope.headerName = value;
18065 scope.sort = function(sortType) {
18066 if(typeof sortType === 'boolean') {
18067 reverse = sortType;
18069 ctrl.sortData(scope.index, reverse);
18070 scope.sortPattern = reverse ? 'desc' : 'asc';
18071 reverse = !reverse;
18073 scope.$watch(function() {
18074 return ctrl.currentSortIndex;
18075 }, function(value) {
18076 if (value !== scope.index) {
18077 scope.sortPattern = null;
18080 if(scope.sortable !== 'false') {
18081 if(scope.defaultSort === 'A' || scope.defaultSort === 'a') {
18083 } else if(scope.defaultSort === 'D' || scope.defaultSort === 'd') {
18087 scope.resetSortPattern = function() {
18088 reverse = tableConfig.defaultSortPattern;
18094 .directive('attTableBody', ['$filter', '$timeout', 'tableConfig', function($filter, $timeout, tableConfig) {
18097 require: '^attTable',
18100 templateUrl: 'app/scripts/ng_js_att_tpls/table/attTableBody.html',
18101 link: function (scope, elem, attr, ctrl) {
18102 var highlightSearchStringClass = tableConfig.highlightSearchStringClass;
18103 var searchString = "";
18104 var wrapElement = function (elem) {
18105 var text = elem.text();
18106 elem.html($filter('highlight')(text, searchString, highlightSearchStringClass));
18108 var traverse = function (elem) {
18109 var innerHtml = elem.children();
18110 if (innerHtml.length > 0) {
18111 for (var i = 0; i < innerHtml.length; i++) {
18112 traverse(innerHtml.eq(i));
18119 var clearWrap = function (elem) {
18120 var elems = elem.find('*');
18121 for (var i = 0; i < elems.length; i++) {
18122 if (elems.eq(i).attr('class') && elems.eq(i).attr('class').indexOf(highlightSearchStringClass) !== -1) {
18123 var text = elems.eq(i).text();
18124 elems.eq(i).replaceWith(text);
18128 $timeout(function () {
18129 var actualHtml = elem.children();
18130 scope.$watch(function () {
18131 return ctrl.getSearchString();
18132 }, function (val) {
18133 searchString = val;
18135 if (actualHtml.length > 0) {
18146 angular.module('att.abs.tableMessages', ['att.abs.utilities'])
18147 .constant('messageConstants', {
18148 TABLE_MESSAGE_TYPES: {
18153 USER_MESSAGE_TYPES: {
18158 .directive('attTableMessage', ['messageConstants', function(messageConstants) {
18165 onRefreshClick: '&'
18167 templateUrl: 'app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html',
18168 link: function(scope) {
18169 scope.messageConstants = messageConstants;
18170 scope.refreshAction = function(evt) {
18171 scope.onRefreshClick(evt);
18175 }]).directive('attUserMessage', ['messageConstants', '$timeout', 'DOMHelper', function(messageConstants, $timeout, DOMHelper) {
18186 templateUrl: 'app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html',
18187 link: function(scope, element) {
18188 var prevActiveElement = undefined;
18189 var firstElement = undefined;
18190 scope.messageConstants = messageConstants;
18192 $timeout(function() {
18193 firstElement = DOMHelper.firstTabableElement(element[0]);
18197 scope.$watch('trigger', function() {
18198 if (scope.trigger) {
18199 prevActiveElement = document.activeElement;
18200 if (angular.isDefined(firstElement)) {
18201 firstElement.focus();
18204 if (angular.isDefined(prevActiveElement)) {
18205 prevActiveElement.focus();
18214 angular.module('att.abs.tabs', ['att.abs.utilities'])
18215 .directive('attTabs', function () {
18223 controller: ['$scope', function ($scope) {
18224 this.getData = function () {
18225 return $scope.tabs;
18227 this.onClickTab = function (tab) {
18228 $scope.currentTab = tab.url;
18229 return $scope.currentTab;
18231 this.isActiveTab = function (tab) {
18232 return (tab === $scope.currentTab);
18235 link: function (scope) {
18236 for (var i = 0; i < scope.tabs.length; i++) {
18237 if ((scope.tabs[i].selected) && (scope.tabs[i].url)) {
18238 scope.currentTab = scope.tabs[i].url;
18244 .directive('floatingTabs', function () {
18246 require: '^attTabs',
18253 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/floatingTabs.html',
18254 link: function (scope, elem, attr, attTabsCtrl) {
18255 scope.tabs = attTabsCtrl.getData();
18256 scope.onClickTab = attTabsCtrl.onClickTab;
18257 scope.isActiveTab = attTabsCtrl.isActiveTab;
18261 .directive('simplifiedTabs', function () {
18263 require: '^attTabs',
18270 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html',
18271 link: function (scope, elem, attr, attTabsCtrl) {
18272 scope.tabs = attTabsCtrl.getData();
18273 scope.clickTab = function (tab) {
18274 scope.ctab = tab.id;
18277 scope.isActive = function (tab) {
18278 return (tab === scope.ctab);
18283 .directive('genericTabs', ['$state',function ($state) {
18285 require: '^attTabs',
18292 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/genericTabs.html',
18293 link: function (scope, elem, attr, attTabsCtrl) {
18294 scope.tabs = attTabsCtrl.getData();
18295 scope.clickTab = function (tab) {
18296 if (tab.state!=null) {
18297 $state.go(tab.state);
18300 scope.ctab = tab.id;
18303 scope.isActive = function (tab) {
18304 return (tab === scope.ctab);
18309 .directive('skipNavigation', function(){
18311 link: function(scope,elem,attr){
18312 elem.bind('click', function(){
18313 var skiptoBody = angular.element(elem.parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18314 (angular.element(skiptoBody)).attr('tabindex',-1);
18315 skiptoBody.focus();
18321 .directive('parentTab', [function () {
18326 activeSubMenu: '=',
18329 controller: ['$scope', function ($scope) {
18330 $scope.megaMenu = $scope.menuItems;
18331 $scope.megaMenuTab;
18332 $scope.megaMenuHoverTab;
18333 this.setMenu = function () {
18334 $scope.menuItems = $scope.megaMenu;
18335 $scope.activeSubMenu.scroll=false;
18336 for (var i = 0; i < $scope.menuItems.length; i++) {
18337 if ($scope.menuItems[i].active) {
18338 $scope.activeMenu = $scope.menuItems[i];
18341 this.setSubMenuStatus(false);
18344 this.setActiveMenu = function () {
18345 if (!($scope.megaMenuTab === undefined || $scope.megaMenuTab === null)) {
18346 $scope.menuItems = [$scope.megaMenuTab];
18347 $scope.megaMenuTab.scroll = true;
18348 $scope.activeMenu = {};
18349 $scope.activeSubMenu = $scope.megaMenuTab;
18350 this.setSubMenuStatus(true);
18353 for(var i=0; i<$scope.menuItems.length; i++){
18354 ($scope.menuItems[i].active = false);
18355 if($scope.menuItems[i].subItems)
18356 for(var j=0; j<$scope.menuItems[i].subItems.length; j++){
18357 $scope.menuItems[i].subItems[j].active = false;
18360 $scope.menuItems=$scope.megaMenu;
18364 var checkSubMenuStatus = false;
18365 this.setSubMenuStatus = function (value) {
18366 checkSubMenuStatus = value;
18368 this.getSubMenuStatus = function () {
18369 return checkSubMenuStatus;
18371 this.setActiveMenuTab = function (tab) {
18372 $scope.megaMenuTab = tab;
18374 this.setActiveMenuHoverTab = function (tab) {
18375 $scope.megaMenuHoverTab = tab;
18377 this.setActiveSubMenuTab = function () {
18378 $scope.megaMenuTab = $scope.megaMenuHoverTab;
18380 this.resetMenuTab = function () {
18381 $scope.megaMenuTab = undefined;
18383 this.clearSubMenu = function () {
18384 /* Clears Sub-tems when focus shifts from Sub-menu to Mega menu*/
18385 $scope.$evalAsync(function(){
18386 $scope.megaMenuTab = undefined;
18387 $scope.megaMenuHoverTab = undefined;
18393 .directive('parentmenuTabs', [function () {
18402 controller: ['$scope', function ($scope) {
18403 this.getMenu = function () {
18404 return $scope.menuItems;
18406 this.setMenu = function (menuItem) {
18407 $scope.menuItems = menuItem;
18410 templateUrl: 'app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html'
18414 .directive('menuTabs', ["$window", "$document",'events','keymap', function (win, $document, events, keymap) {
18419 require: ['^?parentTab', '^?parentmenuTabs'],
18424 subItemActive: "@",
18428 templateUrl: function (element, attrs) {
18429 if (attrs.megaMenu) {
18430 return 'app/scripts/ng_js_att_tpls/tabs/menuTab.html';
18433 return 'app/scripts/ng_js_att_tpls/tabs/submenuTab.html';
18436 link: function (scope, elem, attr, ctrl) {
18437 var parentCtrl = ctrl[0];
18438 var parentmenuCtrl = ctrl[1];
18439 scope.clickInactive = true;
18440 scope.showHoverChild = function (e) {
18441 scope.clickInactive = false;
18442 scope.hoverChild = ctrl[0].getSubMenuStatus();
18443 if (e.type === "mouseover" && ctrl[0].getSubMenuStatus())
18445 scope.showChildren(e);
18448 scope.showChildren = function (e) {
18449 scope.parentMenuItems = parentmenuCtrl.getMenu();
18450 for (var i = 0; i < scope.parentMenuItems.length; i++) {
18451 scope.parentMenuItems[i].active = false;
18452 if (scope.parentMenuItems[i].subItems) {
18453 for (var j = 0; j < scope.parentMenuItems[i].subItems.length; j++) {
18454 scope.parentMenuItems[i].subItems[j].active = false;
18457 scope.clickInactive = true;
18459 scope.menuItem.active = true;
18460 scope.activeMenu = scope.menuItem;
18461 e.stopPropagation();
18463 scope.$watch("subItemActive", function (value) {
18464 if (value === "true" && scope.subMenu === 'true') {
18465 parentCtrl.setActiveMenuHoverTab(scope.menuItem);
18468 scope.showMenuClick = function (e) {
18469 parentCtrl.setActiveMenuTab(scope.menuItem);
18470 e.stopPropagation();
18472 scope.showSubMenuClick = function (e) {
18473 parentCtrl.setActiveSubMenuTab();
18474 e.stopPropagation();
18476 scope.resetMenu = function (e) {
18477 parentCtrl.resetMenuTab();
18478 e.stopPropagation();
18480 function debounce(method, delay) {
18481 clearTimeout(method._tId);
18482 method._tId = setTimeout(function () {
18483 parentCtrl.setMenu();
18486 function debounce1(method, delay) {
18487 clearTimeout(method._tId);
18488 method._tId = setTimeout(function () {
18489 parentCtrl.setActiveMenu();
18492 $document.bind('scroll', function () {
18493 if (win.pageYOffset === 0) {
18494 debounce(parentCtrl.setMenu, 100);
18496 else if (win.pageYOffset > 1 && win.pageYOffset < 1500) {
18497 debounce1(parentCtrl.setActiveMenu, 100);
18500 elem.bind('keydown', function(evt){
18501 if (!(evt.keyCode)){
18502 evt.keyCode = evt.which;
18504 if(evt.keyCode !== keymap.KEY.TAB){
18505 events.preventDefault(evt);
18506 events.stopPropagation(evt);
18509 switch (evt.keyCode) {
18510 case keymap.KEY.ESC:
18512 if (!(elem.attr('mega-menu'))) {
18513 if (elem.attr("sub-menu") === "true") {
18514 /* condition true when user navigates through Sub-menu*/
18516 skiptoBody = angular.element(elem.parent().parent().parent().parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18517 (angular.element(skiptoBody)).attr('tabindex',-1);
18518 skiptoBody.focus();
18520 else if (elem.attr("sub-menu") === undefined) {
18521 skiptoBody = angular.element(elem.parent().parent().parent().parent().parent().parent().parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18522 (angular.element(skiptoBody)).attr('tabindex',-1);
18523 skiptoBody.focus();
18528 if (elem.attr("menu-item") === "item") {
18529 /* Works when user on Mega menu*/
18531 skiptoBody = angular.element(elem.parent().parent().parent().parent())[0].querySelector('a.skiptoBody');
18532 (angular.element(skiptoBody)).attr('tabindex',-1);
18533 skiptoBody.focus();
18537 case keymap.KEY.RIGHT:
18538 if (!(elem.attr('mega-menu'))) {
18539 var el = angular.element(elem)[0];
18540 if (elem.attr("sub-menu") === "true") {
18541 /* condition true when user navigates through Sub-menu*/
18542 if(el.nextElementSibling === null){ break;}
18543 if(el.nextElementSibling){
18544 el.nextElementSibling.querySelector("a").focus();
18548 if (el && el.nextSibling){
18549 el = el.nextSibling;
18554 } while (el && el.tagName !== 'LI');
18556 if (el.querySelector("a") == null){}
18558 el.querySelector("a").focus();}
18560 events.preventDefault(evt);
18561 events.stopPropagation(evt);
18564 else if (elem.attr("sub-menu") === undefined) {
18565 if(el.nextElementSibling === null) break;
18566 if(el.nextElementSibling){
18567 el.nextElementSibling.querySelector("a").focus();
18571 if (el && el.nextSibling){
18572 el = el.nextSibling;
18577 } while (el && el.tagName !== 'LI');
18579 if (el.querySelector("a") == null){}
18581 el.querySelector("a").focus();}
18589 if (elem.attr("menu-item") === "item") {
18590 /* When user navigates through on Mega menu*/
18592 var el = angular.element(elem)[0];
18594 if(el.nextElementSibling){
18595 if(el.nextElementSibling.querySelector("span") == null){
18598 el.nextElementSibling.querySelector("span").focus();
18603 if (el && el.nextSibling){
18604 el = el.nextSibling;
18609 } while (el && el.tagName !== 'LI');
18611 if(el.querySelector("span") === null){}
18613 el.querySelector("span").focus();
18616 events.preventDefault(evt);
18617 events.stopPropagation(evt);
18622 case keymap.KEY.DOWN:
18625 if (elem.attr('mega-menu')) {
18626 /* When user navigates from top menu to Sub-menu*/
18627 angular.element(elem)[0].querySelectorAll(".megamenu__items")[0].querySelector("a").focus();
18629 else if(elem.attr("sub-menu") === undefined) {
18630 /*When user navigates within Sub Items*/
18631 var el = document.activeElement;
18632 if(el.nextElementSibling === null) break;
18633 if(el.nextElementSibling) {
18634 el.nextElementSibling.focus();
18637 if (el && el.nextSibling){
18638 el = el.nextSibling;
18643 } while (el && el.tagName !== 'A');
18644 if(el.attributes !== null){
18647 events.stopPropagation(evt);
18651 else if (elem.attr("sub-menu")=== "true" ) {
18652 /* condition true when user navigates from sub menu to Sub Item*/
18653 var childItems = angular.element(elem)[0].querySelector("span").querySelector('a');
18654 if(childItems === null) break;
18655 childItems.focus();
18659 case keymap.KEY.LEFT:
18661 if (!(elem.attr('mega-menu'))) {
18662 var el = angular.element(elem)[0];
18663 if (elem.attr("sub-menu") === "true") {
18664 /* condition true when user navigates through Sub-menu*/
18665 if(el.previousElementSibling === null) break;
18666 if(el.previousElementSibling){
18667 el.previousElementSibling.querySelector("a").focus();
18671 if (el && el.previousSibling){
18672 el = el.previousSibling;
18677 } while (el && el.tagName !== 'LI');
18679 if (el.querySelector("a") == null){}
18681 el.querySelector("a").focus();}
18683 events.preventDefault(evt);
18684 events.stopPropagation(evt);
18687 /*el.previousElementSibling.querySelector("span").focus();
18688 events.stopPropagation(evt);
18691 else if (elem.attr("sub-menu") === undefined) {
18692 if(el.previousElementSibling === null) break;
18693 if(el.previousElementSibling){
18694 el.previousElementSibling.querySelector("a").focus();
18698 if (el && el.previousSibling){
18699 el = el.previousSibling;
18704 } while (el && el.tagName !== 'LI');
18706 if (el.querySelector("a") == null){}
18708 el.querySelector("a").focus();}
18715 if (elem.attr("menu-item") === "item") {
18716 /* Works when user on Mega menu*/
18718 var el = angular.element(elem)[0];
18719 if(el.previousElementSibling){
18721 if(el.previousElementSibling.querySelector("span") === null){
18724 el.previousElementSibling.querySelector("span").focus();
18730 if (el && el.previousSibling){
18731 el = el.previousSibling;
18736 } while (el && el.tagName !== 'LI');
18738 if (el.querySelector("span") === null) {
18741 el.querySelector("span").focus();
18744 events.preventDefault(evt);
18745 events.stopPropagation(evt);
18750 case keymap.KEY.UP:
18752 if (elem.attr("sub-menu") === "true") {
18753 var el = document.activeElement;
18754 var parent_menu = angular.element(elem.parent().parent().parent().parent())[0].querySelector("span");
18755 parent_menu.focus();
18756 parentCtrl.clearSubMenu();
18757 scope.menuItem.active = false;
18760 else if(elem.attr("sub-menu") === undefined) {
18761 /* condition true when user navigates within Sub Items*/
18762 var el = document.activeElement;
18763 var parent_menu = angular.element(elem.parent().parent().parent().parent())[0].querySelector("a");
18764 if(document.activeElement === angular.element(el).parent().parent()[0].querySelectorAll('a')[0]){
18765 parent_menu.focus();
18769 if(el.previousElementSibling) {
18770 var prev_a = el.previousElementSibling;
18771 (el.previousElementSibling != null)? el.previousElementSibling.focus(): parent_menu.focus();
18774 if (el && el.previousSibling){
18775 el = el.previousSibling;
18780 } while (el && el.tagName !== 'A');
18781 if(el && (el.nodeType !== 3)){
18784 events.preventDefault(evt);
18785 events.stopPropagation(evt);
18798 angular.module('att.abs.tagBadges', [])
18799 .directive('tagBadges', ['$parse', '$timeout', function($parse, $timeout) {
18804 templateUrl: 'app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html',
18809 link: function(scope, elem, attr) {
18810 scope.isSmall = false;
18811 scope.isIcon = false;
18812 scope.isColor = false;
18813 scope.display = true;
18814 scope.isClosable = false;
18815 scope.isHighlight = false;
18816 scope.customColor = false;
18818 if (attr.small === "") {
18819 scope.isSmall = true;
18821 if (scope.styleType === "icon") {
18822 scope.isIcon = true;
18824 else if (scope.styleType === "color") {
18825 scope.isColor = true;
18826 if(attr.color !== undefined && attr.color !== "") {
18827 scope.customColor = true;
18828 attr.$observe("color", function(val) {
18829 scope.border_type_borderColor = val;
18830 scope.background_type_backgroundColor = val;
18831 scope.background_type_borderColor = val;
18835 scope.activeHighlight = function(state){
18836 if(scope.customColor){
18838 scope.isHighlight = true;
18841 scope.isHighlight = false;
18845 if (attr.closable === "") {
18846 scope.isClosable = true;
18847 scope.closeMe = function() {
18848 scope.display = false;
18849 $timeout(function(){
18850 elem.attr("tabindex", "0");
18852 elem.bind('blur', function(){
18856 if(attr['onClose']){
18857 scope.onClose = $parse(scope.onClose);
18865 angular.module('att.abs.textOverflow', [])
18866 .constant('textDefaultOptions', {
18869 .directive('attTextOverflow', ['textDefaultOptions','$compile',function(textDefaultOptions,$compile)
18873 link: function(scope, elem, attrs)
18875 var tooltipText = elem.text();
18876 elem.addClass('text-ellipsis');
18877 attrs.$observe('attTextOverflow', function(val){
18879 elem.css({"width":val});
18882 elem.css({"width":textDefaultOptions.width});
18885 if(!(elem.attr('tooltip'))){
18886 elem.attr("tooltip", tooltipText);
18887 elem.attr("tooltip-placement", 'above');
18888 var newElem = angular.element(elem);
18889 $compile(newElem)(scope);
18895 angular.module('att.abs.toggle', ['angular-gestures', 'att.abs.position'])
18896 .directive('attToggleTemplate', ['$compile', '$log', '$position', function ($compile, $log, $position)
18900 require: 'ngModel',
18903 modelVal: "=ngModel"
18905 templateUrl: 'app/scripts/ng_js_att_tpls/toggle/demoToggle.html',
18906 link: function (scope, element, attr) {
18907 scope.initialDragPosition = 0;
18908 var dragStatus = 0;
18909 var switchMovementPath = ($position.offset(element.children().eq(1).children().eq(0)).width - 1);
18910 var updateModelVal = function () {
18911 if (scope.attrValue === attr.ngTrueValue || scope.attrValue)
18913 scope.modelVal = false;
18917 scope.modelVal = true;
18920 scope.updateModel = function (env) {
18922 if (dragStatus !== 1) {
18927 env.preventDefault();
18929 scope.drag = function (e) {
18931 if (e.type === 'dragstart') {
18932 scope.initialDragPosition = $position.position(element.children().eq(1)).left;
18933 element.children().eq(1).addClass('dragging');
18934 } else if (e.type === 'drag') {
18935 var left = Math.min(0, Math.max(scope.initialDragPosition + e.gesture.deltaX, -switchMovementPath));
18936 element.children().eq(1).css({
18939 } else if (e.type === 'dragend') {
18940 var isOn = $position.position(element.children().eq(1)).left > (switchMovementPath * -1) / 2;
18941 element.children().eq(1).removeClass('dragging');
18942 TweenMax.to(element.children().eq(1), .1, {left: isOn ? 0 : (switchMovementPath * -1), ease: Power4.easeOut,
18943 onComplete: function () {
18944 element.children().eq(1).css({left: ''});
18946 if (isOn || (!isOn && e.gesture.direction === "left")) {
18955 scope.directiveValue = attr.attToggleTemplate;
18956 scope.on = attr.trueValue;
18957 scope.off = attr.falseValue;
18958 var switchMovementPathPixels = ((switchMovementPath) * -1) + 'px';
18959 scope.$watch('modelVal', function (newVal) {
18960 scope.attrValue = newVal;
18961 if (newVal === attr.ngTrueValue || newVal) {
18962 element.children().eq(1).css({
18965 element.addClass('att-checkbox--on');
18966 var elem = element.find('div').find('div').eq(1);
18967 elem.attr("aria-checked", true);
18970 element.children().eq(1).css({
18971 left: switchMovementPathPixels
18973 element.removeClass('att-checkbox--on');
18974 var elem = element.find('div').find('div').eq(1);
18975 elem.attr("aria-checked", false);
18978 element.children().eq(1).css({
18987 .directive('attToggleMain', ['$compile', function ($compile)
18991 require: 'ngModel',
18995 modelValue: "=ngModel",
18996 trueValue: "=ngTrueValue",
18997 falseValue: "=ngFalseValue"
18999 link: function (scope, element, attr) {
19002 element.removeAttr('att-toggle-main');
19003 scope.on = attr.ngTrueValue;
19004 scope.off = attr.ngFalseValue;
19005 scope.largeValue = attr.attToggleMain;
19006 if (angular.isDefined(attr.ngTrueValue)) {
19007 html += ' true-value="{{on}}" false-value="{{off}}"';
19009 if (scope.largeValue !== undefined)
19011 attrVal += ' ="{{largeValue}}"';
19014 element.css({display: 'none'});
19015 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>');
19016 elm = $compile(elm)(scope);
19017 element.replaceWith(elm);
19021 angular.module('att.abs.treeview', [])
19022 .directive('treeView', function() {
19025 link: function(scope, elem) {
19026 var el = elem.children('ul li');
19027 var list = TweenMax.from(el, .2, {display: 'none', paused: true, reversed: true});
19028 elem.attr("tabindex","0");
19029 function toggleBranch() {
19030 if (list.reversed())
19038 function toggleTree(e) {
19039 e.stopPropagation();
19040 if (angular.element(e.target).attr("tree-view") !== undefined)
19042 if (elem.hasClass('minus'))
19044 elem.removeClass('minus');
19048 elem.addClass('minus');
19053 elem.on('click', function(e) {
19056 elem.on('keypress', function (e) {
19057 var activeCode = e.keyCode ? e.keyCode : e.charCode;
19058 var keyCode = [13,32];
19059 if (keyCode.length > 0 && ((activeCode && keyCode.indexOf(activeCode) > -1))) {
19061 e.preventDefault();
19068 angular.module('att.abs.typeAhead', ['att.abs.tagBadges'])
19070 .directive('focusMe',['$timeout', '$parse', function($timeout, $parse) {
19072 link: function(scope, element, attrs) {
19073 var model = $parse(attrs.focusMe);
19074 scope.$watch(model, function(value) {
19076 $timeout(function() {
19077 element[0].focus();
19078 scope.inputActive=true;
19082 element.bind('blur', function() {
19083 model.assign(scope, false);
19084 scope.inputActive=false;
19091 .directive('typeAhead', ['$timeout','$log', function($timeout,$log) {
19094 templateUrl: 'app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html',
19105 link: function(scope, elem) {
19106 if(!angular.isDefined(scope.titleName) && angular.isDefined(scope.title)){
19107 $timeout(function(){
19108 scope.titleName = scope.title;
19109 $log.warn("title attribute is deprecated and title-name attribute is used instead as it is conflicting with html title attribute");
19112 scope.lineItems = [];
19113 scope.filteredListLength = -1;
19114 scope.filteredList = [];
19115 scope.setFocus = function() {
19116 scope.clickFocus = true;
19119 scope.handleSelection = function(selectedItem,emailItem) {
19120 scope.lineItems.push(selectedItem);
19121 scope.emailIdList.push(emailItem);
19124 scope.selected = true;
19125 scope.clickFocus = true;
19127 scope.theMethodToBeCalled = function(index) {
19128 var tempArr = scope.lineItems.slice();
19129 scope.emailIdList.splice(index, 1);
19130 tempArr.splice(index, 1);
19131 $timeout(function() {
19132 scope.lineItems = [];
19134 scope.lineItems = scope.lineItems.concat(tempArr);
19139 scope.selected = true;
19141 scope.isCurrent = function(index, itemName,itemEmail,dropdownLength) {
19142 if (scope.current === index) {
19143 scope.itemName = itemName;
19144 scope.itemEmail = itemEmail;
19146 scope.dropdownLength=dropdownLength;
19147 return scope.current === index;
19150 scope.setCurrent = function(index) {
19151 scope.current = index;
19154 scope.selectionIndex = function(evt) {
19155 if (evt.keyCode === 38 && scope.current > 0) {
19156 evt.preventDefault();
19157 scope.current = scope.current - 1;
19158 scope.isCurrent(scope.current);
19159 } else if (evt.keyCode === 9) {
19160 scope.selected = true;
19161 } else if (evt.keyCode === 13 && scope.dropdownLength!==scope.items.length) {
19162 scope.handleSelection(scope.itemName,scope.itemEmail);
19163 } else if ((evt.keyCode === 8 && scope.model.length === 0) || evt.keyCode === 46) {
19164 scope.theMethodToBeCalled(scope.lineItems.length - 1);
19165 } else if (evt.keyCode === 40 && scope.current < scope.dropdownLength-1) {
19166 evt.preventDefault();
19167 scope.current = scope.current + 1;
19168 scope.isCurrent(scope.current);
19170 elem[0].querySelector('.list-scrollable').scrollTop = (scope.current - 1) * 35;
19175 angular.module('att.abs.verticalSteptracker', ['ngSanitize'])
19176 .directive('verticalSteptracker', [ function(){
19182 template: '<div class="vertical-nav"><ul ng-transclude arial-label="step list" role="presentation" class="tickets-list-height"></ul></div>',
19183 link: function () {}
19186 .directive('verticalSteptrackerStep',[ function(){
19195 templateUrl: 'app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html',
19199 .directive('attAbsLink',[ function(){
19204 template: '<span ng-transclude class="view-log"></span>'
19207 angular.module('att.abs.videoControls', [])
19208 .config(['$compileProvider' , function ($compileProvider) {
19209 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|javascript):/);
19211 .directive('videoControls', [function() {
19216 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/videoControls.html'
19219 .directive('photoControls', [function() {
19224 templateUrl: 'app/scripts/ng_js_att_tpls/videoControls/photoControls.html',
19229 link: function(scope, elem, attr) {
19230 if(!attr['prevLink']){
19231 scope.prevLink = 'javascript:void(0)';
19233 if(!attr['nextLink']){
19234 scope.nextLink = 'javascript:void(0)';
19237 prevLink : scope.prevLink,
19238 nextLink : scope.nextLink
19243 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
19244 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion.html",
19245 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
19246 " <a ng-show=\"showicon\" \n" +
19247 " class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\" \n" +
19248 " aria-selected=\"{{focused}}\" \n" +
19249 " aria-controls=\"panel{{index}}\" \n" +
19250 " aria-expanded=\"{{isOpen}}\" \n" +
19251 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19252 " role=\"tab\" \n" +
19253 " ng-click=\"toggle()\" \n" +
19254 " accordion-transclude=\"heading\" \n" +
19255 " style=\"cursor:pointer; text-decoration:none\">\n" +
19256 " <span>{{heading}}</span>\n" +
19257 " <i ng-class=\"{'icon-chevron-down':!isOpen,'icon-chevron-up':isOpen }\" class=\"pull-right\"></i>\n" +
19259 " <div ng-show=\"!showicon\" \n" +
19260 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19261 " style=\"text-decoration:none\" \n" +
19262 " accordion-transclude=\"heading\" \n" +
19263 " role=\"tab\" \n" +
19264 " aria-expanded=\"{{isOpen}}\"\n" +
19265 " aria-selected=\"{{focused}}\" \n" +
19266 " aria-controls=\"panel{{index}}\" \n" +
19267 " class=\"toggle-header att-accordion__heading att-accordion__toggle noafter\">\n" +
19268 " <span>{{heading}}</span>\n" +
19270 " <div aria-label=\"{{heading}}\" \n" +
19271 " aria-hidden=\"{{!isOpen}}\" \n" +
19272 " role=\"tabpanel\" \n" +
19273 " collapse=\"!isOpen\" \n" +
19274 " class=\"att-accordion__body\" \n" +
19275 " id=\"panel{{index}}\" \n" +
19276 " ng-transclude>\n" +
19278 " <div class=\"att-accordion__bottom--border\"></div> \n" +
19282 angular.module("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html", []).run(["$templateCache", function($templateCache) {
19283 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/accordion_alt.html",
19284 "<div class=\"att-accordion__group tabpanel\" ng-class=\"{'att-accordion__group att-accordion__group--open':isOpen,'att-accordion__group':!isOpen }\">\n" +
19285 " <a class=\"toggle-header att-accordion__heading att-accordion__toggle\" \n" +
19286 " aria-selected=\"{{focused}}\" \n" +
19287 " aria-controls=\"panel{{index}}\" \n" +
19288 " ng-class=\"{focus: focused, selected: focused}\" \n" +
19289 " aria-expanded=\"{{isOpen}}\" \n" +
19290 " role=\"tab\" \n" +
19291 " ng-click=\"toggle()\" \n" +
19292 " accordion-transclude=\"heading\"> \n" +
19294 " <span>{{heading}}</span>\n" +
19295 " <div aria-label=\"{{heading}}\" \n" +
19296 " aria-hidden=\"{{!isOpen}}\" \n" +
19297 " role=\"tabpanel\" \n" +
19298 " collapse=\"!isOpen\" \n" +
19299 " class=\"att-accordion__body\" \n" +
19300 " id=\"panel{{index}}\" \n" +
19301 " ng-transclude>\n" +
19306 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccord.html", []).run(["$templateCache", function($templateCache) {
19307 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccord.html",
19308 "<div ng-transclude></div>");
19311 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html", []).run(["$templateCache", function($templateCache) {
19312 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordBody.html",
19313 "<div ng-transclude></div>");
19316 angular.module("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html", []).run(["$templateCache", function($templateCache) {
19317 $templateCache.put("app/scripts/ng_js_att_tpls/accordion/attAccordHeader.html",
19318 "<div ng-click=\"clickFunc()\">\n" +
19319 " <div ng-transclude>\n" +
19320 " <i class=\"icon-chevron-down\"></i>\n" +
19325 angular.module("app/scripts/ng_js_att_tpls/alert/alert.html", []).run(["$templateCache", function($templateCache) {
19326 $templateCache.put("app/scripts/ng_js_att_tpls/alert/alert.html",
19327 "<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" +
19328 " <div class=\"container\">\n" +
19329 " <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" +
19330 " <span ng-transclude> </span>\n" +
19335 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html", []).run(["$templateCache", function($templateCache) {
19336 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attAddBoard.html",
19337 "<div tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"addBoard()\" aria-label=\"Add Board\" class=\"boardstrip-item--add\">\n" +
19338 " <i aria-hidden=\"true\" class=\"icon-add centered\"></i>\n" +
19340 " <div class=\"centered\">Add board</div>\n" +
19344 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attBoard.html", []).run(["$templateCache", function($templateCache) {
19345 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attBoard.html",
19346 "<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" +
19347 " <div ng-transclude></div>\n" +
19348 " <div class=\"board-caret\" ng-if=\"getCurrentIndex()===boardIndex\">\n" +
19349 " <div class=\"board-caret-indicator\"></div>\n" +
19350 " <div class=\"board-caret-arrow-up\"></div>\n" +
19355 angular.module("app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html", []).run(["$templateCache", function($templateCache) {
19356 $templateCache.put("app/scripts/ng_js_att_tpls/boardStrip/attBoardStrip.html",
19357 "<div class=\"att-boardstrip\">\n" +
19358 " <div class=\"boardstrip-reel\">\n" +
19359 " <div class=\"prev-items\" ng-if=\"isPrevBoard()\">\n" +
19360 " <i tabindex=\"0\" aria-label=\"Scroll Boardstrip Left\" att-accessibility-click=\"13,32\" ng-click=\"prevBoard()\" class=\"arrow icon-arrow-left-circle\"></i>\n" +
19362 " <div att-add-board on-add-board=\"onAddBoard()\"></div>\n" +
19363 " <div class=\"board-viewport\"><ul role=\"presentation\" class=\"boardstrip-container\" ng-transclude></ul></div>\n" +
19364 " <div class=\"next-items\" ng-if=\"isNextBoard()\">\n" +
19365 " <i tabindex=\"0\" aria-label=\"Scroll Boardstrip Right\" att-accessibility-click=\"13,32\" ng-click=\"nextBoard()\" class=\"arrow icon-arrow-right-circle\"></i>\n" +
19371 angular.module("app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html", []).run(["$templateCache", function($templateCache) {
19372 $templateCache.put("app/scripts/ng_js_att_tpls/buttons/buttonDropdown.html",
19373 "<div class=\"att-btn-dropdown\">\n" +
19374 " <div class=\"buttons-dropdown--small btn-group\" ng-class=\"{'open': isOpen}\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\">\n" +
19376 " <button role=\"menu\" class=\"button button--secondary button--small buttons-dropdown__drop dropdown-toggle\" ng-if=\"type==='dots'\" alt=\"Click for Options\" >\n" +
19378 " <div class=\"circle\"></div>\n" +
19379 " <div class=\"circle\"></div>\n" +
19380 " <div class=\"circle\"></div>\n" +
19382 " <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" +
19385 " <ul ng-class=\"{'dropdown-menu dots-dropdwn': type==='dots', 'dropdown-menu actions-dropdwn': type === 'actions'}\" ng-transclude></ul>\n" +
19392 angular.module("app/scripts/ng_js_att_tpls/colorselector/colorselector.html", []).run(["$templateCache", function($templateCache) {
19393 $templateCache.put("app/scripts/ng_js_att_tpls/colorselector/colorselector.html",
19394 "<div class=\"att-radio att-color-selector__item\" \n" +
19395 " ng-class=\"{'att-radio--on': (iconColor === selected)}\">\n" +
19396 " <div class=\"att-radio__indicator\" tabindex=\"0\" att-accessibility-click=\"32,13\" ng-click=\"selectedcolor(iconColor)\" \n" +
19397 " ng-style=\"applycolor\" ng-transclude></div>\n" +
19401 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html", []).run(["$templateCache", function($templateCache) {
19402 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilter.html",
19403 "<div class=\"calendar\" ng-class=\"{'monthpicker':mode === 1}\">\n" +
19404 " <div class=\"select2-container\" ng-class=\"{'select2-container-active select2-dropdown-open': showDropdownList}\" style=\"width: 100%; z-index:0\">\n" +
19405 " <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" +
19406 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
19407 " <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" +
19408 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
19409 " <span ng-class=\"{'select2-arrow': mode !== 1, 'calendar-icon': mode === 1}\"><b></b></span>\n" +
19411 " <a id=\"select2-chosen\" class=\"select2-choice\" href=\"javascript:void(0)\" ng-show=\"showCalendar\">\n" +
19412 " <span class=\"select2-chosen\" ng-show=\"!showCalendar\">{{selectedOption}}</span>\n" +
19413 " <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" +
19414 " <abbr class=\"select2-search-choice-close\"></abbr>\n" +
19415 " <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" +
19418 " <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" +
19419 " <div id=\"dateFilterList\" att-scrollbar ><ul class=\"select2-results options\" ng-transclude></ul></div>\n" +
19420 " <ul class=\"select2-results sttings\" style=\"margin-top:0px\">\n" +
19421 " <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" +
19422 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Single Date...</div>\n" +
19423 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom single month...</div>\n" +
19425 " <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" +
19426 " <div class=\"select2-result-label\" ng-if=\"mode !== 1\">Custom Range...</div>\n" +
19427 " <div class=\"select2-result-label\" ng-if=\"mode === 1\">Custom month range...</div>\n" +
19429 " <li class=\"select2-result select2-highlighted btnContainer\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
19430 " <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" +
19431 " <button tabindex=\"0\" att-button=\"\" btn-type=\"secondary\" size=\"small\" att-accessibility-click=\"13,32\" ng-click=\"cancel()\">Cancel</button>\n" +
19433 " <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" +
19434 " <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" +
19439 " <div class=\"datepicker-wrapper show-right\" ng-style=\"{display: (showCalendar && 'block') || 'none'}\">\n" +
19440 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusSingleDateCalendar\" ng-show=\"checkCurrentSelection('Custom Single Date')\"></span>\n" +
19441 " <span datepicker ng-blur=\"resetFocus($event)\" att-element-focus=\"focusRangeCalendar\" ng-show=\"checkCurrentSelection('Custom Range')\"></span>\n" +
19447 angular.module("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html", []).run(["$templateCache", function($templateCache) {
19448 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/dateFilterList.html",
19449 "<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" +
19450 " <div class=\"select2-result-label\" ng-class=\"{'disabled':disabled}\" ng-transclude></div>\n" +
19454 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
19455 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepicker.html",
19456 "<div id=\"datepicker\" class=\"datepicker\" ng-class=\"{'monthpicker': mode === 1}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\" aria-labelledby=\"datepicker\">\n" +
19457 " <div class=\"datepicker-days\" style=\"display: block;\">\n" +
19458 " <table class=\"table-condensed\">\n" +
19461 " <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" +
19462 " <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" +
19463 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-left-circle\" ng-class=\"{'disabled': disablePrev}\" alt=\"Left Arrow\"></i>\n" +
19464 " </div><span class=\"hidden-spoken\">Previous Month</span>\n" +
19466 " <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" +
19467 " <div class=\"icons-list\" data-size=\"medium\"><i class=\"icon-arrow-right-circle\" ng-class=\"{'disabled': disableNext}\" alt=\"Right Arrow\"></i>\n" +
19468 " </div><span class=\"hidden-spoken\">Next Month</span>\n" +
19471 " <tr ng-if=\"labels.length > 0\">\n" +
19472 " <th tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"><span>{{label.pre}}</span></th>\n" +
19477 " <td id=\"datepickerBody\" att-scrollbar colspan=\"{{currentRows[0].length}}\" style=\"padding: 0px;\" headers=\"\">\n" +
19478 " <table ng-class=\"{'table-condensed': mode === 0, 'monthtable-condensed': mode === 1}\" style=\"padding: 0px;\">\n" +
19479 " <thead class=\"hidden-spoken\">\n" +
19480 " <tr ng-show=\"labels.length > 0\">\n" +
19481 " <th id=\"{{label.post}}\" tabindex=\"-1\" class=\"dow weekday\" ng-repeat=\"label in labels\"></th>\n" +
19485 " <tr ng-repeat=\"row in currentRows\">\n" +
19486 " <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" +
19488 " <tr ng-if=\"mode === 1\" class=\"divider\"><td colspan=\"{{nextRows[0].length}}\"><hr></td></tr>\n" +
19490 " <th id=\"month\" tabindex=\"0\" class=\"datepicker-switch internal\" colspan=\"{{nextRows[0].length}}\" style=\"text-align:left\">{{nextTitle}}</th>\n" +
19492 " <tr ng-repeat=\"row in nextRows\">\n" +
19493 " <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" +
19506 angular.module("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html", []).run(["$templateCache", function($templateCache) {
19507 $templateCache.put("app/scripts/ng_js_att_tpls/datepicker/datepickerPopup.html",
19508 "<div class=\"calendar\">\n" +
19509 " <div class=\"box\" ng-class=\"{'active': isOpen}\">\n" +
19510 " <span ng-transclude></span>\n" +
19511 " <i class=\"calendar-icon\" tabindex=\"0\" att-accessibility-click=\"13,32\" ng-click=\"toggle()\" alt=\"Calendar Icon\"></i>\n" +
19513 " <div class=\"datepicker-wrapper datepicker-wrapper-display-none\" ng-style=\"{display: (isOpen && 'block') || 'none'}\" aria-hidden=\"false\" role=\"dialog\" tabindex=\"-1\">\n" +
19514 " <span datepicker></span>\n" +
19520 angular.module("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html", []).run(["$templateCache", function($templateCache) {
19521 $templateCache.put("app/scripts/ng_js_att_tpls/dividerLines/dividerLines.html",
19522 "<div class=\"divider-container\" ng-class=\"{'divider-container-light': lightContainer}\">\n" +
19523 " <hr ng-class=\"{'divider-light': lightContainer}\">\n" +
19529 angular.module("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html", []).run(["$templateCache", function($templateCache) {
19530 $templateCache.put("app/scripts/ng_js_att_tpls/dragdrop/fileUpload.html",
19531 "<label class=\"fileContainer\"><span ng-transclude></span><input type=\"file\" att-file-change></label>");
19534 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html", []).run(["$templateCache", function($templateCache) {
19535 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlert.html",
19536 "<div class=\"form-field\" ng-class=\"{'error': errorMessage, 'warning': warningMessage}\">\n" +
19537 " <label class=\"form-field__label\" ng-class=\"{'form-field__label--show': showLabel, 'form-field__label--hide': hideLabel}\"></label>\n" +
19538 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
19542 angular.module("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html", []).run(["$templateCache", function($templateCache) {
19543 $templateCache.put("app/scripts/ng_js_att_tpls/formField/attFormFieldValidationAlertPrv.html",
19544 "<div class=\"form-field\" ng-class=\"{'error':hideErrorMsg}\">\n" +
19545 " <div class=\"form-field-input-container\" ng-transclude></div>\n" +
19546 " <div class=\"form-field__message error\" type=\"error\" ng-show=\"hideErrorMsg\" >\n" +
19547 " <i class=\"icon-info-alert\"></i>{{errorMessage}}\n" +
19553 angular.module("app/scripts/ng_js_att_tpls/formField/creditCardImage.html", []).run(["$templateCache", function($templateCache) {
19554 $templateCache.put("app/scripts/ng_js_att_tpls/formField/creditCardImage.html",
19555 "<span class=\"css-sprite pull-right\">\n" +
19556 "<span class=\"hidden-spoken\">We accept</span>\n" +
19557 "<ul class=\"{{newValCCI}}\">\n" +
19558 " <li class=\"css-sprite-mc\"><span class=\"hidden-spoken\">MasterCard</span></li>\n" +
19559 " <li class=\"css-sprite-visa\"><span class=\"hidden-spoken\">Visa</span></li>\n" +
19560 " <li class=\"css-sprite-amex\"><span class=\"hidden-spoken\">American Express</span></li>\n" +
19561 " <li class=\"css-sprite-discover\"><span class=\"hidden-spoken\">Discover</span></li> \n" +
19564 "<label for=\"ccForm.card\" class=\"pull-left\">Card number</label>");
19567 angular.module("app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html", []).run(["$templateCache", function($templateCache) {
19568 $templateCache.put("app/scripts/ng_js_att_tpls/formField/cvcSecurityImg.html",
19570 "<button type=\"button\" class=\"btn btn-alt btn-tooltip\" style=\"padding-top:16px\" title=\"Help\"><i class=\"hidden-spoken\">Help</i></button>\n" +
19571 "<div class=\"helpertext\" role=\"tooltip\">\n" +
19572 "<div class=\"popover-title\"></div>\n" +
19573 "<div class=\"popover-content\">\n" +
19574 " <p class=\"text-legal cvc-cc\">\n" +
19575 " <img ng-src=\"images/{{newValI}}.png\" alt=\"{{newValIAlt}}\">\n" +
19583 angular.module("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html", []).run(["$templateCache", function($templateCache) {
19584 $templateCache.put("app/scripts/ng_js_att_tpls/hourpicker/hourpicker.html",
19585 "<div class=\"hourpicker\">\n" +
19586 " <div class=\"dropdown-width\">\n" +
19587 " <div ng-model=\"showlist\" class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': showlist}\" >\n" +
19588 " <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" +
19589 " <span class=\"select2-chosen\">{{selectedOption}}</span>\n" +
19590 " <span class=\"select2-arrow\"><b></b></span>\n" +
19593 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultTopWidth\" ng-show=\"showlist\"> \n" +
19594 " <ul class=\"select2-results resultTopMargin\" > \n" +
19595 " <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" +
19599 " <div ng-show=\"showDaysSelector\" class=\"customdays-width\">\n" +
19600 " <div att-divider-lines class=\"divider-margin-f\"></div> \n" +
19601 " <div class=\"col-md-3 fromto-margin\">\n" +
19602 " <div>From</div> <br>\n" +
19603 " <div>To</div>\n" +
19605 " <div ng-repeat=\"day in days\">\n" +
19606 " <div class=\"col-md-3 col-md-days\">\n" +
19607 " <div class=\"col-md-1 daysselect-margin\">\n" +
19608 " <input type=\"checkbox\" ng-model=\"daysList[day]\" title=\"Day selection {{$index}}\" att-checkbox ng-change=\"addSelectedValue(day)\"> \n" +
19610 " <span>{{day}}</span><br>\n" +
19612 " <div class=\"dropDownMarginBottom\">\n" +
19613 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': FrtimeListDay[day]}\" >\n" +
19614 " <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" +
19615 " <span class=\"select2-chosen dropDownMarginRight\" >{{selectedFromOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"FrtimeListDay[day] ? 'icon-dropdown-up' : 'icon-dropdown-down'\"></i></span>\n" +
19619 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultFromDropDown\" ng-show=\"FrtimeListDay[day]\"> \n" +
19620 " <ul class=\"select2-results resultTopMargin\" > \n" +
19621 " <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" +
19626 " <div class=\"dropDownMarginBottom\">\n" +
19627 " <div class=\"select2-container topDropDownWidth\" ng-class=\"{'select2-dropdown-open select2-container-active': TotimeListDay[day]}\" >\n" +
19628 " <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" +
19629 " <span class=\"select2-chosen dropDownMarginRight\">{{selectedToOption[day]}} <i ng-if=\"daysList[day]\" ng-class=\"TotimeListDay[day] ? 'icon-dropdown-up' : 'icon-dropdown-down'\" ></i></span>\n" +
19633 " <div class=\"select2-display-none select2-with-searchbox select2-drop-active show-search resultToDropDown\" ng-show=\"TotimeListDay[day]\"> \n" +
19634 " <ul class=\"select2-results resultTopMargin\" > \n" +
19635 " <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" +
19641 " <div att-divider-lines class=\"divider-margin-s\"></div>\n" +
19643 " <div ng-transclude></div>\n" +
19647 angular.module("app/scripts/ng_js_att_tpls/links/readMore.html", []).run(["$templateCache", function($templateCache) {
19648 $templateCache.put("app/scripts/ng_js_att_tpls/links/readMore.html",
19650 " <div ng-bind-html=\"textToDisplay\" ng-class=\"{'att--readMore': readFlag, 'att--readLess': !readFlag}\" ng-style=\"readLinkStyle\"></div>\n" +
19651 " <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" +
19654 "<span class=\"att--readless__link\" ng-show=\"readLessLink\">\n" +
19655 " <a href=\"javascript:void(0);\" ng-click=\"readLess()\" att-accessbility-click=\"32,13\">Read Less</a>\n" +
19659 angular.module("app/scripts/ng_js_att_tpls/loading/loading.html", []).run(["$templateCache", function($templateCache) {
19660 $templateCache.put("app/scripts/ng_js_att_tpls/loading/loading.html",
19661 "<div data-progress=\"{{progressStatus}}\" class=\"{{colorClass}}\" ng-class=\"{'att-loading-count':icon == 'count','loading--small':icon == 'small','loading': icon != 'count'}\" alt=\"Loading\">\n" +
19662 " <div class=\"att-loading-circle\" ng-if=\"icon == 'count'\">\n" +
19663 " <div class=\"att-loading-circle__mask att-loading-circle__full\">\n" +
19664 " <div class=\"att-loading-circle__fill\"></div>\n" +
19666 " <div class=\"att-loading-circle__mask att-loading-circle__half\">\n" +
19667 " <div class=\"att-loading-circle__fill\"></div>\n" +
19668 " <div class=\"att-loading-circle__fill att-loading-circle__fix\"></div>\n" +
19671 " <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" +
19677 angular.module("app/scripts/ng_js_att_tpls/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
19678 $templateCache.put("app/scripts/ng_js_att_tpls/modal/backdrop.html",
19679 "<div class=\"overlayed\" ng-class=\"{show: animate}\" \n" +
19680 " ng-style=\"{'z-index': 2000 + index*10,'overflow':'scroll'}\"> \n" +
19684 angular.module("app/scripts/ng_js_att_tpls/modal/tabbedItem.html", []).run(["$templateCache", function($templateCache) {
19685 $templateCache.put("app/scripts/ng_js_att_tpls/modal/tabbedItem.html",
19687 " <ul class=\"tabs_overlay\">\n" +
19688 " <li ng-repeat=\"item in items\" class=\"tabs_overlay__item two__item\" ng-class=\"{'active':isActiveTab($index)}\" ng-click=\"clickTab($index)\">\n" +
19689 " <i class=\"{{item.iconClass}}\"></i>\n" +
19690 " {{item.title}} ({{item.number}})\n" +
19691 " <a class=\"viewLink\" att-link>Show</a>\n" +
19697 angular.module("app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html", []).run(["$templateCache", function($templateCache) {
19698 $templateCache.put("app/scripts/ng_js_att_tpls/modal/tabbedOverlayItem.html",
19700 " <ul class=\"tabs_overlay\">\n" +
19701 " <li ng-repeat=\"item in items\" class=\"tabs_overlay__item two__item\" ng-class=\"{'active':isActiveTab($index)}\" ng-click=\"clickTab($index)\">\n" +
19702 " <i class=\"{{item.iconClass}}\"></i>\n" +
19703 " {{item.title}} ({{item.number}})\n" +
19704 " <a class=\"viewLink\" att-link>Show</a>\n" +
19710 angular.module("app/scripts/ng_js_att_tpls/modal/window.html", []).run(["$templateCache", function($templateCache) {
19711 $templateCache.put("app/scripts/ng_js_att_tpls/modal/window.html",
19712 "<div tabindex=\"-1\" role=\"dialog\" att-element-focus=\"focusModalFlag\" class=\"modals {{ windowClass }}\" ng-class=\"{show: animate}\" \n" +
19713 " ng-style=\"{'z-index': 2010 + index*10}\" ng-click=\"close($event)\" ng-transclude> \n" +
19718 angular.module("app/scripts/ng_js_att_tpls/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
19719 $templateCache.put("app/scripts/ng_js_att_tpls/pagination/pagination.html",
19720 "<div class=\"pager\">\n" +
19721 " <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" +
19722 " <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" +
19723 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage > 3\">...</span>\n" +
19724 " <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" +
19725 " <span class=\"pager__item\" ng-if=\"totalPages > 7 && currentPage < totalPages - 2 && showInput !== true\">...</span>\n" +
19726 " <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" +
19727 " <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" +
19728 " <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" +
19732 angular.module("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html", []).run(["$templateCache", function($templateCache) {
19733 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/innerPane.html",
19734 "<div class='inner-pane' ng-transclude></div>");
19737 angular.module("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html", []).run(["$templateCache", function($templateCache) {
19738 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/paneGroup.html",
19739 "<div class='pane-group' ng-transclude></div>");
19742 angular.module("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html", []).run(["$templateCache", function($templateCache) {
19743 $templateCache.put("app/scripts/ng_js_att_tpls/paneSelector/sidePane.html",
19744 "<div class='side-pane' ng-transclude></div>");
19747 angular.module("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
19748 $templateCache.put("app/scripts/ng_js_att_tpls/tooltip/tooltip-popup.html",
19749 "<div class=\"att-tooltip \" \n" +
19750 " ng-class=\"{ 'att-tooltip--on': isOpen, \n" +
19751 " 'att-tooltip--dark att-tooltip--dark--hover':stylett=='dark', \n" +
19752 " 'att-tooltip--light att-tooltip--light--hover':stylett=='light',\n" +
19753 " 'att-tooltip--left':placement=='left', \n" +
19754 " 'att-tooltip--above':placement=='above', \n" +
19755 " 'att-tooltip--right':placement=='right', \n" +
19756 " 'att-tooltip--below':placement=='below'}\" \n" +
19757 " ng-bind-html=\"content | unsafe\" ></div>");
19760 angular.module("app/scripts/ng_js_att_tpls/popOvers/popOvers.html", []).run(["$templateCache", function($templateCache) {
19761 $templateCache.put("app/scripts/ng_js_att_tpls/popOvers/popOvers.html",
19762 "<div class=\"att-popover popover-demo\" ng-style=\"{backgroundColor:popOverStyle}\"\n" +
19763 " ng-class=\"{'att-tooltip--dark':popOverStyle==='grey',\n" +
19764 " 'att-pop-over--left':popOverPlacement==='left', \n" +
19765 " 'att-pop-over--bell':popOverPlacement==='bell', \n" +
19766 " 'att-pop-over--above':popOverPlacement==='above', \n" +
19767 " 'att-pop-over--right':popOverPlacement==='right'}\" \n" +
19768 " style='position: absolute; max-width: 490px;'>\n" +
19769 " <div class=\"pop-over-caret\"\n" +
19770 " ng-class=\"{'pop-over-caret-border--left':popOverPlacement==='left', \n" +
19771 " 'pop-over-caret-border--above':popOverPlacement==='above', \n" +
19772 " 'pop-over-caret-border--right':popOverPlacement==='right', \n" +
19773 " 'pop-over-caret-border--below':popOverPlacement==='below'}\">\n" +
19775 " <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" +
19776 " ng-class=\"{'pop-over-caret--left':popOverPlacement==='left', \n" +
19777 " 'pop-over-caret--above':popOverPlacement==='above', \n" +
19778 " 'pop-over-caret--right':popOverPlacement==='right', \n" +
19779 " 'pop-over-caret--below':popOverPlacement==='below'}\"></div>\n" +
19781 " <div class=\"att-popover-content\">\n" +
19782 " <a ng-if=\"closeable\" href=\"javascript:void(0)\" class=\"icon-close att-popover__close\" ng-click=\"closeMe();$event.preventDefault()\"></a>\n" +
19783 " <div class=\"popover-packages__container\" ng-include=\"content\"></div>\n" +
19788 angular.module("app/scripts/ng_js_att_tpls/profileCard/addUser.html", []).run(["$templateCache", function($templateCache) {
19789 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/addUser.html",
19790 "<div class=\"col-md-9 profile-card add-user\">\n" +
19791 " <div class=\"atcenter\">\n" +
19792 " <div><i class=\"icon-add\"></i></div>\n" +
19793 " <span>add User</span>\n" +
19798 angular.module("app/scripts/ng_js_att_tpls/profileCard/profileCard.html", []).run(["$templateCache", function($templateCache) {
19799 $templateCache.put("app/scripts/ng_js_att_tpls/profileCard/profileCard.html",
19800 "<div class=\"col-md-9 profile-card\">\n" +
19801 " <div class=\"top-block\">\n" +
19802 " <div class=\"profile-image\">\n" +
19803 " <img ng-if=\"image\" profile-name=\"{{profile.name}}\" ng-src=\"{{profile.img}}\" alt=\"{{profile.name}}\">\n" +
19804 " <span ng-hide=\"image\" class=\"default-img\">{{initials}}</span>\n" +
19805 " <p class=\"name\" tooltip-condition=\"{{profile.name}}\" height=\"true\"></p>\n" +
19806 " <p class=\"status\">\n" +
19807 " <span class=\"status-icon\" ng-class=\"{'icon-green':colorIcon==='green','icon-red':colorIcon==='red','icon-blue':colorIcon==='blue','icon-yellow':colorIcon==='yellow'}\"> \n" +
19809 " <span>{{profile.state}}<span ng-if=\"badge\" class=\"status-badge\">Admin</span></span>\n" +
19813 " <div class=\"bottom-block\">\n" +
19814 " <div class=\"profile-details\">\n" +
19815 " <label>Username</label>\n" +
19816 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.userName}}\">{{profile.userName}}</p>\n" +
19817 " <label>Email</label>\n" +
19818 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.email}}\">{{profile.email}}</p>\n" +
19819 " <label>Role</label>\n" +
19820 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.role}}\">{{profile.role}}</p>\n" +
19821 " <label>Last Login</label>\n" +
19822 " <p att-text-overflow=\"92%\" tooltip-condition=\"{{profile.lastLogin}}\">{{profile.lastLogin}}</p>\n" +
19828 angular.module("app/scripts/ng_js_att_tpls/progressBars/progressBars.html", []).run(["$templateCache", function($templateCache) {
19829 $templateCache.put("app/scripts/ng_js_att_tpls/progressBars/progressBars.html",
19830 "<div class=\"att-progress\">\n" +
19831 " <div class=\"att-progress-value\"> </div>\n" +
19835 angular.module("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html", []).run(["$templateCache", function($templateCache) {
19836 $templateCache.put("app/scripts/ng_js_att_tpls/scrollbar/scrollbar.html",
19837 "<div class=\"scroll-bar\" style=\"position: absolute\">\n" +
19838 " <div class=\"scroll-thumb\" style=\"position: absolute; overflow: hidden\"></div>\n" +
19840 "<div class=\"prev icons-list\" data-size=\"medium\" ng-show=\"navigation && prevAvailable\" ng-style=\"{height: scrollbarAxis === 'x' && position.height + 'px'}\">\n" +
19841 " <a href=\"javascript:void(0);\" ng-click=\"customScroll(false)\" aria-label=\"Scroll\" aria-hidden=\"true\">\n" +
19842 " <i ng-class=\"{'icon-chevron-up': (scrollbarAxis === 'y'), 'icon-chevron-left': (scrollbarAxis === 'x')}\"></i>\n" +
19845 "<div class=\"scroll-viewport\" ng-style=\"{height: (scrollbarAxis === 'x' && position.height + 'px') || viewportHeight, width: viewportWidth}\" style=\"position: relative; overflow: hidden\">\n" +
19846 " <div class=\"scroll-overview\" style=\"position: absolute; display: table; width: 100%\" att-position=\"position\" ng-transclude></div>\n" +
19848 "<div class='next icons-list' data-size=\"medium\" ng-show=\"navigation && nextAvailable\" ng-style=\"{height: scrollbarAxis === 'x' && position.height + 'px'}\">\n" +
19849 " <a href=\"javascript:void(0);\" ng-click=\"customScroll(true)\" aria-label=\"Scroll\" aria-hidden=\"true\">\n" +
19850 " <i ng-class=\"{'icon-chevron-down': (scrollbarAxis === 'y'), 'icon-chevron-right': (scrollbarAxis === 'x')}\"></i>\n" +
19856 angular.module("app/scripts/ng_js_att_tpls/search/search.html", []).run(["$templateCache", function($templateCache) {
19857 $templateCache.put("app/scripts/ng_js_att_tpls/search/search.html",
19858 "<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" +
19859 " <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" +
19860 " <span class=\"select2-chosen needsclick\" aria-hidden = \"true\">{{selectedOption}}</span>\n" +
19861 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
19862 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
19863 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
19866 " <input class=\"select2-focusser select2-offscreen\" \n" +
19867 " tabindex=\"-1\" \n" +
19868 " type=\"text\" \n" +
19869 " aria-hidden=\"true\" \n" +
19870 " title=\"hidden\" \n" +
19871 " aria-haspopup=\"true\" \n" +
19872 " role=\"button\"> \n" +
19875 "<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" +
19876 " <div class=\"select2-search\">\n" +
19877 " <label ng-if=\"!noFilter\" class=\"select2-offscreen\" aria-label=\"Inline Search Field\" aria-hidden=\"true\">Inline Search Field</label>\n" +
19878 " <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" +
19880 " <ul id=\"inList\" class=\"select2-results\" role=\"listbox\">\n" +
19881 " <li ng-show=\"filteredName.length === 0\" class=\"select2-no-results\" tabindex=\"-1\">No matches found</li>\n" +
19882 " <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" +
19883 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
19884 " <span class=\"select2-match\"></span>\n" +
19886 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
19887 " <span class=\"select2-match\"></span>\n" +
19891 " <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" +
19892 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
19893 " <span class=\"select2-match\"></span>\n" +
19897 " <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" +
19898 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
19899 " <span class=\"select2-match\"></span>\n" +
19906 angular.module("app/scripts/ng_js_att_tpls/select/select.html", []).run(["$templateCache", function($templateCache) {
19907 $templateCache.put("app/scripts/ng_js_att_tpls/select/select.html",
19908 "<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" +
19909 " <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=\"{{selectedOption}} selected\" ng-focus=\"isact=true;\" ng-blur=\"isact=false;\">\n" +
19910 " <span class=\"select2-chosen needsclick\" aria-hidden=\"true\">{{selectedOption}}</span>\n" +
19911 " <abbr class=\"select2-search-choice-close needsclick\"></abbr>\n" +
19912 " <span class=\"select2-arrow needsclick\" role=\"presentation\">\n" +
19913 " <b role=\"presentation\" class=\"needsclick\"></b>\n" +
19916 " <input class=\"select2-focusser select2-offscreen\" \n" +
19917 " tabindex=\"-1\" \n" +
19918 " type=\"text\" \n" +
19919 " aria-hidden=\"true\" \n" +
19920 " title=\"hidden\" \n" +
19921 " aria-haspopup=\"true\" \n" +
19922 " role=\"button\"> \n" +
19925 "<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" +
19926 " <div class=\"select2-search\">\n" +
19927 " <label ng-if=\"!noFilter\" class=\"select2-offscreen\" aria-label=\"Inline Search Field\" aria-hidden=\"true\">Inline Search Field</label>\n" +
19928 " <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" +
19930 " <ul id=\"inList\" class=\"select2-results\" role=\"listbox\">\n" +
19931 " <li ng-if=\"!noFilter\" ng-show=\"filteredName.length === 0\" class=\"select2-no-results\" tabindex=\"-1\">No matches found</li>\n" +
19932 " <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" +
19933 " <div ng-if=\"startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | unsafe\" role=\"option\">\n" +
19934 " <span class=\"select2-match\"></span>\n" +
19936 " <div ng-if=\"!startsWithFilter\" class=\"select2-result-label\" ng-bind-html=\"selectMsg | highlight:title:className | unsafe\" role=\"option\">\n" +
19937 " <span class=\"select2-match\"></span>\n" +
19941 " <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" +
19942 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | unsafe\" role=\"option\">\n" +
19943 " <span class=\"select2-match\"></span>\n" +
19947 " <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" +
19948 " <div class=\"select2-result-label\" ng-bind-html=\"item.title | highlight:title:className | unsafe\" role=\"option\">\n" +
19949 " <span class=\"select2-match\"></span>\n" +
19956 angular.module("app/scripts/ng_js_att_tpls/select/textDropdown.html", []).run(["$templateCache", function($templateCache) {
19957 $templateCache.put("app/scripts/ng_js_att_tpls/select/textDropdown.html",
19958 "<div tabindex=\"0\" class=\"text-dropdown\">\n" +
19959 " <div class=\"dropdown\" ng-class=\"{'not-visible': isActionsShown}\" ng-click=\"toggle()\">\n" +
19960 " <span class=\"action--selected\" ng-bind=\"currentAction\"></span>\n" +
19961 " <i ng-class=\"isActionsShown ? 'icon-dropdown-up' : 'icon-dropdown-down'\"></i>\n" +
19963 " <ul ng-class=\"isActionsShown ? 'actionsOpened' : 'actionsClosed'\" ng-show=\"isActionsShown\">\n" +
19964 " <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" +
19969 angular.module("app/scripts/ng_js_att_tpls/slider/maxContent.html", []).run(["$templateCache", function($templateCache) {
19970 $templateCache.put("app/scripts/ng_js_att_tpls/slider/maxContent.html",
19971 "<div class=\"att-slider__label att-slider__label--max att-slider__label--below\" ng-transclude></div>");
19974 angular.module("app/scripts/ng_js_att_tpls/slider/minContent.html", []).run(["$templateCache", function($templateCache) {
19975 $templateCache.put("app/scripts/ng_js_att_tpls/slider/minContent.html",
19976 "<div class=\"att-slider__label att-slider__label--min att-slider__label--below\" ng-transclude></div>");
19979 angular.module("app/scripts/ng_js_att_tpls/slider/slider.html", []).run(["$templateCache", function($templateCache) {
19980 $templateCache.put("app/scripts/ng_js_att_tpls/slider/slider.html",
19981 "<div class=\"att-slider\" ng-mousemove=\"moveElem($event)\" ng-mouseup=\"mouseUp($event)\">\n" +
19982 " <div class=\"att-slider__track\">\n" +
19983 " <div class=\"att-slider__range att-slider__range--disabled\" ng-style=\"disabledStyle\"></div>\n" +
19984 " <div class=\"att-slider__range\" ng-style=\"rangeStyle\"></div>\n" +
19986 " <div class=\"att-slider__handles-container\">\n" +
19987 " <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" +
19988 " <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" +
19989 " <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" +
19991 " <div ng-transclude></div>\n" +
19995 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html", []).run(["$templateCache", function($templateCache) {
19996 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdown.html",
19997 "<div class=\" btn-group\" \n" +
19998 " ng-class=\"{'buttons-dropdown--large':!isSmall, \n" +
19999 " 'buttons-dropdown--small':isSmall, \n" +
20000 " 'action-dropdown':(isActionDropdown), \n" +
20001 " 'open':isDropDownOpen}\">\n" +
20002 " <a tabindex=\"0\" href=\"javascript:void(0)\" class=\"button btn buttons-dropdown__split\" \n" +
20003 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
20004 " 'button--secondary':btnType=='secondary', \n" +
20005 " 'button--disabled':btnType=='disabled', \n" +
20006 " 'button--small':isSmall}\" \n" +
20007 " ng-if=\"!isActionDropdown\"\n" +
20008 " ng-click=\"btnType==='disabled'?undefined:clickFxn()\" att-accessibility-click=\"13,32\">{{btnText}}</a>\n" +
20009 " <a tabindex=\"0\" href=\"javascript:void(0)\" role=\"button\" aria-label=\"Toggle Dropdown\" aria-haspopup=\"true\" class=\"button buttons-dropdown__drop dropdown-toggle\" \n" +
20010 " ng-class=\"{'button--primary':(btnType==undefined || btnType=='primary'), \n" +
20011 " 'button--secondary':btnType=='secondary', \n" +
20012 " 'button--disabled':btnType=='disabled', \n" +
20013 " 'button--small':isSmall}\" ng-click=\"toggleDropdown()\" att-accessibility-click=\"13,32\">{{toggleTitle}} </a>\n" +
20014 " <ul class=\"dropdown-menu\" ng-class=\"{'align-right':multiselect ===true}\" aria-expanded=\"{{isDropDownOpen}}\" ng-click=\"hideDropdown()\" role=\"menu\" ng-transclude></ul>\n" +
20018 angular.module("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html", []).run(["$templateCache", function($templateCache) {
20019 $templateCache.put("app/scripts/ng_js_att_tpls/splitButtonDropdown/splitButtonDropdownItem.html",
20020 "<li role=\"menuitem\" att-element-focus=\"sFlag\" tabindex=\"0\" ng-transclude></li>");
20023 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html", []).run(["$templateCache", function($templateCache) {
20024 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIcon.html",
20025 "<div class='split-icon-button-container'>\n" +
20027 " <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" +
20028 " <a class='{{icon}}' title='{{iconTitle}}' tabindex=\"0\"></a>\n" +
20029 " <i ng-if=\"isRight && !isMiddle && !isLeftNextDropdown && !isNextToDropDown\" \n" +
20030 " ng-class=\"isDropDownOpen ? 'icon-dropdown-up' : 'icon-dropdown-down'\"> </i>\n" +
20033 " <ul ng-if='isDropdown' class='dropdown-menu {{dropDownId}}' ng-show='\n" +
20034 " isDropDownOpen' ng-click='toggleDropdown(false)' role=\"presentation\" ng-transclude>\n" +
20040 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html", []).run(["$templateCache", function($templateCache) {
20041 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButton.html",
20043 " <div ng-if='isLeftLineShown' dir-type='{{iconStateConstants.DIR_TYPE.LEFT}}' expandable-line></div>\n" +
20044 " <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" +
20045 " <div ng-transclude>\n" +
20048 " <div ng-if='isRightLineShown' dir-type='{{iconStateConstants.DIR_TYPE.RIGHT}}' expandable-line></div>\n" +
20052 angular.module("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html", []).run(["$templateCache", function($templateCache) {
20053 $templateCache.put("app/scripts/ng_js_att_tpls/splitIconButton/splitIconButtonGroup.html",
20054 "<div ng-transclude>\n" +
20058 angular.module("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html", []).run(["$templateCache", function($templateCache) {
20059 $templateCache.put("app/scripts/ng_js_att_tpls/stepSlider/attStepSlider.html",
20060 "<span ng-class=\"mainSliderClass\">\n" +
20064 " <div class=\"jslider-bg\">\n" +
20065 " <i class=\"l\"></i>\n" +
20066 " <i class=\"r\"></i>\n" +
20067 " <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" +
20069 " <div class=\"jslider-pointer\" id=\"left-pointer\"></div>\n" +
20070 " <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" +
20071 " <div class=\"jslider-label\"><span ng-bind=\"from\"></span><span ng-bind=\"options.dimension\"></span></div>\n" +
20072 " <div class=\"jslider-label jslider-label-to\"><span ng-bind=\"toStr\"></span><span ng-bind=\"endDimension\"></span></div>\n" +
20073 " <div class=\"jslider-value\" id=\"jslider-value-left\"><span></span>{{options.dimension}}</div>\n" +
20074 " <div class=\"jslider-value jslider-value-to\"><span></span>{{toolTipDimension}}</div>\n" +
20075 " <div class=\"jslider-scale\" ng-class=\"{'show-dividers': showDividers, 'cutoff-slider-dividers':isCutOffSlider}\">\n" +
20077 " <div class=\"jslider-cutoff\">\n" +
20078 " <div class=\"jslider-label jslider-label-cutoff\">\n" +
20079 " <span ng-bind=\"cutOffVal\"></span>\n" +
20089 angular.module("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html", []).run(["$templateCache", function($templateCache) {
20090 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step-tracker.html",
20091 "<div class=\"steptracker1\">\n" +
20092 " <div class=\"steptracker-bg\">\n" +
20093 " <div tabindex=\"0\" ng-click=\"stepclick($event, $index);\" att-accessibility-click=\"13,23\" class=\"steptracker-track size-onethird\" ng-repeat=\"step in sdata\"\n" +
20094 " ng-style=\"set_width($index)\"\n" +
20095 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index), 'incomplete': isIncomplete($index), 'disabled': disableClick}\">\n" +
20096 " <div class=\"circle\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
20097 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
20103 angular.module("app/scripts/ng_js_att_tpls/steptracker/step.html", []).run(["$templateCache", function($templateCache) {
20104 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/step.html",
20105 "<div class=\"steptracker1\">\n" +
20106 " <div class=\"steptracker-bg\">\n" +
20107 " <div class=\"steptracker-track size-onethird\" \n" +
20108 " ng-class=\"{'last':laststep($index),'done':donesteps($index),'active':activestep($index)}\">\n" +
20109 " <div class=\"circle\" tabindex=\"0\" \n" +
20110 " ng-click=\"stepclick($event, $index);\" \n" +
20111 " att-accessibility-click=\"13,23\">{{($index) + 1}}<span>{{step.title}}</span></div>\n" +
20112 " <div ng-if=\"!laststep($index)\" class=\"track\"></div>\n" +
20119 angular.module("app/scripts/ng_js_att_tpls/steptracker/timeline.html", []).run(["$templateCache", function($templateCache) {
20120 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timeline.html",
20121 "<div class='att-timeline'>\n" +
20122 " <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" +
20124 " <div ng-repeat=\"m in middleSteps track by $index\">\n" +
20125 " <div timeline-bar order='{{$index}}'></div>\n" +
20126 " <div timeline-dot order='{{$index + 1}}' title='{{m.title}}' description='{{m.description}}' by='{{m.by}}' date='{{m.date}}' type='{{m.type}}'>\n" +
20133 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html", []).run(["$templateCache", function($templateCache) {
20134 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineBar.html",
20135 "<div class='timeline-bar'>\n" +
20136 " <div class='progress-bar' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20142 angular.module("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html", []).run(["$templateCache", function($templateCache) {
20143 $templateCache.put("app/scripts/ng_js_att_tpls/steptracker/timelineDot.html",
20144 "<div class='timeline-dot'>\n" +
20146 " <div class='bigger-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20149 " <div class='inactive-circle'>\n" +
20152 " <div class='expandable-circle' ng-class=\"{'completed-color':isCompleted,'cancelled-color':isCancelled,'alert-color':isAlert}\">\n" +
20155 " <div ng-class=\"{'below-info-box':isBelowInfoBoxShown, 'above-info-box': !isBelowInfoBoxShown}\" tabindex=\"0\">\n" +
20157 " <div ng-if='isBelowInfoBoxShown' class='vertical-line'>\n" +
20160 " <div class='info-container' ng-init='isContentShown=false'>\n" +
20161 " <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" +
20162 " <div class='content'>\n" +
20163 " <div class='description' ng-bind='description'></div>\n" +
20164 " <div class='submitter' ng-bind='by'></div>\n" +
20166 " <div class='date' ng-mouseover='titleMouseover(2)' ng-mouseleave='titleMouseleave()' ng-bind='date'></div>\n" +
20169 " <div ng-if='!isBelowInfoBoxShown' class='vertical-line'>\n" +
20176 angular.module("app/scripts/ng_js_att_tpls/table/attTable.html", []).run(["$templateCache", function($templateCache) {
20177 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTable.html",
20178 "<table class=\"tablesorter tablesorter-default\" ng-transclude></table>\n" +
20182 angular.module("app/scripts/ng_js_att_tpls/table/attTableBody.html", []).run(["$templateCache", function($templateCache) {
20183 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableBody.html",
20184 "<td ng-transclude></td>\n" +
20188 angular.module("app/scripts/ng_js_att_tpls/table/attTableHeader.html", []).run(["$templateCache", function($templateCache) {
20189 $templateCache.put("app/scripts/ng_js_att_tpls/table/attTableHeader.html",
20190 "<th role=\"button\" aria-label=\"column header {{headerName}} {{sortable !== 'false' && '' || 'sortable'}} {{sortPattern !== 'null' && '' || sortPattern}}\" tabindex=\"{{sortable !== 'false' && '0' || '-1'}}\" class=\"tablesorter-header\" ng-class=\"{'tablesorter-headerAsc': sortPattern === 'asc', 'tablesorter-headerDesc': sortPattern === 'desc', 'tablesort-sortable': sortable !== 'false', 'sorter-false': sortable === 'false'}\" att-accessibility-click=\"13,32\" ng-click=\"(sortable !== 'false') && sort();\"><div class=\"tablesorter-header-inner\" ng-transclude></div></th>");
20193 angular.module("app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html", []).run(["$templateCache", function($templateCache) {
20194 $templateCache.put("app/scripts/ng_js_att_tpls/tableMessages/attTableMessage.html",
20195 "<div class=\"att-table-message\">\n" +
20196 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.noMatching\">\n" +
20197 " <div class=\"img-magnify-glass\"></div> \n" +
20199 " <div ng-transclude></div>\n" +
20202 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.errorLoading\">\n" +
20203 " <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" +
20204 " <div>Oops!</div>\n" +
20205 " <div>The information could not load at this time.</div>\n" +
20206 " <div>Please <a href=\"javascript:void(0)\" ng-click=\"refreshAction($event)\">refresh the page</a>\n" +
20209 " <div class=\"message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.magnifySearch\">\n" +
20210 " <div class=\"img-magnify-glass\"></div>\n" +
20212 " <p class=\"title\" tabindex=\"0\">Please input values to <br/> begin your search.</p>\n" +
20215 " <div class=\"message loading-message\" ng-if=\"msgType==messageConstants.TABLE_MESSAGE_TYPES.isLoading\">\n" +
20216 " <div class=\"img-loading-dots\"></div>\n" +
20217 " <div ng-transclude></div>\n" +
20222 angular.module("app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html", []).run(["$templateCache", function($templateCache) {
20223 $templateCache.put("app/scripts/ng_js_att_tpls/tableMessages/attUserMessage.html",
20224 "<div class=\"att-user-message\">\n" +
20225 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.error && trigger ? 'message-wrapper-error' : 'hidden'\">\n" +
20226 " <div class=\"message-icon-error\"> <i class=\"icon-info-alert\"></i> </div>\n" +
20228 " <div class=\"message-body-wrapper\">\n" +
20229 " <div class=\"message-title-error\" ng-if=\"thetitle && thetitle.length > 0\"> <span ng-bind=\"thetitle\" tabindex=\"0\" aria-label=\"{{thetitle}}\"></span> </div>\n" +
20230 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\" tabindex=\"0\"></div>\n" +
20231 " <div class=\"message-bottom\">\n" +
20232 " <div ng-transclude></div>\n" +
20237 " <div ng-class=\"type==messageConstants.USER_MESSAGE_TYPES.success && trigger ? 'message-wrapper-success' : 'hidden'\">\n" +
20238 " <div class=\"message-icon-success\"> <i class=\"icon-included-checkmark\"></i></div>\n" +
20240 " <div class=\"message-body-wrapper\">\n" +
20241 " <div class=\"message-title-success\" ng-if=\"thetitle && thetitle.length > 0\" >\n" +
20242 " <span ng-bind=\"thetitle\" tabindex=\"0\" aria-label=\"{{thetitle}}\"></span>\n" +
20244 " <div class=\"message-msg\" ng-bind=\"message\" ng-if=\"message && message.length > 0\" tabindex=\"0\"></div>\n" +
20245 " <div class=\"message-bottom\">\n" +
20246 " <div ng-transclude></div>\n" +
20255 angular.module("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html", []).run(["$templateCache", function($templateCache) {
20256 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/floatingTabs.html",
20257 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
20258 " <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" +
20259 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
20264 angular.module("app/scripts/ng_js_att_tpls/tabs/genericTabs.html", []).run(["$templateCache", function($templateCache) {
20265 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/genericTabs.html",
20266 "<ul ng-class=\"{'tabsbid': size === 'large', 'tabsbid--small': size === 'small'}\">\n" +
20267 " <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" +
20268 " <a class=\"tabsbid__item-link\" href=\"{{tab.url}}\" tabindex=\"0\" att-accessibility-click=\"32,13\">{{tab.title}}</a>\n" +
20274 angular.module("app/scripts/ng_js_att_tpls/tabs/menuTab.html", []).run(["$templateCache", function($templateCache) {
20275 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/menuTab.html",
20276 "<li class=\"megamenu__item\" ng-mouseover=\"showHoverChild($event)\" ng-class=\"{'tabs__item--active': menuItem.active==true && !hoverChild==true}\">\n" +
20277 " <span role=\"menuitem\" att-accessibility-click=\"13,32\" tabindex=\"0\" ng-click=\"showChildren($event);!clickInactive||resetMenu($event)\">{{tabName}}</span>\n" +
20278 " <div ng-transclude></div>\n" +
20283 angular.module("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html", []).run(["$templateCache", function($templateCache) {
20284 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/parentmenuTab.html",
20285 "<div ng-class=\"{'megamenu-tabs': megaMenu,'submenu-tabs': !megaMenu}\">\n" +
20286 " <ul class=\"megamenu__items\" role=\"presentation\" ng-transclude>\n" +
20291 angular.module("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html", []).run(["$templateCache", function($templateCache) {
20292 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/simplifiedTabs.html",
20293 "<div class=\"simplified-tabs\">\n" +
20294 "<ul class=\"simplified-tabs__items\" role=\"tablist\">\n" +
20295 " <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" +
20296 " <li class=\"tabs__pointer\"></li>\n" +
20301 angular.module("app/scripts/ng_js_att_tpls/tabs/submenuTab.html", []).run(["$templateCache", function($templateCache) {
20302 $templateCache.put("app/scripts/ng_js_att_tpls/tabs/submenuTab.html",
20303 "<li class=\"tabsbid__item megamenu__item\" ng-class=\"{'subMenuHover': menuItem.active==true}\">\n" +
20304 "<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" +
20305 "<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" +
20306 "<span ng-transclude></span>\n" +
20311 angular.module("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html", []).run(["$templateCache", function($templateCache) {
20312 $templateCache.put("app/scripts/ng_js_att_tpls/tagBadges/tagBadges.html",
20313 "<div class=\"tags__item\" \n" +
20314 " ng-class=\"{'tags__item--small':isSmall, \n" +
20315 " 'tags__item--color':isColor, \n" +
20316 " 'tags__item--cloud':!isClosable && !isColor,'active':applyActiveClass}\"\n" +
20317 " ng-if=\"display\" \n" +
20318 " ng-style=\"{borderColor: border_type_borderColor, background: isHighlight?'#bbb':undefined, color: isHighlight?'#444':undefined }\"\n" +
20319 " ng-mousedown=\"activeHighlight(true)\" role=\"presentation\" ng-mouseup=\"activeHighlight(false)\">\n" +
20320 " <i class=\"icon-filter tags__item--icon\" ng-if=\"isIcon\"> </i>\n" +
20321 " <i class=\"tags__item--color-icon\" ng-if=\"isColor\" ng-style=\"{backgroundColor: background_type_backgroundColor, borderColor: background_type_borderColor}\"></i>\n" +
20322 " <span class=\"tags__item--title\" role=\"presentation\" tabindex=0 aria-label=\"tag\" ng-mousedown=\"activeHighlight(true)\" ng-mouseup=\"activeHighlight(false)\" ng-transclude></span>\n" +
20323 " <a href=\"javascript:void(0)\" title=\"Dismiss Link\" class=\"tags__item--action\" ng-click=\"closeMe();$event.preventDefault()\" ng-if=\"isClosable\"\n" +
20324 " ng-style=\"{color: (isHighlight && '#444') || '#888' , borderLeft: (isHighlight && '1px solid #444')|| '1px solid #888' }\">\n" +
20325 " <i class=\"icon-erase\"> </i>\n" +
20330 angular.module("app/scripts/ng_js_att_tpls/toggle/demoToggle.html", []).run(["$templateCache", function($templateCache) {
20331 $templateCache.put("app/scripts/ng_js_att_tpls/toggle/demoToggle.html",
20332 "<span ng-transclude></span>\n" +
20333 "<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" +
20334 " <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" +
20335 " <div class=\"att-switch-thumb\" tabindex=\"0\" title=\"Toggle switch\" role=\"checkbox\" ng-class=\"{'large' : directiveValue == 'large'}\"></div>\n" +
20336 " <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" +
20341 angular.module("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html", []).run(["$templateCache", function($templateCache) {
20342 $templateCache.put("app/scripts/ng_js_att_tpls/typeAhead/typeAhead.html",
20343 "<div class=\"typeahead mainContainerOuter\">\n" +
20344 " <span class=\"message\">To</span>\n" +
20345 " <div class='maincontainer' ng-click=\"setFocus()\" ng-focus=\"inputActive=true\" ng-class =\"{'typeahed_active':inputActive || (lineItems.length && inputActive)}\">\n" +
20346 " <span tag-badges closable ng-repeat =\"lineItem in lineItems track by $index\" on-close=\"theMethodToBeCalled($index)\" >{{lineItem}}</span>\n" +
20347 " <input type=\"text\" focus-me=\"clickFocus\" ng-focus=\"inputActive=true\" ng-model=\"model\" ng-keydown=\"selected = false; selectionIndex($event)\"/><br/> \n" +
20349 " <div ng-hide=\"!model.length || selected\">\n" +
20350 " <div class=\"filtercontainer list-scrollable\" ng-show=\"( items | filter:model).length\">\n" +
20351 " <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" +
20352 " <span class=\"title\" >{{item[titleName]}}</span>\n" +
20353 " <span class=\"subtitle\">{{item[subtitle]}}</span>\n" +
20358 " <div class=\"textAreaEmailContentDiv\">\n" +
20359 " <span class=\"message\">Message</span>\n" +
20360 " <textarea rows=\"4\" cols=\"50\" role=\"textarea\" class=\"textAreaEmailContent\" ng-model=\"emailMessage\">To send \n" +
20361 " a text, picture, or video message1 to an AT&T wireless device from your email:my message.</textarea>\n" +
20369 angular.module("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html", []).run(["$templateCache", function($templateCache) {
20370 $templateCache.put("app/scripts/ng_js_att_tpls/verticalSteptracker/vertical-step-tracker.html",
20372 " <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" +
20373 " <span ng-transclude></span>\n" +
20379 angular.module("app/scripts/ng_js_att_tpls/videoControls/photoControls.html", []).run(["$templateCache", function($templateCache) {
20380 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/photoControls.html",
20382 " <a title=\"{{links.prevLink}}\" aria-label=\"Previous Link\" ng-href=\"{{links.prevLink}}\"><i alt=\"previous\" class=\"icon-arrow-left\"> </i></a>\n" +
20383 " <span ng-transclude></span>\n" +
20384 " <a title=\"{{links.nextLink}}\" aria-label=\"Next Link\" ng-href=\"{{links.nextLink}}\"><i alt=\"next\" class=\"icon-arrow-right\"> </i></a>\n" +
20388 angular.module("app/scripts/ng_js_att_tpls/videoControls/videoControls.html", []).run(["$templateCache", function($templateCache) {
20389 $templateCache.put("app/scripts/ng_js_att_tpls/videoControls/videoControls.html",
20390 "<div class=\"video-player\">\n" +
20391 " <div class=\"video-player__control video-player__play-button\">\n" +
20392 " <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" +
20394 " <div class=\"video-player__control video-player__track\">\n" +
20396 " <div class=\"video-player__track--inner\">\n" +
20397 " <div class=\"video-player__track--loaded\" style=\"width: 75%\"></div>\n" +
20398 " <div class=\"video-player__track--played\" style=\"width: 40%\">\n" +
20399 " <div class=\"att-tooltip att-tooltip--on att-tooltip--dark att-tooltip--above video-player__track-tooltip\" ng-transclude></div>\n" +
20400 " <div class=\"video-player__track-handle\"></div>\n" +
20404 " <a class=\"video-player__time\" ng-transclude></a>\n" +
20405 " <div class=\"video-player__control video-player__volume_icon\">\n" +
20406 " <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" +
20408 " <ul class=\"video-player__control video-player__volume\">\n" +
20409 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
20410 " <li class=\"video-player__volume-bar video-player__volume-bar--full\"> </li>\n" +
20411 " <li class=\"video-player__volume-bar\"> </li>\n" +
20412 " <li class=\"video-player__volume-bar\"> </li>\n" +
20413 " <li class=\"video-player__volume-bar\"> </li>\n" +
20415 " <div class=\"video-player__control video-player__toggle-fullscreen-button\">\n" +
20416 " <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" +
20422 })(angular, window);